zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit dfabf1586fa2fcd9350e204fa138f44f952acbfd (tree)
parent 80212b03ff792ddfff82092b35aa7ed0fdf937a8
Author: Alex Rønne Petersen <alex@alexrp.com>
Date:   Sat, 17 Jan 2026 05:40:55 +0100

libcxx: update to LLVM 22

Diffstat:
Mlib/libcxx/include/__algorithm/all_of.h | 16+++++++++++-----
Mlib/libcxx/include/__algorithm/comp.h | 4++++
Mlib/libcxx/include/__algorithm/copy.h | 175+++++++++++++------------------------------------------------------------------
Mlib/libcxx/include/__algorithm/copy_backward.h | 33+++++++++------------------------
Mlib/libcxx/include/__algorithm/copy_n.h | 66++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mlib/libcxx/include/__algorithm/count.h | 4++--
Mlib/libcxx/include/__algorithm/equal.h | 98+++++++++++++++++++++++++++++++++++--------------------------------------------
Mlib/libcxx/include/__algorithm/fill.h | 34++++++++++++++++++++++++++--------
Mlib/libcxx/include/__algorithm/fill_n.h | 78++++++++++++++++++++++++++++++++----------------------------------------------
Mlib/libcxx/include/__algorithm/find.h | 135++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mlib/libcxx/include/__algorithm/find_end.h | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__algorithm/for_each.h | 42++++++++++++++++++------------------------
Mlib/libcxx/include/__algorithm/for_each_n.h | 67++++++++++++++++++++-----------------------------------------------
Mlib/libcxx/include/__algorithm/for_each_n_segment.h | 2+-
Mlib/libcxx/include/__algorithm/for_each_segment.h | 26++++++++++++++++++++++++++
Mlib/libcxx/include/__algorithm/generate.h | 6++++--
Mlib/libcxx/include/__algorithm/generate_n.h | 25+++++++++++++++++++------
Mlib/libcxx/include/__algorithm/is_permutation.h | 8++++----
Mlib/libcxx/include/__algorithm/iterator_operations.h | 3+++
Mlib/libcxx/include/__algorithm/lexicographical_compare.h | 4++--
Mlib/libcxx/include/__algorithm/lexicographical_compare_three_way.h | 12++++++------
Mlib/libcxx/include/__algorithm/make_heap.h | 20++++++++++++++++----
Mlib/libcxx/include/__algorithm/mismatch.h | 4++--
Mlib/libcxx/include/__algorithm/move.h | 27++++++++-------------------
Mlib/libcxx/include/__algorithm/move_backward.h | 33+++++++++------------------------
Mlib/libcxx/include/__algorithm/none_of.h | 8++++----
Mlib/libcxx/include/__algorithm/partial_sort.h | 2+-
Mlib/libcxx/include/__algorithm/partial_sort_copy.h | 2+-
Mlib/libcxx/include/__algorithm/pstl.h | 18+++++++++---------
Mlib/libcxx/include/__algorithm/radix_sort.h | 52+++++++++++++++++++++++++++-------------------------
Mlib/libcxx/include/__algorithm/ranges_copy_n.h | 29+++--------------------------
Mlib/libcxx/include/__algorithm/ranges_equal.h | 43+++++++++++++++++--------------------------
Mlib/libcxx/include/__algorithm/ranges_fill.h | 13+++++++------
Mlib/libcxx/include/__algorithm/ranges_for_each.h | 10+++++++++-
Mlib/libcxx/include/__algorithm/ranges_generate_n.h | 8++------
Mlib/libcxx/include/__algorithm/ranges_search_n.h | 4++--
Mlib/libcxx/include/__algorithm/rotate.h | 71+++++++++++++++++++++++++++--------------------------------------------
Mlib/libcxx/include/__algorithm/search_n.h | 86+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlib/libcxx/include/__algorithm/sift_down.h | 37+++++++++++++++++++------------------
Mlib/libcxx/include/__algorithm/simd_utils.h | 37+++++++++++++++++++++++++++++++++----
Alib/libcxx/include/__algorithm/specialized_algorithms.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__algorithm/stable_sort.h | 2+-
Mlib/libcxx/include/__assertion_handler | 35+++++++++++++++++++++++++++++++----
Mlib/libcxx/include/__atomic/atomic.h | 96++++++++++++++++++++++++++++++-------------------------------------------------
Mlib/libcxx/include/__atomic/atomic_flag.h | 56+++++++++++++++++++-------------------------------------
Mlib/libcxx/include/__atomic/atomic_ref.h | 41+++++++++++++++++++++++++++++------------
Mlib/libcxx/include/__atomic/atomic_sync.h | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Alib/libcxx/include/__atomic/atomic_sync_timed.h | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libcxx/include/__atomic/atomic_waitable_traits.h | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__atomic/contention_t.h | 30+++++++++++++++++++++++++++---
Alib/libcxx/include/__atomic/floating_point_helper.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__bit/countl.h | 3+--
Mlib/libcxx/include/__bit/countr.h | 3+--
Mlib/libcxx/include/__bit/has_single_bit.h | 2+-
Mlib/libcxx/include/__bit/popcount.h | 1-
Mlib/libcxx/include/__bit/rotate.h | 41+++++++++++++++--------------------------
Mlib/libcxx/include/__bit_reference | 225++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mlib/libcxx/include/__charconv/from_chars_integral.h | 2+-
Mlib/libcxx/include/__charconv/from_chars_result.h | 2+-
Mlib/libcxx/include/__charconv/to_chars_integral.h | 1+
Mlib/libcxx/include/__charconv/to_chars_result.h | 2+-
Mlib/libcxx/include/__charconv/traits.h | 27+++------------------------
Mlib/libcxx/include/__chrono/day.h | 11+++++++++++
Mlib/libcxx/include/__chrono/duration.h | 91++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mlib/libcxx/include/__chrono/file_clock.h | 6++++--
Alib/libcxx/include/__chrono/is_clock.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__chrono/leap_second.h | 13+++++++++++++
Mlib/libcxx/include/__chrono/month.h | 13+++++++++++++
Mlib/libcxx/include/__chrono/month_weekday.h | 22++++++++++++++++++++++
Mlib/libcxx/include/__chrono/monthday.h | 20++++++++++++++++++++
Mlib/libcxx/include/__chrono/steady_clock.h | 2+-
Mlib/libcxx/include/__chrono/system_clock.h | 6+++---
Mlib/libcxx/include/__chrono/time_point.h | 50+++++++++++++++++++++++++++++++++++++-------------
Mlib/libcxx/include/__chrono/weekday.h | 25+++++++++++++++++++++++++
Mlib/libcxx/include/__chrono/year.h | 11+++++++++++
Mlib/libcxx/include/__chrono/year_month.h | 13+++++++++++++
Mlib/libcxx/include/__chrono/year_month_day.h | 23+++++++++++++++++++++++
Mlib/libcxx/include/__chrono/year_month_weekday.h | 26++++++++++++++++++++++++++
Mlib/libcxx/include/__chrono/zoned_time.h | 16++++++++++++++++
Mlib/libcxx/include/__compare/is_eq.h | 12++++++------
Mlib/libcxx/include/__compare/strong_order.h | 42++++++++++++------------------------------
Mlib/libcxx/include/__compare/three_way_comparable.h | 4++--
Alib/libcxx/include/__concepts/comparison_common_type.h | 40++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__concepts/equality_comparable.h | 3++-
Mlib/libcxx/include/__condition_variable/condition_variable.h | 2+-
Mlib/libcxx/include/__config | 343+++++++++++++++----------------------------------------------------------------
Mlib/libcxx/include/__configuration/abi.h | 38++++++++++++++------------------------
Mlib/libcxx/include/__configuration/availability.h | 183++++++++++++++++++++++++++++---------------------------------------------------
Mlib/libcxx/include/__configuration/compiler.h | 12++++++------
Alib/libcxx/include/__configuration/experimental.h | 38++++++++++++++++++++++++++++++++++++++
Alib/libcxx/include/__configuration/hardening.h | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__configuration/language.h | 3+++
Mlib/libcxx/include/__configuration/platform.h | 25+++++++++----------------
Mlib/libcxx/include/__coroutine/coroutine_handle.h | 18+++++++++---------
Mlib/libcxx/include/__coroutine/noop_coroutine_handle.h | 24+++++++++++-------------
Mlib/libcxx/include/__debug_utils/strict_weak_ordering_check.h | 2+-
Mlib/libcxx/include/__exception/exception.h | 10++++++----
Mlib/libcxx/include/__exception/exception_ptr.h | 32+++++++++++++++++++++++++++-----
Mlib/libcxx/include/__exception/nested_exception.h | 4++--
Mlib/libcxx/include/__exception/operations.h | 10+++++-----
Mlib/libcxx/include/__expected/bad_expected_access.h | 14++++++++------
Mlib/libcxx/include/__expected/expected.h | 126+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlib/libcxx/include/__expected/unexpected.h | 8++++----
Mlib/libcxx/include/__filesystem/copy_options.h | 8++++----
Mlib/libcxx/include/__filesystem/directory_entry.h | 70+++++++++++++++++++++++++++++++++++++---------------------------------
Mlib/libcxx/include/__filesystem/directory_iterator.h | 20+++++++++-----------
Mlib/libcxx/include/__filesystem/directory_options.h | 11+++++++----
Mlib/libcxx/include/__filesystem/file_status.h | 6+++---
Mlib/libcxx/include/__filesystem/filesystem_error.h | 19+++++++++----------
Mlib/libcxx/include/__filesystem/operations.h | 163+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlib/libcxx/include/__filesystem/path.h | 132+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mlib/libcxx/include/__filesystem/path_iterator.h | 4+---
Mlib/libcxx/include/__filesystem/perm_options.h | 8++++----
Mlib/libcxx/include/__filesystem/perms.h | 8++++----
Mlib/libcxx/include/__filesystem/recursive_directory_iterator.h | 23+++++++++--------------
Mlib/libcxx/include/__filesystem/space_info.h | 2+-
Mlib/libcxx/include/__filesystem/u8path.h | 26++++++++++++--------------
Mlib/libcxx/include/__flat_map/flat_map.h | 159++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mlib/libcxx/include/__flat_map/flat_multimap.h | 423+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlib/libcxx/include/__flat_map/key_value_iterator.h | 1-
Mlib/libcxx/include/__flat_map/utils.h | 1+
Mlib/libcxx/include/__flat_set/flat_multiset.h | 354+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlib/libcxx/include/__flat_set/flat_set.h | 154++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mlib/libcxx/include/__format/concepts.h | 14--------------
Mlib/libcxx/include/__format/extended_grapheme_cluster_table.h | 5+++--
Alib/libcxx/include/__format/fmt_pair_like.h | 42++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__format/format_arg.h | 17+++++++----------
Mlib/libcxx/include/__format/format_args.h | 2+-
Mlib/libcxx/include/__format/format_context.h | 10+++++-----
Mlib/libcxx/include/__format/format_parse_context.h | 4++--
Mlib/libcxx/include/__format/formatter_output.h | 64++++++++++++++++++++++++++++++----------------------------------
Mlib/libcxx/include/__format/indic_conjunct_break_table.h | 5+++--
Mlib/libcxx/include/__format/range_default_formatter.h | 43++-----------------------------------------
Alib/libcxx/include/__format/range_format.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__format/range_formatter.h | 1+
Mlib/libcxx/include/__format/width_estimation_table.h | 6++++--
Mlib/libcxx/include/__functional/bind.h | 25++++++++++---------------
Mlib/libcxx/include/__functional/bind_back.h | 2+-
Mlib/libcxx/include/__functional/bind_front.h | 2+-
Mlib/libcxx/include/__functional/function.h | 132++++++++++++++++++++++++++++++++++---------------------------------------------
Mlib/libcxx/include/__functional/hash.h | 11+----------
Mlib/libcxx/include/__functional/identity.h | 2+-
Mlib/libcxx/include/__functional/is_transparent.h | 8++++++++
Mlib/libcxx/include/__functional/mem_fn.h | 3++-
Mlib/libcxx/include/__functional/operations.h | 18++++++++++++++++++
Mlib/libcxx/include/__functional/ranges_operations.h | 7+++++++
Mlib/libcxx/include/__functional/reference_wrapper.h | 12+++++++-----
Mlib/libcxx/include/__functional/weak_result_type.h | 42++++++++++++++----------------------------
Mlib/libcxx/include/__fwd/ios.h | 2+-
Mlib/libcxx/include/__fwd/tuple.h | 14++++++++++++++
Mlib/libcxx/include/__hash_table | 728++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/libcxx/include/__ios/fpos.h | 8++++----
Mlib/libcxx/include/__iterator/back_insert_iterator.h | 8+-------
Mlib/libcxx/include/__iterator/bounded_iter.h | 15+++++++--------
Mlib/libcxx/include/__iterator/concepts.h | 15++++++---------
Mlib/libcxx/include/__iterator/cpp17_iterator_concepts.h | 25+++++++++++++------------
Mlib/libcxx/include/__iterator/distance.h | 58++++++++++++++++++++++++++++++++++++++++------------------
Mlib/libcxx/include/__iterator/front_insert_iterator.h | 8+-------
Mlib/libcxx/include/__iterator/insert_iterator.h | 8+-------
Mlib/libcxx/include/__iterator/istream_iterator.h | 13++++++-------
Mlib/libcxx/include/__iterator/istreambuf_iterator.h | 13++++++-------
Mlib/libcxx/include/__iterator/iter_move.h | 2+-
Mlib/libcxx/include/__iterator/iterator.h | 13+++++++++++++
Mlib/libcxx/include/__iterator/iterator_traits.h | 27+++++++++++++--------------
Mlib/libcxx/include/__iterator/ostream_iterator.h | 8+-------
Mlib/libcxx/include/__iterator/ostreambuf_iterator.h | 8+-------
Mlib/libcxx/include/__iterator/reverse_iterator.h | 21++++++++-------------
Mlib/libcxx/include/__iterator/segmented_iterator.h | 11+++--------
Mlib/libcxx/include/__iterator/static_bounded_iter.h | 6+++---
Mlib/libcxx/include/__iterator/wrap_iter.h | 14++++++++------
Mlib/libcxx/include/__locale | 13+++----------
Mlib/libcxx/include/__locale_dir/locale_base_api.h | 33+++++----------------------------
Mlib/libcxx/include/__locale_dir/locale_base_api/bsd_locale_fallbacks.h | 10----------
Mlib/libcxx/include/__locale_dir/messages.h | 2+-
Mlib/libcxx/include/__locale_dir/money.h | 4++--
Mlib/libcxx/include/__locale_dir/num.h | 433+++++++++++++++++++++++++++++++++++--------------------------------------------
Mlib/libcxx/include/__locale_dir/pad_and_output.h | 11+++++------
Mlib/libcxx/include/__locale_dir/support/bsd_like.h | 20--------------------
Mlib/libcxx/include/__locale_dir/support/fuchsia.h | 7-------
Mlib/libcxx/include/__locale_dir/support/linux.h | 37-------------------------------------
Mlib/libcxx/include/__locale_dir/support/netbsd.h | 2--
Alib/libcxx/include/__locale_dir/support/newlib.h | 243+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__locale_dir/support/no_locale/characters.h | 4----
Mlib/libcxx/include/__locale_dir/support/no_locale/strtonum.h | 9---------
Mlib/libcxx/include/__locale_dir/support/windows.h | 29-----------------------------
Mlib/libcxx/include/__locale_dir/time.h | 10+++-------
Mlib/libcxx/include/__math/hypot.h | 2+-
Mlib/libcxx/include/__math/logarithms.h | 2+-
Mlib/libcxx/include/__math/traits.h | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mlib/libcxx/include/__mdspan/extents.h | 11+++++++----
Mlib/libcxx/include/__mdspan/layout_stride.h | 9++++-----
Mlib/libcxx/include/__mdspan/mdspan.h | 52+++++++++++++++++++++++++++++-----------------------
Mlib/libcxx/include/__memory/addressof.h | 12+++++++-----
Mlib/libcxx/include/__memory/align.h | 19++++++++++++++++++-
Mlib/libcxx/include/__memory/allocate_at_least.h | 25+++++++++++++++----------
Mlib/libcxx/include/__memory/allocator.h | 40++++++++++++++--------------------------
Mlib/libcxx/include/__memory/allocator_traits.h | 10++++++----
Mlib/libcxx/include/__memory/compressed_pair.h | 24+++++++++++++++---------
Mlib/libcxx/include/__memory/construct_at.h | 35++++++++++++-----------------------
Mlib/libcxx/include/__memory/inout_ptr.h | 2+-
Mlib/libcxx/include/__memory/is_sufficiently_aligned.h | 2+-
Mlib/libcxx/include/__memory/out_ptr.h | 2+-
Mlib/libcxx/include/__memory/pointer_traits.h | 2+-
Mlib/libcxx/include/__memory/raw_storage_iterator.h | 12+++---------
Mlib/libcxx/include/__memory/shared_count.h | 39+++++++++------------------------------
Mlib/libcxx/include/__memory/shared_ptr.h | 245++++++++++++++++++++++++++++++++-----------------------------------------------
Mlib/libcxx/include/__memory/temp_value.h | 3+--
Mlib/libcxx/include/__memory/uninitialized_algorithms.h | 159++++++++++++++++++++++---------------------------------------------------------
Mlib/libcxx/include/__memory/unique_ptr.h | 30++++++++++++++----------------
Mlib/libcxx/include/__memory/uses_allocator_construction.h | 1+
Mlib/libcxx/include/__memory_resource/memory_resource.h | 6++++--
Mlib/libcxx/include/__memory_resource/monotonic_buffer_resource.h | 2+-
Mlib/libcxx/include/__memory_resource/polymorphic_allocator.h | 21+++++++++++++--------
Mlib/libcxx/include/__memory_resource/pool_options.h | 2+-
Mlib/libcxx/include/__memory_resource/synchronized_pool_resource.h | 6++++--
Mlib/libcxx/include/__memory_resource/unsynchronized_pool_resource.h | 2+-
Mlib/libcxx/include/__mutex/mutex.h | 4++--
Mlib/libcxx/include/__mutex/once_flag.h | 25++++++++++++++-----------
Mlib/libcxx/include/__mutex/tag_types.h | 6+++---
Mlib/libcxx/include/__mutex/unique_lock.h | 15++++++++-------
Mlib/libcxx/include/__new/align_val_t.h | 6++++++
Mlib/libcxx/include/__new/allocate.h | 3+--
Mlib/libcxx/include/__new/exceptions.h | 10++++++++--
Mlib/libcxx/include/__new/global_new_delete.h | 15++++-----------
Mlib/libcxx/include/__new/interference_size.h | 4----
Mlib/libcxx/include/__new/launder.h | 8+++-----
Mlib/libcxx/include/__new/nothrow_t.h | 2+-
Mlib/libcxx/include/__numeric/gcd_lcm.h | 58++++++++++++++++++++++++----------------------------------
Mlib/libcxx/include/__numeric/midpoint.h | 23+++++++++--------------
Mlib/libcxx/include/__numeric/pstl.h | 4++--
Mlib/libcxx/include/__numeric/saturation_arithmetic.h | 18+++++++++++++-----
Mlib/libcxx/include/__ostream/basic_ostream.h | 16++++++++--------
Mlib/libcxx/include/__pstl/backends/default.h | 28++++++++++++++--------------
Mlib/libcxx/include/__pstl/backends/libdispatch.h | 4++--
Mlib/libcxx/include/__pstl/cpu_algos/find_if.h | 2+-
Mlib/libcxx/include/__pstl/cpu_algos/transform.h | 11+++++------
Mlib/libcxx/include/__pstl/cpu_algos/transform_reduce.h | 9+++++----
Mlib/libcxx/include/__random/binomial_distribution.h | 14++++++++++----
Mlib/libcxx/include/__random/mersenne_twister_engine.h | 204++++++++++++++++++++-----------------------------------------------------------
Mlib/libcxx/include/__random/piecewise_constant_distribution.h | 5+++--
Mlib/libcxx/include/__random/piecewise_linear_distribution.h | 5+++--
Alib/libcxx/include/__ranges/adjacent_transform_view.h | 406+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/libcxx/include/__ranges/adjacent_view.h | 419+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__ranges/as_rvalue_view.h | 18+++++++++---------
Mlib/libcxx/include/__ranges/chunk_by_view.h | 12++++++------
Mlib/libcxx/include/__ranges/common_view.h | 14+++++++-------
Mlib/libcxx/include/__ranges/drop_view.h | 16++++++++--------
Mlib/libcxx/include/__ranges/drop_while_view.h | 10+++++-----
Alib/libcxx/include/__ranges/elements_of.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__ranges/empty_view.h | 10+++++-----
Mlib/libcxx/include/__ranges/filter_view.h | 20++++++++++----------
Mlib/libcxx/include/__ranges/iota_view.h | 63+++++++++++++++++++++++++++++++++++++++++----------------------
Mlib/libcxx/include/__ranges/owning_view.h | 30+++++++++++++++---------------
Mlib/libcxx/include/__ranges/ref_view.h | 12++++++------
Mlib/libcxx/include/__ranges/repeat_view.h | 27+++++++++++++++++----------
Mlib/libcxx/include/__ranges/single_view.h | 16++++++++--------
Mlib/libcxx/include/__ranges/take_view.h | 18+++++++++---------
Mlib/libcxx/include/__ranges/transform_view.h | 3+--
Mlib/libcxx/include/__ranges/view_interface.h | 20++++++++++----------
Alib/libcxx/include/__ranges/zip_transform_view.h | 357+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__ranges/zip_view.h | 40++++++++++++++++++++--------------------
Mlib/libcxx/include/__split_buffer | 852+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mlib/libcxx/include/__stop_token/atomic_unique_lock.h | 2+-
Mlib/libcxx/include/__stop_token/stop_callback.h | 4++--
Mlib/libcxx/include/__stop_token/stop_source.h | 2+-
Mlib/libcxx/include/__stop_token/stop_state.h | 8++++----
Mlib/libcxx/include/__stop_token/stop_token.h | 2+-
Mlib/libcxx/include/__string/char_traits.h | 82+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mlib/libcxx/include/__string/constexpr_c_functions.h | 10+++++-----
Mlib/libcxx/include/__support/xlocale/__strtonum_fallback.h | 8--------
Mlib/libcxx/include/__system_error/error_category.h | 16++++++++--------
Mlib/libcxx/include/__system_error/error_code.h | 10+++++-----
Mlib/libcxx/include/__system_error/error_condition.h | 8++++----
Mlib/libcxx/include/__system_error/system_error.h | 2+-
Mlib/libcxx/include/__thread/id.h | 2+-
Mlib/libcxx/include/__thread/jthread.h | 2+-
Mlib/libcxx/include/__thread/poll_with_backoff.h | 35+++++++++++++++++++++++++++--------
Mlib/libcxx/include/__thread/support/c11.h | 16++++++++--------
Mlib/libcxx/include/__thread/support/pthread.h | 16++++++++--------
Mlib/libcxx/include/__thread/support/windows.h | 16++++++++--------
Mlib/libcxx/include/__thread/thread.h | 21+++++++++++++--------
Mlib/libcxx/include/__thread/timed_backoff_policy.h | 5+++--
Mlib/libcxx/include/__tree | 1550+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlib/libcxx/include/__tuple/sfinae_helpers.h | 45+--------------------------------------------
Mlib/libcxx/include/__tuple/tuple_element.h | 12------------
Mlib/libcxx/include/__tuple/tuple_size.h | 4----
Alib/libcxx/include/__tuple/tuple_transform.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__type_traits/aligned_storage.h | 53+++++++++++++----------------------------------------
Mlib/libcxx/include/__type_traits/desugars_to.h | 4++++
Mlib/libcxx/include/__type_traits/invoke.h | 8++++++++
Mlib/libcxx/include/__type_traits/is_allocator.h | 13++++++-------
Mlib/libcxx/include/__type_traits/is_array.h | 26++++++++++++++++++++++++++
Mlib/libcxx/include/__type_traits/is_equality_comparable.h | 37++++++++++++++++---------------------
Mlib/libcxx/include/__type_traits/is_final.h | 2+-
Mlib/libcxx/include/__type_traits/is_floating_point.h | 13+++++++------
Alib/libcxx/include/__type_traits/is_generic_transparent_comparator.h | 30++++++++++++++++++++++++++++++
Mlib/libcxx/include/__type_traits/is_specialization.h | 8++------
Alib/libcxx/include/__type_traits/is_within_lifetime.h | 29+++++++++++++++++++++++++++++
Alib/libcxx/include/__type_traits/make_transparent.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__type_traits/reference_constructs_from_temporary.h | 8+-------
Mlib/libcxx/include/__type_traits/reference_converts_from_temporary.h | 2+-
Mlib/libcxx/include/__utility/cmp.h | 26+++++++++++++++++++-------
Alib/libcxx/include/__utility/default_three_way_comparator.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__utility/in_place.h | 2+-
Mlib/libcxx/include/__utility/integer_sequence.h | 97++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Alib/libcxx/include/__utility/lazy_synth_three_way_comparator.h | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__utility/pair.h | 47++++++++++++++++++++++-------------------------
Mlib/libcxx/include/__utility/scope_guard.h | 2++
Alib/libcxx/include/__utility/try_key_extraction.h | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/__vector/vector.h | 347+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlib/libcxx/include/__vector/vector_bool.h | 159++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mlib/libcxx/include/any | 273++++++++++++++++++++++++++++++++++---------------------------------------------
Mlib/libcxx/include/array | 144++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mlib/libcxx/include/atomic | 2++
Mlib/libcxx/include/barrier | 44++++++++++++++++++++------------------------
Mlib/libcxx/include/bitset | 79+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mlib/libcxx/include/ccomplex | 14+++-----------
Mlib/libcxx/include/chrono | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/ciso646 | 9+++------
Mlib/libcxx/include/complex | 142+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlib/libcxx/include/complex.h | 20++++++++++----------
Mlib/libcxx/include/condition_variable | 6+++---
Mlib/libcxx/include/cstdalign | 13+++----------
Mlib/libcxx/include/cstdbool | 13+++----------
Mlib/libcxx/include/ctgmath | 13++-----------
Mlib/libcxx/include/ctype.h | 48++++++++++++++++++++++++------------------------
Mlib/libcxx/include/cwchar | 4++--
Mlib/libcxx/include/deque | 334++++++++++++++++++++++++++-----------------------------------------------------
Mlib/libcxx/include/errno.h | 538++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlib/libcxx/include/exception | 5++++-
Mlib/libcxx/include/ext/hash_map | 55+++++++------------------------------------------------
Mlib/libcxx/include/ext/hash_set | 10++--------
Mlib/libcxx/include/fenv.h | 86++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mlib/libcxx/include/flat_map | 674+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mlib/libcxx/include/flat_set | 551+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mlib/libcxx/include/float.h | 32++++++++++++++++----------------
Mlib/libcxx/include/forward_list | 86++++++++++++++++++++++++++++++-------------------------------------------------
Mlib/libcxx/include/fstream | 99+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mlib/libcxx/include/future | 92+++++++++++++++++++++++++++++++++++--------------------------------------------
Mlib/libcxx/include/initializer_list | 12+++++++++---
Mlib/libcxx/include/inttypes.h | 32++++++++++++++++----------------
Mlib/libcxx/include/ios | 56++++++++++++++++++++++++++++----------------------------
Mlib/libcxx/include/istream | 32+++++++++++++++++++-------------
Mlib/libcxx/include/iterator | 10++++++++++
Mlib/libcxx/include/latch | 12+++++++-----
Mlib/libcxx/include/limits | 8++++----
Mlib/libcxx/include/list | 140++++++++++++++++++++++++++++++++++---------------------------------------------
Mlib/libcxx/include/map | 660++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mlib/libcxx/include/math.h | 19+++++++++++++++++++
Mlib/libcxx/include/mdspan | 6+-----
Mlib/libcxx/include/mutex | 48+++++++++++++++++++++++++++++-------------------
Mlib/libcxx/include/optional | 793++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mlib/libcxx/include/print | 14+++++++++-----
Mlib/libcxx/include/queue | 76+++++++++++++++++++++++++++++++++++++++-------------------------------------
Mlib/libcxx/include/ranges | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/include/regex | 64+++++++++++++++++++++++++++++++++-------------------------------
Mlib/libcxx/include/scoped_allocator | 27++++++++++++++++-----------
Mlib/libcxx/include/semaphore | 33+++++++++++++++------------------
Mlib/libcxx/include/set | 412++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mlib/libcxx/include/shared_mutex | 11+++--------
Mlib/libcxx/include/span | 90++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mlib/libcxx/include/sstream | 62++++++++++++++++++++++++++++++++++----------------------------
Mlib/libcxx/include/stack | 28+++++++++++++---------------
Mlib/libcxx/include/stddef.h | 20++++++++++----------
Mlib/libcxx/include/stdexcept | 4++--
Mlib/libcxx/include/stdio.h | 41++++++++++++++++++++---------------------
Mlib/libcxx/include/streambuf | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mlib/libcxx/include/string | 1147++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/libcxx/include/string_view | 202++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mlib/libcxx/include/strstream | 20++++++++++----------
Mlib/libcxx/include/syncstream | 8++++----
Mlib/libcxx/include/tgmath.h | 24++++++++++++------------
Mlib/libcxx/include/tuple | 454++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mlib/libcxx/include/type_traits | 10++++++++--
Mlib/libcxx/include/typeindex | 8+++++---
Mlib/libcxx/include/typeinfo | 181++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/libcxx/include/unordered_map | 483+++++++++++++++++++++++++++++--------------------------------------------------
Mlib/libcxx/include/unordered_set | 363+++++++++++++++++++++++++++++++++++++------------------------------------------
Mlib/libcxx/include/utility | 12++++++++++++
Mlib/libcxx/include/valarray | 267+++++++++++++++++++++++++++++++------------------------------------------------
Mlib/libcxx/include/variant | 58+++++++++++++++++++++++++---------------------------------
Mlib/libcxx/include/version | 65+++++++++++++++++++++++++++++++++++++++++------------------------
Mlib/libcxx/include/wctype.h | 58+++++++++++++++++++++++++++++-----------------------------
Mlib/libcxx/src/any.cpp | 4++++
Mlib/libcxx/src/atomic.cpp | 445++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mlib/libcxx/src/barrier.cpp | 7++++---
Mlib/libcxx/src/charconv.cpp | 9++++++---
Mlib/libcxx/src/condition_variable_destructor.cpp | 2+-
Mlib/libcxx/src/error_category.cpp | 4+++-
Mlib/libcxx/src/exception.cpp | 12++----------
Mlib/libcxx/src/experimental/time_zone.cpp | 2+-
Mlib/libcxx/src/experimental/tzdb.cpp | 5++++-
Mlib/libcxx/src/filesystem/error.h | 26++++----------------------
Mlib/libcxx/src/filesystem/format_string.h | 27+++++++++------------------
Mlib/libcxx/src/filesystem/int128_builtins.cpp | 2++
Mlib/libcxx/src/filesystem/operations.cpp | 11++---------
Mlib/libcxx/src/filesystem/path.cpp | 4+++-
Alib/libcxx/src/include/aligned_alloc.h | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/libcxx/src/include/config_elast.h | 2+-
Mlib/libcxx/src/include/from_chars_floating_point.h | 18+++++++++++-------
Mlib/libcxx/src/include/overridable_function.h | 18++++++++----------
Mlib/libcxx/src/iostream.cpp | 93+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mlib/libcxx/src/locale.cpp | 409+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mlib/libcxx/src/memory.cpp | 26++++++++++++--------------
Mlib/libcxx/src/mutex_destructor.cpp | 2+-
Mlib/libcxx/src/new.cpp | 10+++++-----
Mlib/libcxx/src/optional.cpp | 4++++
Mlib/libcxx/src/print.cpp | 10+++++++++-
Mlib/libcxx/src/random.cpp | 26--------------------------
Mlib/libcxx/src/string.cpp | 35++++++++++-------------------------
Mlib/libcxx/src/support/runtime/exception_fallback.ipp | 2++
Mlib/libcxx/src/support/runtime/exception_glibcxx.ipp | 3+++
Mlib/libcxx/src/support/runtime/exception_libcxxabi.ipp | 8++++++--
Mlib/libcxx/src/support/runtime/exception_libcxxrt.ipp | 2++
Mlib/libcxx/src/support/runtime/exception_msvc.ipp | 2++
Mlib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp | 19+++++++++----------
Mlib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp | 2++
Mlib/libcxx/src/support/runtime/exception_pointer_msvc.ipp | 1+
Mlib/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp | 1+
Mlib/libcxx/src/support/win32/locale_win32.cpp | 2+-
Mlib/libcxx/src/system_error.cpp | 2++
Mlib/libcxx/src/thread.cpp | 4+---
Mlib/libcxx/src/valarray.cpp | 3+--
Mlib/libcxx/src/vector.cpp | 4++--
Msrc/libs/libcxx.zig | 19++++++++++++++-----
425 files changed, 15825 insertions(+), 10341 deletions(-)

diff --git a/lib/libcxx/include/__algorithm/all_of.h b/lib/libcxx/include/__algorithm/all_of.h @@ -10,24 +10,28 @@ #ifndef _LIBCPP___ALGORITHM_ALL_OF_H #define _LIBCPP___ALGORITHM_ALL_OF_H +#include <__algorithm/any_of.h> #include <__config> #include <__functional/identity.h> #include <__type_traits/invoke.h> +#include <__utility/forward.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template <class _Iter, class _Sent, class _Proj, class _Pred> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __all_of(_Iter __first, _Sent __last, _Pred& __pred, _Proj& __proj) { - for (; __first != __last; ++__first) { - if (!std::__invoke(__pred, std::__invoke(__proj, *__first))) - return false; - } - return true; + using _Ref = decltype(std::__invoke(__proj, *__first)); + auto __negated_pred = [&__pred](_Ref __arg) -> bool { return !std::__invoke(__pred, std::forward<_Ref>(__arg)); }; + return !std::__any_of(std::move(__first), std::move(__last), __negated_pred, __proj); } template <class _InputIterator, class _Predicate> @@ -39,4 +43,6 @@ all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) { _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_ALL_OF_H diff --git a/lib/libcxx/include/__algorithm/comp.h b/lib/libcxx/include/__algorithm/comp.h @@ -11,6 +11,7 @@ #include <__config> #include <__type_traits/desugars_to.h> +#include <__type_traits/is_generic_transparent_comparator.h> #include <__type_traits/is_integral.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -48,6 +49,9 @@ inline const bool __desugars_to_v<__less_tag, __less<>, _Tp, _Tp> = true; template <class _Tp> inline const bool __desugars_to_v<__totally_ordered_less_tag, __less<>, _Tp, _Tp> = is_integral<_Tp>::value; +template <> +inline const bool __is_generic_transparent_comparator_v<__less<> > = true; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ALGORITHM_COMP_H diff --git a/lib/libcxx/include/__algorithm/copy.h b/lib/libcxx/include/__algorithm/copy.h @@ -12,11 +12,10 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/for_each_segment.h> #include <__algorithm/min.h> +#include <__algorithm/specialized_algorithms.h> #include <__config> -#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> -#include <__memory/pointer_traits.h> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> #include <__utility/move.h> @@ -38,124 +37,14 @@ copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result); template <class _InIter, class _Sent, class _OutIter> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> __copy(_InIter, _Sent, _OutIter); -template <class _Cp, bool _IsConst> -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_aligned( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - using _In = __bit_iterator<_Cp, _IsConst>; - using difference_type = typename _In::difference_type; - using __storage_type = typename _In::__storage_type; - - const int __bits_per_word = _In::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__first.__ctz_ != 0) { - unsigned __clz = __bits_per_word - __first.__ctz_; - difference_type __dn = std::min(static_cast<difference_type>(__clz), __n); - __n -= __dn; - __storage_type __m = std::__middle_mask<__storage_type>(__clz - __dn, __first.__ctz_); - __storage_type __b = *__first.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b; - __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word); - ++__first.__seg_; - // __first.__ctz_ = 0; - } - // __first.__ctz_ == 0; - // do middle words - __storage_type __nw = __n / __bits_per_word; - std::copy(std::__to_address(__first.__seg_), - std::__to_address(__first.__seg_ + __nw), - std::__to_address(__result.__seg_)); - __n -= __nw * __bits_per_word; - __result.__seg_ += __nw; - // do last word - if (__n > 0) { - __first.__seg_ += __nw; - __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); - __storage_type __b = *__first.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b; - __result.__ctz_ = static_cast<unsigned>(__n); - } - } - return __result; -} - -template <class _Cp, bool _IsConst> -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_unaligned( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - using _In = __bit_iterator<_Cp, _IsConst>; - using difference_type = typename _In::difference_type; - using __storage_type = typename _In::__storage_type; - - const int __bits_per_word = _In::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__first.__ctz_ != 0) { - unsigned __clz_f = __bits_per_word - __first.__ctz_; - difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n); - __n -= __dn; - __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); - __storage_type __b = *__first.__seg_ & __m; - unsigned __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); - __m = std::__middle_mask<__storage_type>(__clz_r - __ddn, __result.__ctz_); - *__result.__seg_ &= ~__m; - if (__result.__ctz_ > __first.__ctz_) - *__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_); - else - *__result.__seg_ |= __b >> (__first.__ctz_ - __result.__ctz_); - __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word); - __dn -= __ddn; - if (__dn > 0) { - __m = std::__trailing_mask<__storage_type>(__bits_per_word - __dn); - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b >> (__first.__ctz_ + __ddn); - __result.__ctz_ = static_cast<unsigned>(__dn); - } - ++__first.__seg_; - // __first.__ctz_ = 0; - } - // __first.__ctz_ == 0; - // do middle words - unsigned __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __m = std::__leading_mask<__storage_type>(__result.__ctz_); - for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { - __storage_type __b = *__first.__seg_; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b << __result.__ctz_; - ++__result.__seg_; - *__result.__seg_ &= __m; - *__result.__seg_ |= __b >> __clz_r; - } - // do last word - if (__n > 0) { - __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); - __storage_type __b = *__first.__seg_ & __m; - __storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r)); - __m = std::__middle_mask<__storage_type>(__clz_r - __dn, __result.__ctz_); - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b << __result.__ctz_; - __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; - __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word); - __n -= __dn; - if (__n > 0) { - __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b >> __dn; - __result.__ctz_ = static_cast<unsigned>(__n); - } - } - } - return __result; -} - struct __copy_impl { - template <class _InIter, class _Sent, class _OutIter> + template <class _InIter, + class _Sent, + class _OutIter, + __enable_if_t<!__specialized_algorithm<_Algorithm::__copy, + __iterator_pair<_InIter, _Sent>, + __single_iterator<_OutIter> >::__has_algorithm, + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> operator()(_InIter __first, _Sent __last, _OutIter __result) const { while (__first != __last) { @@ -167,37 +56,39 @@ struct __copy_impl { return std::make_pair(std::move(__first), std::move(__result)); } - template <class _InIter, class _OutIter> - struct _CopySegment { - using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_InIter>; - - _OutIter& __result_; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _CopySegment(_OutIter& __result) - : __result_(__result) {} - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void - operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) { - __result_ = std::__copy(__lfirst, __llast, std::move(__result_)).second; - } - }; + template <class _InIter, + class _Sent, + class _OutIter, + __enable_if_t<__specialized_algorithm<_Algorithm::__copy, + __iterator_pair<_InIter, _Sent>, + __single_iterator<_OutIter> >::__has_algorithm, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 static pair<_InIter, _OutIter> + operator()(_InIter __first, _Sent __last, _OutIter __result) { + return __specialized_algorithm<_Algorithm::__copy, __iterator_pair<_InIter, _Sent>, __single_iterator<_OutIter> >()( + std::move(__first), std::move(__last), 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 { - std::__for_each_segment(__first, __last, _CopySegment<_InIter, _OutIter>(__result)); + using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator; + std::__for_each_segment(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) { + __result = std::__copy(std::move(__lfirst), std::move(__llast), std::move(__result)).second; + }); return std::make_pair(__last, std::move(__result)); } 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 { using _Traits = __segmented_iterator_traits<_OutIter>; - using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + using _DiffT = + typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type; if (__first == __last) return std::make_pair(std::move(__first), std::move(__result)); @@ -217,16 +108,6 @@ struct __copy_impl { } } - template <class _Cp, bool _IsConst> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > - operator()(__bit_iterator<_Cp, _IsConst> __first, - __bit_iterator<_Cp, _IsConst> __last, - __bit_iterator<_Cp, false> __result) const { - if (__first.__ctz_ == __result.__ctz_) - return std::make_pair(__last, std::__copy_aligned(__first, __last, __result)); - return std::make_pair(__last, std::__copy_unaligned(__first, __last, __result)); - } - // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template <class _In, class _Out, __enable_if_t<__can_lower_copy_assignment_to_memmove<_In, _Out>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/lib/libcxx/include/__algorithm/copy_backward.h b/lib/libcxx/include/__algorithm/copy_backward.h @@ -11,6 +11,7 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/copy_n.h> +#include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> @@ -170,37 +171,20 @@ 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>; - auto __sfirst = _Traits::__segment(__first); - auto __slast = _Traits::__segment(__last); - if (__sfirst == __slast) { - auto __iters = - std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); - return std::make_pair(__last, __iters.second); - } - - __result = - std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__local(__last), std::move(__result)) - .second; - --__slast; - while (__sfirst != __slast) { - __result = - std::__copy_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__end(__slast), std::move(__result)) - .second; - --__slast; - } - __result = std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__slast), std::move(__result)) - .second; + using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator; + std::__for_each_segment_backward(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) { + __result = std::__copy_backward<_AlgPolicy>(std::move(__lfirst), std::move(__llast), std::move(__result)).second; + }); return std::make_pair(__last, std::move(__result)); } 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 { @@ -214,7 +198,8 @@ struct __copy_backward_impl { auto __local_last = _Traits::__local(__result); while (true) { - using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + using _DiffT = + typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type; auto __local_first = _Traits::__begin(__segment_iterator); auto __size = std::min<_DiffT>(__local_last - __local_first, __last - __first); diff --git a/lib/libcxx/include/__algorithm/copy_n.h b/lib/libcxx/include/__algorithm/copy_n.h @@ -10,31 +10,63 @@ #define _LIBCPP___ALGORITHM_COPY_N_H #include <__algorithm/copy.h> +#include <__algorithm/iterator_operations.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__type_traits/enable_if.h> #include <__utility/convert_to_integral.h> +#include <__utility/move.h> +#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD +template <class _AlgPolicy, + class _InIter, + class _OutIter, + __enable_if_t<__has_random_access_iterator_category<_InIter>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter> +__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) { + return std::__copy(__first, __first + __n, std::move(__result)); +} + +template <class _AlgPolicy, + class _InIter, + class _OutIter, + __enable_if_t<!__has_random_access_iterator_category<_InIter>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter> +__copy_n(_InIter __first, typename _IterOps<_AlgPolicy>::template __difference_type<_InIter> __n, _OutIter __result) { + while (__n != 0) { + *__result = *__first; + ++__first; + ++__result; + --__n; + } + return std::make_pair(std::move(__first), std::move(__result)); +} + +// The InputIterator case is handled specially here because it's been written in a way to avoid incrementing __first +// if not absolutely required. This was done to allow its use with istream_iterator and we want to avoid breaking +// people, at least currently. +// See https://github.com/llvm/llvm-project/commit/99847d2bf132854fffa019bab19818768102ccad template <class _InputIterator, class _Size, class _OutputIterator, - __enable_if_t<__has_input_iterator_category<_InputIterator>::value && - !__has_random_access_iterator_category<_InputIterator>::value, - int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator -copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { - typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; - _IntegralSize __n = __orig_n; - if (__n > 0) { + __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) { + using _IntegralSize = decltype(std::__convert_to_integral(__n)); + _IntegralSize __converted = __n; + if (__converted > 0) { *__result = *__first; ++__result; - for (--__n; __n > 0; --__n) { + for (--__converted; __converted > 0; --__converted) { ++__first; *__result = *__first; ++__result; @@ -46,15 +78,17 @@ copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { template <class _InputIterator, class _Size, class _OutputIterator, - __enable_if_t<__has_random_access_iterator_category<_InputIterator>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator -copy_n(_InputIterator __first, _Size __orig_n, _OutputIterator __result) { - typedef typename iterator_traits<_InputIterator>::difference_type difference_type; - typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; - _IntegralSize __n = __orig_n; - return std::copy(__first, __first + difference_type(__n), __result); + __enable_if_t<!__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) { + using _IntegralSize = decltype(std::__convert_to_integral(__n)); + _IntegralSize __converted = __n; + return std::__copy_n<_ClassicAlgPolicy>(__first, __iterator_difference_type<_InputIterator>(__converted), __result) + .second; } _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_COPY_N_H diff --git a/lib/libcxx/include/__algorithm/count.h b/lib/libcxx/include/__algorithm/count.h @@ -72,7 +72,7 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename __size_difference_t } template <class, class _Cp, bool _IsConst, class _Tp, class _Proj, __enable_if_t<__is_identity<_Proj>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<__bit_iterator<_Cp, _IsConst> > +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iterator_difference_type<__bit_iterator<_Cp, _IsConst> > __count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, const _Tp& __value, _Proj&) { if (__value) return std::__count_bool<true>( @@ -82,7 +82,7 @@ __count(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __l } template <class _InputIterator, class _Tp> -[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iter_diff_t<_InputIterator> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __iterator_difference_type<_InputIterator> count(_InputIterator __first, _InputIterator __last, const _Tp& __value) { __identity __proj; return std::__count<_ClassicAlgPolicy>(__first, __last, __value, __proj); diff --git a/lib/libcxx/include/__algorithm/equal.h b/lib/libcxx/include/__algorithm/equal.h @@ -160,22 +160,28 @@ template <class _Cp, bool _IsConst1, bool _IsConst2, class _BinaryPredicate, - __enable_if_t<__desugars_to_v<__equal_tag, _BinaryPredicate, bool, bool>, int> = 0> + class _Proj1, + class _Proj2, + __enable_if_t<__is_identity<_Proj1>::value && __is_identity<_Proj2>::value && + __desugars_to_v<__equal_tag, _BinaryPredicate, bool, bool>, + int> = 0> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( __bit_iterator<_Cp, _IsConst1> __first1, __bit_iterator<_Cp, _IsConst1> __last1, __bit_iterator<_Cp, _IsConst2> __first2, - _BinaryPredicate) { + _BinaryPredicate, + _Proj1&, + _Proj2&) { if (__first1.__ctz_ == __first2.__ctz_) return std::__equal_aligned(__first1, __last1, __first2); return std::__equal_unaligned(__first1, __last1, __first2); } -template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate> +template <class _InIter1, class _Sent1, class _InIter2, class _Pred, class _Proj1, class _Proj2> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_iter_impl( - _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate& __pred) { + _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { for (; __first1 != __last1; ++__first1, (void)++__first2) - if (!__pred(*__first1, *__first2)) + if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) return false; return true; } @@ -183,19 +189,23 @@ template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate> template <class _Tp, class _Up, class _BinaryPredicate, - __enable_if_t<__desugars_to_v<__equal_tag, _BinaryPredicate, _Tp, _Up> && !is_volatile<_Tp>::value && - !is_volatile<_Up>::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, + class _Proj1, + class _Proj2, + __enable_if_t<__is_identity<_Proj1>::value && __is_identity<_Proj2>::value && + __desugars_to_v<__equal_tag, _BinaryPredicate, _Tp, _Up> && !is_volatile<_Tp>::value && + !is_volatile<_Up>::value && __is_trivially_equality_comparable_v<_Tp, _Up>, int> = 0> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool -__equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&) { +__equal_iter_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _BinaryPredicate&, _Proj1&, _Proj2&) { return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); } template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred) { + __identity __proj; return std::__equal_iter_impl( - std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred); + std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), __pred, __proj, __proj); } template <class _InputIterator1, class _InputIterator2> @@ -206,52 +216,28 @@ equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first #if _LIBCPP_STD_VER >= 14 -template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2> -[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( - _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { - while (__first1 != __last1 && __first2 != __last2) { - if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) - return false; - ++__first1; - ++__first2; - } - return __first1 == __last1 && __first2 == __last2; -} - -template <class _Tp, - class _Up, - class _Pred, - class _Proj1, - class _Proj2, - __enable_if_t<__desugars_to_v<__equal_tag, _Pred, _Tp, _Up> && __is_identity<_Proj1>::value && - __is_identity<_Proj2>::value && !is_volatile<_Tp>::value && !is_volatile<_Up>::value && - __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, - int> = 0> -[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool -__equal_impl(_Tp* __first1, _Tp* __last1, _Up* __first2, _Up*, _Pred&, _Proj1&, _Proj2&) { - return std::__constexpr_memcmp_equal(__first1, __first2, __element_count(__last1 - __first1)); -} - -template <class _Cp, - bool _IsConst1, - bool _IsConst2, +template <bool __known_equal_length, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, class _Pred, class _Proj1, - class _Proj2, - __enable_if_t<__desugars_to_v<__equal_tag, _Pred, bool, bool> && __is_identity<_Proj1>::value && - __is_identity<_Proj2>::value, - int> = 0> + class _Proj2> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __equal_impl( - __bit_iterator<_Cp, _IsConst1> __first1, - __bit_iterator<_Cp, _IsConst1> __last1, - __bit_iterator<_Cp, _IsConst2> __first2, - __bit_iterator<_Cp, _IsConst2>, - _Pred&, - _Proj1&, - _Proj2&) { - if (__first1.__ctz_ == __first2.__ctz_) - return std::__equal_aligned(__first1, __last1, __first2); - return std::__equal_unaligned(__first1, __last1, __first2); + _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __comp, _Proj1& __proj1, _Proj2& __proj2) { + if constexpr (__known_equal_length) { + return std::__equal_iter_impl( + std::move(__first1), std::move(__last1), std::move(__first2), __comp, __proj1, __proj2); + } else { + while (__first1 != __last1 && __first2 != __last2) { + if (!std::__invoke(__comp, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) + return false; + ++__first1; + ++__first2; + } + return __first1 == __last1 && __first2 == __last2; + } } template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate> @@ -261,13 +247,15 @@ equal(_InputIterator1 __first1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __pred) { - if constexpr (__has_random_access_iterator_category<_InputIterator1>::value && - __has_random_access_iterator_category<_InputIterator2>::value) { + static constexpr bool __both_random_access = + __has_random_access_iterator_category<_InputIterator1>::value && + __has_random_access_iterator_category<_InputIterator2>::value; + if constexpr (__both_random_access) { if (std::distance(__first1, __last1) != std::distance(__first2, __last2)) return false; } __identity __proj; - return std::__equal_impl( + return std::__equal_impl<__both_random_access>( std::__unwrap_iter(__first1), std::__unwrap_iter(__last1), std::__unwrap_iter(__first2), diff --git a/lib/libcxx/include/__algorithm/fill.h b/lib/libcxx/include/__algorithm/fill.h @@ -10,8 +10,12 @@ #define _LIBCPP___ALGORITHM_FILL_H #include <__algorithm/fill_n.h> +#include <__algorithm/for_each_segment.h> #include <__config> #include <__iterator/iterator_traits.h> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,23 +25,37 @@ _LIBCPP_BEGIN_NAMESPACE_STD // fill isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset. -template <class _ForwardIterator, class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, forward_iterator_tag) { +template <class _ForwardIterator, class _Sentinel, class _Tp> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __value) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (is_same<_ForwardIterator, _Sentinel>::value && __is_segmented_iterator_v<_ForwardIterator>) { + using __local_iterator_t = typename __segmented_iterator_traits<_ForwardIterator>::__local_iterator; + std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { + std::__fill(__lfirst, __llast, __value); + }); + return __last; + } +#endif for (; __first != __last; ++__first) *__first = __value; + return __first; } -template <class _RandomAccessIterator, class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__fill(_RandomAccessIterator __first, _RandomAccessIterator __last, const _Tp& __value, random_access_iterator_tag) { - std::fill_n(__first, __last - __first, __value); +template <class _RandomAccessIterator, + class _Tp, + __enable_if_t<__has_random_access_iterator_category<_RandomAccessIterator>::value && + !__is_segmented_iterator_v<_RandomAccessIterator>, + int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator +__fill(_RandomAccessIterator __first, _RandomAccessIterator __last, const _Tp& __value) { + return std::__fill_n(__first, __last - __first, __value); } template <class _ForwardIterator, class _Tp> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { - std::__fill(__first, __last, __value, typename iterator_traits<_ForwardIterator>::iterator_category()); + std::__fill(__first, __last, __value); } _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__algorithm/fill_n.h b/lib/libcxx/include/__algorithm/fill_n.h @@ -9,11 +9,14 @@ #ifndef _LIBCPP___ALGORITHM_FILL_N_H #define _LIBCPP___ALGORITHM_FILL_N_H -#include <__algorithm/min.h> +#include <__algorithm/for_each_n_segment.h> +#include <__algorithm/specialized_algorithms.h> #include <__config> -#include <__fwd/bit_reference.h> -#include <__memory/pointer_traits.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/segmented_iterator.h> +#include <__type_traits/enable_if.h> #include <__utility/convert_to_integral.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -26,56 +29,39 @@ _LIBCPP_BEGIN_NAMESPACE_STD // fill_n isn't specialized for std::memset, because the compiler already optimizes the loop to a call to std::memset. -template <class _OutputIterator, class _Size, class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator -__fill_n(_OutputIterator __first, _Size __n, const _Tp& __value); - -template <bool _FillVal, class _Cp> -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void -__fill_n_bool(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) { - using _It = __bit_iterator<_Cp, false>; - using __storage_type = typename _It::__storage_type; - - const int __bits_per_word = _It::__bits_per_word; - // do first partial word - if (__first.__ctz_ != 0) { - __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); - __storage_type __dn = std::min(__clz_f, __n); - std::__fill_masked_range(std::__to_address(__first.__seg_), __clz_f - __dn, __first.__ctz_, _FillVal); - __n -= __dn; - ++__first.__seg_; - } - // do middle whole words - __storage_type __nw = __n / __bits_per_word; - std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0); - __n -= __nw * __bits_per_word; - // do last partial word - if (__n > 0) { - __first.__seg_ += __nw; - std::__fill_masked_range(std::__to_address(__first.__seg_), __bits_per_word - __n, 0u, _FillVal); - } -} - -template <class _Cp, class _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> -__fill_n(__bit_iterator<_Cp, false> __first, _Size __n, const bool& __value) { - if (__n > 0) { - if (__value) - std::__fill_n_bool<true>(__first, __n); - else - std::__fill_n_bool<false>(__first, __n); - } - return __first + __n; -} - -template <class _OutputIterator, class _Size, class _Tp> +template < + class _OutputIterator, + class _Size, + class _Tp, + __enable_if_t<!__specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutputIterator> >::__has_algorithm, + int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator __fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (__is_segmented_iterator_v<_OutputIterator>) { + using __local_iterator = typename __segmented_iterator_traits<_OutputIterator>::__local_iterator; + if constexpr (__has_random_access_iterator_category<__local_iterator>::value) { + return std::__for_each_n_segment(__first, __n, [&](__local_iterator __lfirst, __local_iterator __llast) { + std::__fill_n(__lfirst, __llast - __lfirst, __value); + }); + } + } +#endif for (; __n > 0; ++__first, (void)--__n) *__first = __value; return __first; } +template <class _OutIter, + class _Size, + class _Tp, + __enable_if_t<__specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutIter> >::__has_algorithm, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutIter __fill_n(_OutIter __first, _Size __n, const _Tp& __value) { + return __specialized_algorithm<_Algorithm::__fill_n, __single_iterator<_OutIter> >()( + std::move(__first), __n, __value); +} + template <class _OutputIterator, class _Size, class _Tp> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator fill_n(_OutputIterator __first, _Size __n, const _Tp& __value) { diff --git a/lib/libcxx/include/__algorithm/find.h b/lib/libcxx/include/__algorithm/find.h @@ -12,16 +12,19 @@ #include <__algorithm/find_segment_if.h> #include <__algorithm/min.h> +#include <__algorithm/simd_utils.h> #include <__algorithm/unwrap_iter.h> #include <__bit/countr.h> #include <__bit/invert_if.h> #include <__config> +#include <__cstddef/size_t.h> #include <__functional/identity.h> #include <__fwd/bit_reference.h> #include <__iterator/segmented_iterator.h> #include <__string/constexpr_c_functions.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> +#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_equality_comparable.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_signed.h> @@ -44,46 +47,108 @@ _LIBCPP_BEGIN_NAMESPACE_STD // generic implementation template <class _Iter, class _Sent, class _Tp, class _Proj> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter -__find(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { +__find_loop(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { for (; __first != __last; ++__first) if (std::__invoke(__proj, *__first) == __value) break; return __first; } -// trivially equality comparable implementations -template <class _Tp, - class _Up, - class _Proj, - __enable_if_t<__is_identity<_Proj>::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && - sizeof(_Tp) == 1, - int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) { - if (auto __ret = std::__constexpr_memchr(__first, __value, __last - __first)) - return __ret; - return __last; +template <class _Iter, class _Sent, class _Tp, class _Proj> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter +__find(_Iter __first, _Sent __last, const _Tp& __value, _Proj& __proj) { + return std::__find_loop(std::move(__first), std::move(__last), __value, __proj); } -#if _LIBCPP_HAS_WIDE_CHARACTERS +#if _LIBCPP_VECTORIZE_ALGORITHMS +template <class _Tp, class _Up> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find_vectorized(_Tp* __first, _Tp* __last, _Up __value) { + if (!__libcpp_is_constant_evaluated()) { + constexpr size_t __unroll_count = 4; + constexpr size_t __vec_size = __native_vector_size<_Tp>; + using __vec = __simd_vector<_Tp, __vec_size>; + + auto __orig_first = __first; + + auto __values = static_cast<__simd_vector<_Tp, __vec_size>>(__value); // broadcast the value + while (static_cast<size_t>(__last - __first) >= __unroll_count * __vec_size) [[__unlikely__]] { + __vec __lhs[__unroll_count]; + + for (size_t __i = 0; __i != __unroll_count; ++__i) + __lhs[__i] = std::__load_vector<__vec>(__first + __i * __vec_size); + + for (size_t __i = 0; __i != __unroll_count; ++__i) { + if (auto __cmp_res = __lhs[__i] == __values; std::__any_of(__cmp_res)) { + auto __offset = __i * __vec_size + std::__find_first_set(__cmp_res); + return __first + __offset; + } + } + + __first += __unroll_count * __vec_size; + } + + // check the remaining 0-3 vectors + while (static_cast<size_t>(__last - __first) >= __vec_size) { + if (auto __cmp_res = std::__load_vector<__vec>(__first) == __values; std::__any_of(__cmp_res)) { + return __first + std::__find_first_set(__cmp_res); + } + __first += __vec_size; + } + + if (__last - __first == 0) + return __first; + + // Check if we can load elements in front of the current pointer. If that's the case load a vector at + // (last - vector_size) to check the remaining elements + if (static_cast<size_t>(__first - __orig_first) >= __vec_size) { + __first = __last - __vec_size; + return __first + std::__find_first_set(std::__load_vector<__vec>(__first) == __values); + } + } + + __identity __proj; + return std::__find_loop(__first, __last, __value, __proj); +} +#endif + +#ifndef _LIBCPP_CXX03_LANG +// trivially equality comparable implementations template <class _Tp, class _Up, class _Proj, - __enable_if_t<__is_identity<_Proj>::value && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && - sizeof(_Tp) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp) >= _LIBCPP_ALIGNOF(wchar_t), - int> = 0> + __enable_if_t<__is_identity<_Proj>::value && __is_trivially_equality_comparable_v<_Tp, _Up>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __find(_Tp* __first, _Tp* __last, const _Up& __value, _Proj&) { - if (auto __ret = std::__constexpr_wmemchr(__first, __value, __last - __first)) - return __ret; - return __last; + if constexpr (sizeof(_Tp) == 1) { + if (auto __ret = std::__constexpr_memchr(__first, __value, __last - __first)) + return __ret; + return __last; + } +# if _LIBCPP_HAS_WIDE_CHARACTERS + else if constexpr (sizeof(_Tp) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp) >= _LIBCPP_ALIGNOF(wchar_t)) { + if (auto __ret = std::__constexpr_wmemchr(__first, __value, __last - __first)) + return __ret; + return __last; + } +# endif +# if _LIBCPP_VECTORIZE_ALGORITHMS + else if constexpr (is_integral<_Tp>::value) { + return std::__find_vectorized(__first, __last, __value); + } +# endif + else { + __identity __proj; + return std::__find_loop(__first, __last, __value, __proj); + } } -#endif // _LIBCPP_HAS_WIDE_CHARACTERS +#endif // TODO: This should also be possible to get right with different signedness // cast integral types to allow vectorization template <class _Tp, class _Up, class _Proj, - __enable_if_t<__is_identity<_Proj>::value && !__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value && + __enable_if_t<__is_identity<_Proj>::value && !__is_trivially_equality_comparable_v<_Tp, _Up> && is_integral<_Tp>::value && is_integral<_Up>::value && is_signed<_Tp>::value == is_signed<_Up>::value, int> = 0> @@ -143,31 +208,23 @@ __find(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __la // segmented iterator implementation -template <class> -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); + using __local_iterator = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; + return std::__find_segment_if( + std::move(__first), + std::move(__last), + [&__value](__local_iterator __lfirst, __local_iterator __llast, _Proj& __lproj) { + return std::__rewrap_iter( + __lfirst, std::__find(std::__unwrap_iter(__lfirst), std::__unwrap_iter(__llast), __value, __lproj)); + }, + __proj); } -template <class _Tp> -struct __find_segment { - const _Tp& __value_; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __find_segment(const _Tp& __value) : __value_(__value) {} - - template <class _InputIterator, class _Proj> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _InputIterator - operator()(_InputIterator __first, _InputIterator __last, _Proj& __proj) const { - return std::__find(__first, __last, __value_, __proj); - } -}; - // public API template <class _InputIterator, class _Tp> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator diff --git a/lib/libcxx/include/__algorithm/find_end.h b/lib/libcxx/include/__algorithm/find_end.h @@ -76,6 +76,111 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> } } +template <class _AlgPolicy, + class _Pred, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter1> __find_end_impl( + _Iter1 __first1, + _Sent1 __sent1, + _Iter2 __first2, + _Sent2 __sent2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + bidirectional_iterator_tag, + bidirectional_iterator_tag) { + auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1); + auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2); + // modeled after search algorithm (in reverse) + if (__first2 == __last2) + return std::make_pair(__last1, __last1); // Everything matches an empty sequence + _Iter1 __l1 = __last1; + _Iter2 __l2 = __last2; + --__l2; + while (true) { + // Find last element in sequence 1 that matches *(__last2-1), with a mininum of loop checks + while (true) { + if (__first1 == __l1) // return __last1 if no element matches *__first2 + return std::make_pair(__last1, __last1); + if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2))) + break; + } + // *__l1 matches *__l2, now match elements before here + _Iter1 __match_last = __l1; + _Iter1 __m1 = __l1; + _Iter2 __m2 = __l2; + while (true) { + if (__m2 == __first2) // If pattern exhausted, __m1 is the answer (works for 1 element pattern) + return std::make_pair(__m1, ++__match_last); + if (__m1 == __first1) // Otherwise if source exhaused, pattern not found + return std::make_pair(__last1, __last1); + + // if there is a mismatch, restart with a new __l1 + if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2))) { + break; + } // else there is a match, check next elements + } + } +} + +template <class _AlgPolicy, + class _Pred, + class _Iter1, + class _Sent1, + class _Iter2, + class _Sent2, + class _Proj1, + class _Proj2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __find_end_impl( + _Iter1 __first1, + _Sent1 __sent1, + _Iter2 __first2, + _Sent2 __sent2, + _Pred& __pred, + _Proj1& __proj1, + _Proj2& __proj2, + random_access_iterator_tag, + random_access_iterator_tag) { + typedef typename iterator_traits<_Iter1>::difference_type _D1; + auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1); + auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2); + // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern + auto __len2 = __last2 - __first2; + if (__len2 == 0) + return std::make_pair(__last1, __last1); + auto __len1 = __last1 - __first1; + if (__len1 < __len2) + return std::make_pair(__last1, __last1); + const _Iter1 __s = __first1 + _D1(__len2 - 1); // End of pattern match can't go before here + _Iter1 __l1 = __last1; + _Iter2 __l2 = __last2; + --__l2; + while (true) { + while (true) { + if (__s == __l1) + return std::make_pair(__last1, __last1); + if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2))) + break; + } + _Iter1 __last_match = __l1; + _Iter1 __m1 = __l1; + _Iter2 __m2 = __l2; + while (true) { + if (__m2 == __first2) + return std::make_pair(__m1, ++__last_match); + // no need to check range on __m1 because __s guarantees we have enough source + if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2))) { + break; + } + } + } +} + template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_end_classic( _ForwardIterator1 __first1, diff --git a/lib/libcxx/include/__algorithm/for_each.h b/lib/libcxx/include/__algorithm/for_each.h @@ -11,45 +11,41 @@ #define _LIBCPP___ALGORITHM_FOR_EACH_H #include <__algorithm/for_each_segment.h> +#include <__algorithm/specialized_algorithms.h> #include <__config> #include <__functional/identity.h> #include <__iterator/segmented_iterator.h> -#include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> -#include <__utility/move.h> +#include <__type_traits/is_same.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif -_LIBCPP_PUSH_MACROS -#include <__undef_macros> - _LIBCPP_BEGIN_NAMESPACE_STD template <class _InputIterator, class _Sent, class _Func, class _Proj> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator -__for_each(_InputIterator __first, _Sent __last, _Func& __f, _Proj& __proj) { +__for_each(_InputIterator __first, _Sent __last, _Func& __func, _Proj& __proj) { +#ifndef _LIBCPP_CXX03_LANG + if constexpr (using _SpecialAlg = + __specialized_algorithm<_Algorithm::__for_each, __iterator_pair<_InputIterator, _Sent>>; + _SpecialAlg::__has_algorithm) { + _SpecialAlg()(__first, __last, __func, __proj); + return __last; + } else if constexpr (is_same<_InputIterator, _Sent>::value && __is_segmented_iterator_v<_InputIterator>) { + using __local_iterator_t = typename __segmented_iterator_traits<_InputIterator>::__local_iterator; + std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { + std::__for_each(__lfirst, __llast, __func, __proj); + }); + return __last; + } +#endif for (; __first != __last; ++__first) - std::__invoke(__f, std::__invoke(__proj, *__first)); + std::__invoke(__func, std::__invoke(__proj, *__first)); return __first; } -#ifndef _LIBCPP_CXX03_LANG -template <class _SegmentedIterator, - class _Func, - class _Proj, - __enable_if_t<__is_segmented_iterator<_SegmentedIterator>::value, 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; - std::__for_each_segment(__first, __last, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { - std::__for_each(__lfirst, __llast, __func, __proj); - }); - return __last; -} -#endif // !_LIBCPP_CXX03_LANG - template <class _InputIterator, class _Func> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Func for_each(_InputIterator __first, _InputIterator __last, _Func __f) { @@ -60,6 +56,4 @@ for_each(_InputIterator __first, _InputIterator __last, _Func __f) { _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS - #endif // _LIBCPP___ALGORITHM_FOR_EACH_H diff --git a/lib/libcxx/include/__algorithm/for_each_n.h b/lib/libcxx/include/__algorithm/for_each_n.h @@ -16,10 +16,7 @@ #include <__functional/identity.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> -#include <__type_traits/disjunction.h> -#include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> -#include <__type_traits/negation.h> #include <__utility/convert_to_integral.h> #include <__utility/move.h> @@ -32,57 +29,33 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <class _InputIterator, - class _Size, - 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, - int> = 0> +template <class _InputIterator, class _Size, class _Func, class _Proj> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIterator __for_each_n(_InputIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) { typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; _IntegralSize __n = __orig_n; - while (__n > 0) { - std::__invoke(__f, std::__invoke(__proj, *__first)); - ++__first; - --__n; - } - return std::move(__first); -} - -template <class _RandIter, - class _Size, - class _Func, - class _Proj, - __enable_if_t<__has_random_access_iterator_category<_RandIter>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandIter -__for_each_n(_RandIter __first, _Size __orig_n, _Func& __f, _Proj& __proj) { - typename std::iterator_traits<_RandIter>::difference_type __n = __orig_n; - auto __last = __first + __n; - std::__for_each(__first, __last, __f, __proj); - return __last; -} #ifndef _LIBCPP_CXX03_LANG -template <class _SegmentedIterator, - class _Size, - class _Func, - class _Proj, - __enable_if_t<!__has_random_access_iterator_category<_SegmentedIterator>::value && - __is_segmented_iterator<_SegmentedIterator>::value && - __has_random_access_iterator_category< - typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator>::value, - int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _SegmentedIterator -__for_each_n(_SegmentedIterator __first, _Size __orig_n, _Func& __f, _Proj& __proj) { - using __local_iterator_t = typename __segmented_iterator_traits<_SegmentedIterator>::__local_iterator; - return std::__for_each_n_segment(__first, __orig_n, [&](__local_iterator_t __lfirst, __local_iterator_t __llast) { - std::__for_each(__lfirst, __llast, __f, __proj); - }); + if constexpr (__is_segmented_iterator_v<_InputIterator>) { + using __local_iterator = typename __segmented_iterator_traits<_InputIterator>::__local_iterator; + if constexpr (__has_random_access_iterator_category<__local_iterator>::value) { + return std::__for_each_n_segment(__first, __orig_n, [&](__local_iterator __lfirst, __local_iterator __llast) { + std::__for_each(__lfirst, __llast, __f, __proj); + }); + } else { + return std::__for_each(__first, __first + __n, __f, __proj); + } + } else +#endif + { + while (__n > 0) { + std::__invoke(__f, std::__invoke(__proj, *__first)); + ++__first; + --__n; + } + return std::move(__first); + } } -#endif // !_LIBCPP_CXX03_LANG #if _LIBCPP_STD_VER >= 17 diff --git a/lib/libcxx/include/__algorithm/for_each_n_segment.h b/lib/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/lib/libcxx/include/__algorithm/for_each_segment.h b/lib/libcxx/include/__algorithm/for_each_segment.h @@ -48,6 +48,32 @@ __for_each_segment(_SegmentedIterator __first, _SegmentedIterator __last, _Funct __func(_Traits::__begin(__sfirst), _Traits::__local(__last)); } +template <class _SegmentedIterator, class _Functor> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void +__for_each_segment_backward(_SegmentedIterator __first, _SegmentedIterator __last, _Functor __func) { + using _Traits = __segmented_iterator_traits<_SegmentedIterator>; + + auto __sfirst = _Traits::__segment(__first); + auto __slast = _Traits::__segment(__last); + + // We are in a single segment, so we might not be at the beginning or end + if (__sfirst == __slast) { + __func(_Traits::__local(__first), _Traits::__local(__last)); + return; + } + + // We have more than one segment. Iterate over the last segment, since we might not start at the end + __func(_Traits::__begin(__slast), _Traits::__local(__last)); + --__slast; + // iterate over the segments which are guaranteed to be completely in the range + while (__sfirst != __slast) { + __func(_Traits::__begin(__slast), _Traits::__end(__slast)); + --__slast; + } + // iterate over the first segment + __func(_Traits::__local(__first), _Traits::__end(__slast)); +} + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ALGORITHM_FOR_EACH_SEGMENT_H diff --git a/lib/libcxx/include/__algorithm/generate.h b/lib/libcxx/include/__algorithm/generate.h @@ -9,7 +9,9 @@ #ifndef _LIBCPP___ALGORITHM_GENERATE_H #define _LIBCPP___ALGORITHM_GENERATE_H +#include <__algorithm/for_each.h> #include <__config> +#include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,8 +22,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _ForwardIterator, class _Generator> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void generate(_ForwardIterator __first, _ForwardIterator __last, _Generator __gen) { - for (; __first != __last; ++__first) - *__first = __gen(); + using __iter_ref = decltype(*__first); + std::for_each(__first, __last, [&](__iter_ref __element) { std::forward<__iter_ref>(__element) = __gen(); }); } _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__algorithm/generate_n.h b/lib/libcxx/include/__algorithm/generate_n.h @@ -9,25 +9,38 @@ #ifndef _LIBCPP___ALGORITHM_GENERATE_N_H #define _LIBCPP___ALGORITHM_GENERATE_N_H +#include <__algorithm/for_each_n.h> #include <__config> -#include <__utility/convert_to_integral.h> +#include <__functional/identity.h> +#include <__utility/forward.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template <class _OutputIterator, class _Size, class _Generator> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +__generate_n(_OutputIterator __first, _Size __orig_n, _Generator& __gen) { + using __iter_ref = decltype(*__first); + __identity __proj; + auto __f = [&](__iter_ref __element) { std::forward<__iter_ref>(__element) = __gen(); }; + return std::__for_each_n(std::move(__first), __orig_n, __f, __proj); +} + +template <class _OutputIterator, class _Size, class _Generator> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator generate_n(_OutputIterator __first, _Size __orig_n, _Generator __gen) { - typedef decltype(std::__convert_to_integral(__orig_n)) _IntegralSize; - _IntegralSize __n = __orig_n; - for (; __n > 0; ++__first, (void)--__n) - *__first = __gen(); - return __first; + return std::__generate_n(std::move(__first), __orig_n, __gen); } _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ALGORITHM_GENERATE_N_H diff --git a/lib/libcxx/include/__algorithm/is_permutation.h b/lib/libcxx/include/__algorithm/is_permutation.h @@ -78,7 +78,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation_impl( _Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2) { - using _D1 = __iter_diff_t<_Iter1>; + using _D1 = __iterator_difference_type<_Iter1>; for (auto __i = __first1; __i != __last1; ++__i) { // Have we already counted the number of *__i in [f1, l1)? @@ -126,7 +126,7 @@ template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _Fo return true; // __first1 != __last1 && *__first1 != *__first2 - using _D1 = __iter_diff_t<_ForwardIterator1>; + using _D1 = __iterator_difference_type<_ForwardIterator1>; _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); if (__l1 == _D1(1)) return false; @@ -173,10 +173,10 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation( if (__first2 == __last2) // Second range is shorter return false; - using _D1 = __iter_diff_t<_Iter1>; + using _D1 = __iterator_difference_type<_Iter1>; _D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1); - using _D2 = __iter_diff_t<_Iter2>; + using _D2 = __iterator_difference_type<_Iter2>; _D2 __l2 = _IterOps<_AlgPolicy>::distance(__first2, __last2); if (__l1 != __l2) return false; diff --git a/lib/libcxx/include/__algorithm/iterator_operations.h b/lib/libcxx/include/__algorithm/iterator_operations.h @@ -219,6 +219,9 @@ private: template <class _AlgPolicy, class _Iter> using __policy_iter_diff_t _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __difference_type<_Iter>; +template <class _AlgPolicy, class _Iter> +using __policy_value_type _LIBCPP_NODEBUG = typename _IterOps<_AlgPolicy>::template __value_type<_Iter>; + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/lib/libcxx/include/__algorithm/lexicographical_compare.h b/lib/libcxx/include/__algorithm/lexicographical_compare.h @@ -66,8 +66,8 @@ template <class _Tp, class _Proj2, class _Comp, __enable_if_t<__desugars_to_v<__totally_ordered_less_tag, _Comp, _Tp, _Tp> && !is_volatile<_Tp>::value && - __libcpp_is_trivially_equality_comparable<_Tp, _Tp>::value && - __is_identity<_Proj1>::value && __is_identity<_Proj2>::value, + __is_trivially_equality_comparable_v<_Tp, _Tp> && __is_identity<_Proj1>::value && + __is_identity<_Proj2>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __lexicographical_compare(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Tp* __last2, _Comp&, _Proj1&, _Proj2&) { diff --git a/lib/libcxx/include/__algorithm/lexicographical_compare_three_way.h b/lib/libcxx/include/__algorithm/lexicographical_compare_three_way.h @@ -37,13 +37,13 @@ template <class _InputIterator1, class _InputIterator2, class _Cmp> _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_path( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp& __comp) -> decltype(__comp(*__first1, *__first2)) { - static_assert( - signed_integral<__iter_diff_t<_InputIterator1>>, "Using a non-integral difference_type is undefined behavior."); - static_assert( - signed_integral<__iter_diff_t<_InputIterator2>>, "Using a non-integral difference_type is undefined behavior."); + static_assert(signed_integral<__iterator_difference_type<_InputIterator1>>, + "Using a non-integral difference_type is undefined behavior."); + static_assert(signed_integral<__iterator_difference_type<_InputIterator2>>, + "Using a non-integral difference_type is undefined behavior."); - using _Len1 = __iter_diff_t<_InputIterator1>; - using _Len2 = __iter_diff_t<_InputIterator2>; + using _Len1 = __iterator_difference_type<_InputIterator1>; + using _Len2 = __iterator_difference_type<_InputIterator2>; using _Common = common_type_t<_Len1, _Len2>; _Len1 __len1 = __last1 - __first1; diff --git a/lib/libcxx/include/__algorithm/make_heap.h b/lib/libcxx/include/__algorithm/make_heap.h @@ -12,9 +12,11 @@ #include <__algorithm/comp.h> #include <__algorithm/comp_ref_type.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/push_heap.h> #include <__algorithm/sift_down.h> #include <__config> #include <__iterator/iterator_traits.h> +#include <__type_traits/is_arithmetic.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -31,13 +33,23 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp) { __comp_ref_type<_Compare> __comp_ref = __comp; - using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; - difference_type __n = __last - __first; + using __diff_t = __iterator_difference_type<_RandomAccessIterator>; + const __diff_t __n = __last - __first; + + const bool __assume_both_children = is_arithmetic<__iterator_value_type<_RandomAccessIterator> >::value; + + // While it would be correct to always assume we have both children, in practice we observed this to be a performance + // improvement only for arithmetic types. + const __diff_t __sift_down_n = __assume_both_children ? ((__n & 1) ? __n : __n - 1) : __n; + if (__n > 1) { // start from the first parent, there is no need to consider children - for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) { - std::__sift_down<_AlgPolicy>(__first, __comp_ref, __n, __first + __start); + + for (__diff_t __start = (__sift_down_n - 2) / 2; __start >= 0; --__start) { + std::__sift_down<_AlgPolicy, __assume_both_children>(__first, __comp_ref, __sift_down_n, __start); } + if _LIBCPP_CONSTEXPR (__assume_both_children) + std::__sift_up<_AlgPolicy>(__first, __last, __comp, __n); } } diff --git a/lib/libcxx/include/__algorithm/mismatch.h b/lib/libcxx/include/__algorithm/mismatch.h @@ -60,7 +60,7 @@ __mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Pred& __pred, _Pro template <class _Iter> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter, _Iter> __mismatch_vectorized(_Iter __first1, _Iter __last1, _Iter __first2) { - using __value_type = __iter_value_type<_Iter>; + using __value_type = __iterator_value_type<_Iter>; constexpr size_t __unroll_count = 4; constexpr size_t __vec_size = __native_vector_size<__value_type>; using __vec = __simd_vector<__value_type, __vec_size>; @@ -136,7 +136,7 @@ template <class _Tp, class _Proj2, __enable_if_t<!is_integral<_Tp>::value && __desugars_to_v<__equal_tag, _Pred, _Tp, _Tp> && __is_identity<_Proj1>::value && __is_identity<_Proj2>::value && - __can_map_to_integer_v<_Tp> && __libcpp_is_trivially_equality_comparable<_Tp, _Tp>::value, + __can_map_to_integer_v<_Tp> && __is_trivially_equality_comparable_v<_Tp, _Tp>, int> = 0> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Tp*, _Tp*> __mismatch(_Tp* __first1, _Tp* __last1, _Tp* __first2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { diff --git a/lib/libcxx/include/__algorithm/move.h b/lib/libcxx/include/__algorithm/move.h @@ -50,37 +50,26 @@ struct __move_impl { return std::make_pair(std::move(__first), std::move(__result)); } - template <class _InIter, class _OutIter> - struct _MoveSegment { - using _Traits _LIBCPP_NODEBUG = __segmented_iterator_traits<_InIter>; - - _OutIter& __result_; - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit _MoveSegment(_OutIter& __result) - : __result_(__result) {} - - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void - operator()(typename _Traits::__local_iterator __lfirst, typename _Traits::__local_iterator __llast) { - __result_ = std::__move<_AlgPolicy>(__lfirst, __llast, std::move(__result_)).second; - } - }; - - 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)); + using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator; + std::__for_each_segment(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) { + __result = std::__move<_AlgPolicy>(__lfirst, __llast, std::move(__result)).second; + }); return std::make_pair(__last, std::move(__result)); } 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 { using _Traits = __segmented_iterator_traits<_OutIter>; - using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + using _DiffT = + typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type; if (__first == __last) return std::make_pair(std::move(__first), std::move(__result)); diff --git a/lib/libcxx/include/__algorithm/move_backward.h b/lib/libcxx/include/__algorithm/move_backward.h @@ -11,6 +11,7 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_move_common.h> +#include <__algorithm/for_each_segment.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> @@ -51,42 +52,26 @@ 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>; - auto __sfirst = _Traits::__segment(__first); - auto __slast = _Traits::__segment(__last); - if (__sfirst == __slast) { - auto __iters = - std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); - return std::make_pair(__last, __iters.second); - } - - __result = - std::__move_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__local(__last), std::move(__result)) - .second; - --__slast; - while (__sfirst != __slast) { - __result = - std::__move_backward<_AlgPolicy>(_Traits::__begin(__slast), _Traits::__end(__slast), std::move(__result)) - .second; - --__slast; - } - __result = std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__slast), std::move(__result)) - .second; + using __local_iterator = typename __segmented_iterator_traits<_InIter>::__local_iterator; + std::__for_each_segment_backward(__first, __last, [&__result](__local_iterator __lfirst, __local_iterator __llast) { + __result = std::__move_backward<_AlgPolicy>(std::move(__lfirst), std::move(__llast), std::move(__result)).second; + }); return std::make_pair(__last, std::move(__result)); } 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 { using _Traits = __segmented_iterator_traits<_OutIter>; - using _DiffT = typename common_type<__iter_diff_t<_InIter>, __iter_diff_t<_OutIter> >::type; + using _DiffT = + typename common_type<__iterator_difference_type<_InIter>, __iterator_difference_type<_OutIter> >::type; // When the range contains no elements, __result might not be a valid iterator if (__first == __last) diff --git a/lib/libcxx/include/__algorithm/none_of.h b/lib/libcxx/include/__algorithm/none_of.h @@ -10,7 +10,9 @@ #ifndef _LIBCPP___ALGORITHM_NONE_OF_H #define _LIBCPP___ALGORITHM_NONE_OF_H +#include <__algorithm/any_of.h> #include <__config> +#include <__functional/identity.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,10 +23,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _InputIterator, class _Predicate> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool none_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) { - for (; __first != __last; ++__first) - if (__pred(*__first)) - return false; - return true; + __identity __proj; + return !std::__any_of(__first, __last, __pred, __proj); } _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__algorithm/partial_sort.h b/lib/libcxx/include/__algorithm/partial_sort.h @@ -45,7 +45,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator __part for (; __i != __last; ++__i) { if (__comp(*__i, *__first)) { _IterOps<_AlgPolicy>::iter_swap(__i, __first); - std::__sift_down<_AlgPolicy>(__first, __comp, __len, __first); + std::__sift_down<_AlgPolicy, false>(__first, __comp, __len, 0); } } std::__sort_heap<_AlgPolicy>(std::move(__first), std::move(__middle), __comp); diff --git a/lib/libcxx/include/__algorithm/partial_sort_copy.h b/lib/libcxx/include/__algorithm/partial_sort_copy.h @@ -60,7 +60,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator, _Random for (; __first != __last; ++__first) if (std::__invoke(__comp, std::__invoke(__proj1, *__first), std::__invoke(__proj2, *__result_first))) { *__result_first = *__first; - std::__sift_down<_AlgPolicy>(__result_first, __projected_comp, __len, __result_first); + std::__sift_down<_AlgPolicy, false>(__result_first, __projected_comp, __len, 0); } std::__sort_heap<_AlgPolicy>(__result_first, __r, __projected_comp); } diff --git a/lib/libcxx/include/__algorithm/pstl.h b/lib/libcxx/include/__algorithm/pstl.h @@ -115,7 +115,7 @@ template <class _ExecutionPolicy, class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __iterator_difference_type<_ForwardIterator> count_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( _ForwardIterator, "count_if(first, last, pred) requires [first, last) to be ForwardIterators"); @@ -129,7 +129,7 @@ template <class _ExecutionPolicy, class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_diff_t<_ForwardIterator> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI __iterator_difference_type<_ForwardIterator> count(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR( _ForwardIterator, "count(first, last, val) requires [first, last) to be ForwardIterators"); @@ -144,7 +144,7 @@ template <class _ExecutionPolicy, class _Pred, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI bool +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -166,7 +166,7 @@ template <class _ExecutionPolicy, class _ForwardIterator2, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI bool +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator1, "equal requires ForwardIterators"); _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator2, "equal requires ForwardIterators"); @@ -185,7 +185,7 @@ template <class _ExecutionPolicy, class _Pred, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI bool +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -209,7 +209,7 @@ template <class _ExecutionPolicy, class _ForwardIterator2, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI bool +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool equal(_ExecutionPolicy&& __policy, _ForwardIterator1 __first1, _ForwardIterator1 __last1, @@ -259,7 +259,7 @@ template <class _ExecutionPolicy, class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator find_if(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find_if requires ForwardIterators"); using _Implementation = __pstl::__dispatch<__pstl::__find_if, __pstl::__current_configuration, _RawPolicy>; @@ -272,7 +272,7 @@ template <class _ExecutionPolicy, class _Predicate, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator find_if_not(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate __pred) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find_if_not requires ForwardIterators"); using _Implementation = __pstl::__dispatch<__pstl::__find_if_not, __pstl::__current_configuration, _RawPolicy>; @@ -285,7 +285,7 @@ template <class _ExecutionPolicy, class _Tp, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _ForwardIterator +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _ForwardIterator find(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "find requires ForwardIterators"); using _Implementation = __pstl::__dispatch<__pstl::__find, __pstl::__current_configuration, _RawPolicy>; diff --git a/lib/libcxx/include/__algorithm/radix_sort.h b/lib/libcxx/include/__algorithm/radix_sort.h @@ -72,14 +72,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 14 template <class _InputIterator, class _OutputIterator> -_LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iter_value_type<_InputIterator>> +_LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iterator_value_type<_InputIterator>> __partial_sum_max(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { if (__first == __last) return {__result, 0}; - auto __max = *__first; - __iter_value_type<_InputIterator> __sum = *__first; - *__result = __sum; + auto __max = *__first; + __iterator_value_type<_InputIterator> __sum = *__first; + *__result = __sum; while (++__first != __last) { if (__max < *__first) { @@ -124,7 +124,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __nth_radix(size_t __radix_number, _Radix _ template <class _ForwardIterator, class _Map, class _RandomAccessIterator> _LIBCPP_HIDE_FROM_ABI constexpr void __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _RandomAccessIterator __counters) { - using __value_type = __iter_value_type<_ForwardIterator>; + using __value_type = __iterator_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; std::for_each(__first, __last, [&__counters, &__map](const auto& __preimage) { ++__counters[__map(__preimage)]; }); @@ -160,7 +160,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __collect_impl( _RandomAccessIterator1 __counters, _RandomAccessIterator2 __maximums, index_sequence<_Radices...>) { - using __value_type = __iter_value_type<_ForwardIterator>; + using __value_type = __iterator_value_type<_ForwardIterator>; constexpr auto __radix_value_range = __radix_sort_traits<__value_type, _Map, _Radix>::__radix_value_range; auto __previous = numeric_limits<__invoke_result_t<_Map, __value_type>>::min(); @@ -189,7 +189,7 @@ __collect(_ForwardIterator __first, _Radix __radix, _RandomAccessIterator1 __counters, _RandomAccessIterator2 __maximums) { - using __value_type = __iter_value_type<_ForwardIterator>; + using __value_type = __iterator_value_type<_ForwardIterator>; constexpr auto __radix_count = __radix_sort_traits<__value_type, _Map, _Radix>::__radix_count; return std::__collect_impl( __first, __last, __map, __radix, __counters, __maximums, make_index_sequence<__radix_count>()); @@ -213,10 +213,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __dispose_backward( template <class _ForwardIterator, class _RandomAccessIterator, class _Map> _LIBCPP_HIDE_FROM_ABI constexpr _RandomAccessIterator __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator __result, _Map __map) { - using __value_type = __iter_value_type<_ForwardIterator>; + using __value_type = __iterator_value_type<_ForwardIterator>; using __traits = __counting_sort_traits<__value_type, _Map>; - __iter_diff_t<_RandomAccessIterator> __counters[__traits::__value_range + 1] = {0}; + __iterator_difference_type<_RandomAccessIterator> __counters[__traits::__value_range + 1] = {0}; std::__collect(__first, __last, __map, std::next(std::begin(__counters))); std::__dispose(__first, __last, __result, __map, std::begin(__counters)); @@ -224,12 +224,13 @@ __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomA return __result + __counters[__traits::__value_range]; } -template <class _RandomAccessIterator1, - class _RandomAccessIterator2, - class _Map, - class _Radix, - enable_if_t< __radix_sort_traits<__iter_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count == 1, - int> = 0> +template < + class _RandomAccessIterator1, + class _RandomAccessIterator2, + class _Map, + class _Radix, + enable_if_t<__radix_sort_traits<__iterator_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count == 1, + int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, @@ -243,24 +244,25 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( std::move(__buffer, __buffer_end, __first); } -template < - class _RandomAccessIterator1, - class _RandomAccessIterator2, - class _Map, - class _Radix, - enable_if_t< __radix_sort_traits<__iter_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, - int> = 0 > +template <class _RandomAccessIterator1, + class _RandomAccessIterator2, + class _Map, + class _Radix, + enable_if_t< + __radix_sort_traits<__iterator_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, + int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( _RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer_begin, _Map __map, _Radix __radix) { - using __value_type = __iter_value_type<_RandomAccessIterator1>; + using __value_type = __iterator_value_type<_RandomAccessIterator1>; using __traits = __radix_sort_traits<__value_type, _Map, _Radix>; - __iter_diff_t<_RandomAccessIterator1> __counters[__traits::__radix_count][__traits::__radix_value_range] = {{0}}; - __iter_diff_t<_RandomAccessIterator1> __maximums[__traits::__radix_count] = {0}; + __iterator_difference_type<_RandomAccessIterator1> + __counters[__traits::__radix_count][__traits::__radix_value_range] = {{0}}; + __iterator_difference_type<_RandomAccessIterator1> __maximums[__traits::__radix_count] = {0}; const auto __is_sorted = std::__collect(__first, __last, __map, __radix, __counters, __maximums); if (!__is_sorted) { const auto __range_size = std::distance(__first, __last); diff --git a/lib/libcxx/include/__algorithm/ranges_copy_n.h b/lib/libcxx/include/__algorithm/ranges_copy_n.h @@ -9,16 +9,12 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_COPY_N_H #define _LIBCPP___ALGORITHM_RANGES_COPY_N_H -#include <__algorithm/copy.h> +#include <__algorithm/copy_n.h> #include <__algorithm/in_out_result.h> #include <__algorithm/iterator_operations.h> -#include <__algorithm/ranges_copy.h> #include <__config> -#include <__functional/identity.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> -#include <__iterator/unreachable_sentinel.h> -#include <__iterator/wrap_iter.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -37,32 +33,13 @@ namespace ranges { template <class _Ip, class _Op> using copy_n_result = in_out_result<_Ip, _Op>; -// TODO: Merge this with copy_n struct __copy_n { - template <class _InIter, class _DiffType, class _OutIter> - _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter> - __go(_InIter __first, _DiffType __n, _OutIter __result) { - while (__n != 0) { - *__result = *__first; - ++__first; - ++__result; - --__n; - } - return {std::move(__first), std::move(__result)}; - } - - template <random_access_iterator _InIter, class _DiffType, random_access_iterator _OutIter> - _LIBCPP_HIDE_FROM_ABI constexpr static copy_n_result<_InIter, _OutIter> - __go(_InIter __first, _DiffType __n, _OutIter __result) { - auto __ret = std::__copy(__first, __first + __n, __result); - return {__ret.first, __ret.second}; - } - template <input_iterator _Ip, weakly_incrementable _Op> requires indirectly_copyable<_Ip, _Op> _LIBCPP_HIDE_FROM_ABI constexpr copy_n_result<_Ip, _Op> operator()(_Ip __first, iter_difference_t<_Ip> __n, _Op __result) const { - return __go(std::move(__first), __n, std::move(__result)); + auto __res = std::__copy_n<_RangeAlgPolicy>(std::move(__first), __n, std::move(__result)); + return {std::move(__res.first), std::move(__res.second)}; } }; diff --git a/lib/libcxx/include/__algorithm/ranges_equal.h b/lib/libcxx/include/__algorithm/ranges_equal.h @@ -13,13 +13,12 @@ #include <__algorithm/unwrap_range.h> #include <__config> #include <__functional/identity.h> -#include <__functional/invoke.h> #include <__functional/ranges_operations.h> #include <__iterator/concepts.h> -#include <__iterator/distance.h> #include <__iterator/indirectly_comparable.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/size.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -51,20 +50,17 @@ struct __equal { _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - if constexpr (sized_sentinel_for<_Sent1, _Iter1> && sized_sentinel_for<_Sent2, _Iter2>) { + static constexpr bool __both_sized = sized_sentinel_for<_Sent1, _Iter1> && sized_sentinel_for<_Sent2, _Iter2>; + if constexpr (__both_sized) { if (__last1 - __first1 != __last2 - __first2) return false; } - auto __unwrapped1 = std::__unwrap_range(std::move(__first1), std::move(__last1)); - auto __unwrapped2 = std::__unwrap_range(std::move(__first2), std::move(__last2)); - return std::__equal_impl( - std::move(__unwrapped1.first), - std::move(__unwrapped1.second), - std::move(__unwrapped2.first), - std::move(__unwrapped2.second), - __pred, - __proj1, - __proj2); + + auto [__ufirst1, __ulast1] = std::__unwrap_range(std::move(__first1), std::move(__last1)); + auto [__ufirst2, __ulast2] = std::__unwrap_range(std::move(__first2), std::move(__last2)); + + return std::__equal_impl<__both_sized>( + std::move(__ufirst1), std::move(__ulast1), std::move(__ufirst2), std::move(__ulast2), __pred, __proj1, __proj2); } template <input_range _Range1, @@ -75,21 +71,16 @@ struct __equal { requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>, _Pred, _Proj1, _Proj2> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool operator()( _Range1&& __range1, _Range2&& __range2, _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - if constexpr (sized_range<_Range1> && sized_range<_Range2>) { - if (ranges::distance(__range1) != ranges::distance(__range2)) + static constexpr bool __both_sized = sized_range<_Range1> && sized_range<_Range2>; + if constexpr (__both_sized) { + if (ranges::size(__range1) != ranges::size(__range2)) return false; } - auto __unwrapped1 = std::__unwrap_range(ranges::begin(__range1), ranges::end(__range1)); - auto __unwrapped2 = std::__unwrap_range(ranges::begin(__range2), ranges::end(__range2)); - return std::__equal_impl( - std::move(__unwrapped1.first), - std::move(__unwrapped1.second), - std::move(__unwrapped2.first), - std::move(__unwrapped2.second), - __pred, - __proj1, - __proj2); - return false; + + auto [__ufirst1, __ulast1] = std::__unwrap_range(ranges::begin(__range1), ranges::end(__range1)); + auto [__ufirst2, __ulast2] = std::__unwrap_range(ranges::begin(__range2), ranges::end(__range2)); + return std::__equal_impl<__both_sized>( + std::move(__ufirst1), std::move(__ulast1), std::move(__ufirst2), std::move(__ulast2), __pred, __proj1, __proj2); } }; diff --git a/lib/libcxx/include/__algorithm/ranges_fill.h b/lib/libcxx/include/__algorithm/ranges_fill.h @@ -9,12 +9,14 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_FILL_H #define _LIBCPP___ALGORITHM_RANGES_FILL_H -#include <__algorithm/ranges_fill_n.h> +#include <__algorithm/fill.h> +#include <__algorithm/fill_n.h> #include <__config> #include <__iterator/concepts.h> #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -31,12 +33,11 @@ namespace ranges { struct __fill { template <class _Type, output_iterator<const _Type&> _Iter, sentinel_for<_Iter> _Sent> _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, const _Type& __value) const { - if constexpr (random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) { - return ranges::fill_n(__first, __last - __first, __value); + if constexpr (sized_sentinel_for<_Sent, _Iter>) { + auto __n = __last - __first; + return std::__fill_n(std::move(__first), __n, __value); } else { - for (; __first != __last; ++__first) - *__first = __value; - return __first; + return std::__fill(std::move(__first), std::move(__last), __value); } } diff --git a/lib/libcxx/include/__algorithm/ranges_for_each.h b/lib/libcxx/include/__algorithm/ranges_for_each.h @@ -12,6 +12,7 @@ #include <__algorithm/for_each.h> #include <__algorithm/for_each_n.h> #include <__algorithm/in_fun_result.h> +#include <__algorithm/specialized_algorithms.h> #include <__concepts/assignable.h> #include <__config> #include <__functional/identity.h> @@ -20,6 +21,7 @@ #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> +#include <__type_traits/remove_cvref.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -71,7 +73,13 @@ public: indirectly_unary_invocable<projected<iterator_t<_Range>, _Proj>> _Func> _LIBCPP_HIDE_FROM_ABI constexpr for_each_result<borrowed_iterator_t<_Range>, _Func> operator()(_Range&& __range, _Func __func, _Proj __proj = {}) const { - return __for_each_impl(ranges::begin(__range), ranges::end(__range), __func, __proj); + using _SpecialAlg = __specialized_algorithm<_Algorithm::__for_each, __single_range<remove_cvref_t<_Range>>>; + if constexpr (_SpecialAlg::__has_algorithm) { + auto [__iter, __func2] = _SpecialAlg()(__range, std::move(__func), std::move(__proj)); + return {std::move(__iter), std::move(__func)}; + } else { + return __for_each_impl(ranges::begin(__range), ranges::end(__range), __func, __proj); + } } }; diff --git a/lib/libcxx/include/__algorithm/ranges_generate_n.h b/lib/libcxx/include/__algorithm/ranges_generate_n.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H #define _LIBCPP___ALGORITHM_RANGES_GENERATE_N_H +#include <__algorithm/generate_n.h> #include <__concepts/constructible.h> #include <__concepts/invocable.h> #include <__config> @@ -38,12 +39,7 @@ struct __generate_n { requires invocable<_Func&> && indirectly_writable<_OutIter, invoke_result_t<_Func&>> _LIBCPP_HIDE_FROM_ABI constexpr _OutIter operator()(_OutIter __first, iter_difference_t<_OutIter> __n, _Func __gen) const { - for (; __n > 0; --__n) { - *__first = __gen(); - ++__first; - } - - return __first; + return std::__generate_n(std::move(__first), __n, __gen); } }; diff --git a/lib/libcxx/include/__algorithm/ranges_search_n.h b/lib/libcxx/include/__algorithm/ranges_search_n.h @@ -54,8 +54,8 @@ struct __search_n { } if constexpr (random_access_iterator<_Iter1>) { - auto __ret = std::__search_n_random_access_impl<_RangeAlgPolicy>( - __first, __last, __count, __value, __pred, __proj, __size); + auto __ret = + std::__search_n_random_access_impl<_RangeAlgPolicy>(__first, __count, __value, __pred, __proj, __size); return {std::move(__ret.first), std::move(__ret.second)}; } } diff --git a/lib/libcxx/include/__algorithm/rotate.h b/lib/libcxx/include/__algorithm/rotate.h @@ -12,16 +12,13 @@ #include <__algorithm/copy.h> #include <__algorithm/copy_backward.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__algorithm/move.h> #include <__algorithm/move_backward.h> #include <__algorithm/swap_ranges.h> #include <__config> -#include <__cstddef/size_t.h> #include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> -#include <__memory/construct_at.h> -#include <__memory/pointer_traits.h> -#include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_trivially_assignable.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -89,46 +86,32 @@ __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIt return __r; } -template <typename _Integral> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Integral __algo_gcd(_Integral __x, _Integral __y) { - do { - _Integral __t = __x % __y; - __x = __y; - __y = __t; - } while (__y); - return __x; -} - -template <class _AlgPolicy, typename _RandomAccessIterator> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _RandomAccessIterator -__rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last) { - typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; - typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; - using _Ops = _IterOps<_AlgPolicy>; - - const difference_type __m1 = __middle - __first; - const difference_type __m2 = _Ops::distance(__middle, __last); - if (__m1 == __m2) { - std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last); - return __middle; - } - const difference_type __g = std::__algo_gcd(__m1, __m2); - for (_RandomAccessIterator __p = __first + __g; __p != __first;) { - value_type __t(_Ops::__iter_move(--__p)); - _RandomAccessIterator __p1 = __p; - _RandomAccessIterator __p2 = __p1 + __m1; - do { - *__p1 = _Ops::__iter_move(__p2); - __p1 = __p2; - const difference_type __d = _Ops::distance(__p2, __last); - if (__m1 < __d) - __p2 += __m1; - else - __p2 = __first + (__m1 - __d); - } while (__p2 != __p); - *__p1 = std::move(__t); +template <class _AlgPolicy, class _Iter, class _Sent> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _Iter +__rotate_random_access(_Iter __first, _Iter __middle, _Sent __sent) { + auto __left = _IterOps<_AlgPolicy>::distance(__first, __middle); + auto __right = _IterOps<_AlgPolicy>::distance(__middle, __sent); + auto __last = __first + __right; + + auto __min_len = std::min(__left, __right); + + while (__min_len > 0) { + if (__left <= __right) { + do { + std::__swap_ranges<_AlgPolicy>(__first, __first + __left, __first + __left); + __first += __left; + __right -= __left; + } while (__left <= __right); + __min_len = __right; + } else { + do { + std::__swap_ranges<_AlgPolicy>(__first + (__left - __right), __first + __left, __first + __left); + __left -= __right; + } while (__left > __right); + __min_len = __left; + } } - return __first + __m2; + return __last; } template <class _AlgPolicy, class _ForwardIterator> @@ -170,7 +153,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator return std::__rotate_left<_AlgPolicy>(__first, __last); if (_IterOps<_AlgPolicy>::next(__middle) == __last) return std::__rotate_right<_AlgPolicy>(__first, __last); - return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last); + return std::__rotate_random_access<_AlgPolicy>(__first, __middle, __last); } return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last); } diff --git a/lib/libcxx/include/__algorithm/search_n.h b/lib/libcxx/include/__algorithm/search_n.h @@ -14,11 +14,7 @@ #include <__algorithm/iterator_operations.h> #include <__config> #include <__functional/identity.h> -#include <__iterator/advance.h> -#include <__iterator/concepts.h> -#include <__iterator/distance.h> #include <__iterator/iterator_traits.h> -#include <__ranges/concepts.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> #include <__type_traits/is_callable.h> @@ -68,44 +64,60 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> __search_ } } -template <class _AlgPolicy, class _Pred, class _Iter, class _Sent, class _SizeT, class _Type, class _Proj, class _DiffT> +// Finds the longest suffix in [__first, __last) where each element satisfies __pred. +template <class _RAIter, class _Pred, class _Proj, class _ValueT> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RAIter +__find_longest_suffix(_RAIter __first, _RAIter __last, const _ValueT& __value, _Pred& __pred, _Proj& __proj) { + while (__first != __last) { + if (!std::__invoke(__pred, std::__invoke(__proj, *--__last), __value)) { + return ++__last; + } + } + return __first; +} + +template <class _AlgPolicy, class _Pred, class _Iter, class _SizeT, class _Type, class _Proj, class _DiffT> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 std::pair<_Iter, _Iter> __search_n_random_access_impl( - _Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size1) { - using difference_type = typename iterator_traits<_Iter>::difference_type; + _Iter __first, _SizeT __count_in, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size) { + auto __last = __first + __size; + auto __count = static_cast<_DiffT>(__count_in); + if (__count == 0) return std::make_pair(__first, __first); - if (__size1 < static_cast<_DiffT>(__count)) { - _IterOps<_AlgPolicy>::__advance_to(__first, __last); - return std::make_pair(__first, __first); - } + if (__size < __count) + return std::make_pair(__last, __last); + + // [__match_start, __match_start + __count) is the subrange which we currently check whether it only contains matching + // elements. This subrange is returned in case all the elements match. + // [__match_start, __matched_until) is the longest subrange where all elements are known to match at any given point + // in time. + // [__matched_until, __match_start + __count) is the subrange where we don't know whether the elements match. + + // This algorithm tries to expand the subrange [__match_start, __matched_until) into a range of sufficient length. + // When we fail to do that because we find a mismatching element, we move it forward to the beginning of the next + // consecutive sequence that is not known not to match. + + const _Iter __try_match_until = __last - __count; + _Iter __match_start = __first; + _Iter __matched_until = __first; - const auto __s = __first + __size1 - difference_type(__count - 1); // Start of pattern match can't go beyond here while (true) { - // Find first element in sequence that matchs __value, with a mininum of loop checks - while (true) { - if (__first >= __s) { // return __last if no element matches __value - _IterOps<_AlgPolicy>::__advance_to(__first, __last); - return std::make_pair(__first, __first); - } - if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value)) - break; - ++__first; - } - // *__first matches __value_, now match elements after here - auto __m = __first; - _SizeT __c(0); - while (true) { - if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern) - return std::make_pair(__first, __first + _DiffT(__count)); - ++__m; // no need to check range on __m because __s guarantees we have enough source + // There's no chance of expanding the subrange into a sequence of sufficient length, since we don't have enough + // elements in the haystack anymore. + if (__match_start > __try_match_until) + return std::make_pair(__last, __last); - // if there is a mismatch, restart with a new __first - if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) { - __first = __m; - ++__first; - break; - } // else there is a match, check next elements - } + auto __mismatch = std::__find_longest_suffix(__matched_until, __match_start + __count, __value, __pred, __proj); + + // If all elements in [__matched_until, __match_start + __count) match, we know that + // [__match_start, __match_start + __count) is a full sequence of matching elements, so we're done. + if (__mismatch == __matched_until) + return std::make_pair(__match_start, __match_start + __count); + + // Otherwise, we have to move the [__match_start, __matched_until) subrange forward past the point where we know for + // sure a match is impossible. + __matched_until = __match_start + __count; + __match_start = __mismatch; } } @@ -119,7 +131,7 @@ template <class _Iter, _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> __search_n_impl(_Iter __first, _Sent __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { return std::__search_n_random_access_impl<_ClassicAlgPolicy>( - __first, __last, __count, __value, __pred, __proj, __last - __first); + __first, __count, __value, __pred, __proj, __last - __first); } template <class _Iter1, diff --git a/lib/libcxx/include/__algorithm/sift_down.h b/lib/libcxx/include/__algorithm/sift_down.h @@ -24,59 +24,60 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <class _AlgPolicy, class _Compare, class _RandomAccessIterator> +template <class _AlgPolicy, bool __assume_both_children, class _Compare, class _RandomAccessIterator> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __sift_down(_RandomAccessIterator __first, _Compare&& __comp, - typename iterator_traits<_RandomAccessIterator>::difference_type __len, - _RandomAccessIterator __start) { + __iterator_difference_type<_RandomAccessIterator> __len, + __iterator_difference_type<_RandomAccessIterator> __start) { using _Ops = _IterOps<_AlgPolicy>; typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type; // left-child of __start is at 2 * __start + 1 // right-child of __start is at 2 * __start + 2 - difference_type __child = __start - __first; + difference_type __child = __start; if (__len < 2 || (__len - 2) / 2 < __child) return; - __child = 2 * __child + 1; - _RandomAccessIterator __child_i = __first + __child; + __child = 2 * __child + 1; - if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) { + if _LIBCPP_CONSTEXPR (__assume_both_children) { + // right-child exists and is greater than left-child + __child += __comp(__first[__child], __first[__child + 1]); + } else if ((__child + 1) < __len && __comp(__first[__child], __first[__child + 1])) { // right-child exists and is greater than left-child - ++__child_i; ++__child; } // check if we are in heap-order - if (__comp(*__child_i, *__start)) + if (__comp(__first[__child], __first[__start])) // we are, __start is larger than its largest child return; - value_type __top(_Ops::__iter_move(__start)); + value_type __top(_Ops::__iter_move(__first + __start)); do { // we are not in heap-order, swap the parent with its largest child - *__start = _Ops::__iter_move(__child_i); - __start = __child_i; + __first[__start] = _Ops::__iter_move(__first + __child); + __start = __child; if ((__len - 2) / 2 < __child) break; // recompute the child based off of the updated parent - __child = 2 * __child + 1; - __child_i = __first + __child; + __child = 2 * __child + 1; - if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) { + if _LIBCPP_CONSTEXPR (__assume_both_children) { + __child += __comp(__first[__child], __first[__child + 1]); + } else if ((__child + 1) < __len && __comp(__first[__child], __first[__child + 1])) { // right-child exists and is greater than left-child - ++__child_i; ++__child; } // check if we are in heap-order - } while (!__comp(*__child_i, __top)); - *__start = std::move(__top); + } while (!__comp(__first[__child], __top)); + __first[__start] = std::move(__top); } template <class _AlgPolicy, class _Compare, class _RandomAccessIterator> diff --git a/lib/libcxx/include/__algorithm/simd_utils.h b/lib/libcxx/include/__algorithm/simd_utils.h @@ -26,9 +26,7 @@ _LIBCPP_PUSH_MACROS #include <__undef_macros> // TODO: Find out how altivec changes things and allow vectorizations there too. -// TODO: Simplify this condition once we stop building with AppleClang 15 in the CI. -#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(__ALTIVEC__) && \ - !(defined(_LIBCPP_APPLE_CLANG_VER) && _LIBCPP_APPLE_CLANG_VER < 1600) +#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(__ALTIVEC__) # define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1 #else # define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0 @@ -116,16 +114,47 @@ template <class _VecT, class _Iter> }(make_index_sequence<__simd_vector_size_v<_VecT>>{}); } +// Load the first _Np elements, zero the rest +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") +template <class _VecT, size_t _Np, class _Iter> +[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT __partial_load(_Iter __iter) noexcept { + return [=]<size_t... _LoadIndices, size_t... _ZeroIndices>( + index_sequence<_LoadIndices...>, index_sequence<_ZeroIndices...>) _LIBCPP_ALWAYS_INLINE noexcept { + return _VecT{__iter[_LoadIndices]..., ((void)_ZeroIndices, 0)...}; + }(make_index_sequence<_Np>{}, make_index_sequence<__simd_vector_size_v<_VecT> - _Np>{}); +} + +// Create a vector where every elements is __val +template <class _VecT> +[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT +__broadcast(__simd_vector_underlying_type_t<_VecT> __val) { + return [&]<std::size_t... _Indices>(index_sequence<_Indices...>) { + return _VecT{((void)_Indices, __val)...}; + }(make_index_sequence<__simd_vector_size_v<_VecT>>()); +} +_LIBCPP_DIAGNOSTIC_POP + +template <class _Tp, size_t _Np> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __any_of(__simd_vector<_Tp, _Np> __vec) noexcept { + return __builtin_reduce_or(__builtin_convertvector(__vec, __simd_vector<bool, _Np>)); +} + template <class _Tp, size_t _Np> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __all_of(__simd_vector<_Tp, _Np> __vec) noexcept { return __builtin_reduce_and(__builtin_convertvector(__vec, __simd_vector<bool, _Np>)); } template <class _Tp, size_t _Np> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool __none_of(__simd_vector<_Tp, _Np> __vec) noexcept { + return !__builtin_reduce_or(__builtin_convertvector(__vec, __simd_vector<bool, _Np>)); +} + +template <class _Tp, size_t _Np> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t __find_first_set(__simd_vector<_Tp, _Np> __vec) noexcept { using __mask_vec = __simd_vector<bool, _Np>; - // This has MSan disabled du to https://github.com/llvm/llvm-project/issues/85876 + // This has MSan disabled du to https://llvm.org/PR85876 auto __impl = [&]<class _MaskT>(_MaskT) _LIBCPP_NO_SANITIZE("memory") noexcept { # if defined(_LIBCPP_BIG_ENDIAN) return std::min<size_t>( diff --git a/lib/libcxx/include/__algorithm/specialized_algorithms.h b/lib/libcxx/include/__algorithm/specialized_algorithms.h @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___ALGORITHM_SPECIALIZED_ALGORITHMS_H +#define _LIBCPP___ALGORITHM_SPECIALIZED_ALGORITHMS_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace _Algorithm { +struct __copy {}; +struct __fill_n {}; +struct __for_each {}; +} // namespace _Algorithm + +template <class> +struct __single_iterator; + +template <class, class> +struct __iterator_pair; + +template <class> +struct __single_range; + +// This struct allows specializing algorithms for specific arguments. This is useful when we know a more efficient +// algorithm implementation for e.g. library-defined iterators. _Alg is one of tags defined inside the _Algorithm +// namespace above. _Ranges is an essentially arbitrary subset of the arguments to the algorithm that are used for +// dispatching. This set is specific to the algorithm: look at each algorithm to see which arguments they use for +// dispatching to specialized algorithms. +// +// A specialization of `__specialized_algorithm` has to define `__has_algorithm` to true for the specialized algorithm +// to be used. This is intended for cases where iterators can do generic unwrapping and forward to a different +// specialization of `__specialized_algorithm`. +// +// If __has_algorithm is true, there has to be an operator() which will get called with the actual arguments to the +// algorithm. +template <class _Alg, class... _Ranges> +struct __specialized_algorithm { + static const bool __has_algorithm = false; +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_SPECIALIZED_ALGORITHMS_H diff --git a/lib/libcxx/include/__algorithm/stable_sort.h b/lib/libcxx/include/__algorithm/stable_sort.h @@ -247,7 +247,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void __stable_sort( constexpr auto __default_comp = __desugars_to_v<__less_tag, _Compare, value_type, value_type >; constexpr auto __radix_sortable = __is_ordered_integer_representable_v<value_type> && - is_same_v< value_type&, __iter_reference<_RandomAccessIterator>>; + is_same_v< value_type&, __iterator_reference<_RandomAccessIterator>>; if constexpr (__default_comp && __radix_sortable) { if (__len <= __buff_size && __len >= static_cast<difference_type>(std::__radix_sort_min_bound<value_type>()) && __len <= static_cast<difference_type>(std::__radix_sort_max_bound<value_type>())) { diff --git a/lib/libcxx/include/__assertion_handler b/lib/libcxx/include/__assertion_handler @@ -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 diff --git a/lib/libcxx/include/__atomic/atomic.h b/lib/libcxx/include/__atomic/atomic.h @@ -10,7 +10,9 @@ #define _LIBCPP___ATOMIC_ATOMIC_H #include <__atomic/atomic_sync.h> +#include <__atomic/atomic_waitable_traits.h> #include <__atomic/check_memory_order.h> +#include <__atomic/floating_point_helper.h> #include <__atomic/is_always_lock_free.h> #include <__atomic/memory_order.h> #include <__atomic/support.h> @@ -47,10 +49,10 @@ struct __atomic_base // false static constexpr bool is_always_lock_free = __libcpp_is_always_lock_free<__cxx_atomic_impl<_Tp> >::__value; #endif - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const volatile _NOEXCEPT { return __cxx_atomic_is_lock_free(sizeof(__cxx_atomic_impl<_Tp>)); } - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const _NOEXCEPT { return static_cast<__atomic_base const volatile*>(this)->is_lock_free(); } _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order __m = memory_order_seq_cst) volatile _NOEXCEPT @@ -61,11 +63,11 @@ struct __atomic_base // false _LIBCPP_CHECK_STORE_MEMORY_ORDER(__m) { std::__cxx_atomic_store(std::addressof(__a_), __d, __m); } - _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return std::__cxx_atomic_load(std::addressof(__a_), __m); } - _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __m = memory_order_seq_cst) const _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return std::__cxx_atomic_load(std::addressof(__a_), __m); } @@ -113,22 +115,16 @@ struct __atomic_base // false } #if _LIBCPP_STD_VER >= 20 - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const - volatile _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT { std::__atomic_wait(*this, __v, __m); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void - wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI void wait(_Tp __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { std::__atomic_wait(*this, __v, __m); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { - std::__atomic_notify_one(*this); - } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { - std::__atomic_notify_all(*this); - } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { std::__atomic_notify_all(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); } #endif // _LIBCPP_STD_VER >= 20 #if _LIBCPP_STD_VER >= 20 @@ -205,12 +201,15 @@ struct __atomic_base<_Tp, true> : public __atomic_base<_Tp, false> { _LIBCPP_HIDE_FROM_ABI _Tp operator^=(_Tp __op) _NOEXCEPT { return fetch_xor(__op) ^ __op; } }; +#if _LIBCPP_STD_VER >= 20 // Here we need _IsIntegral because the default template argument is not enough // e.g __atomic_base<int> is __atomic_base<int, true>, which inherits from // __atomic_base<int, false> and the caller of the wait function is // __atomic_base<int, false>. So specializing __atomic_base<_Tp> does not work template <class _Tp, bool _IsIntegral> struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > { + using __value_type _LIBCPP_NODEBUG = _Tp; + static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_base<_Tp, _IsIntegral>& __a, memory_order __order) { return __a.load(__order); } @@ -231,6 +230,8 @@ struct __atomic_waitable_traits<__atomic_base<_Tp, _IsIntegral> > { } }; +#endif // _LIBCPP_STD_VER >= 20 + template <typename _Tp> struct __check_atomic_mandates { using type _LIBCPP_NODEBUG = _Tp; @@ -324,50 +325,26 @@ struct atomic<_Tp*> : public __atomic_base<_Tp*> { atomic& operator=(const atomic&) volatile = delete; }; +#if _LIBCPP_STD_VER >= 20 template <class _Tp> struct __atomic_waitable_traits<atomic<_Tp> > : __atomic_waitable_traits<__atomic_base<_Tp> > {}; -#if _LIBCPP_STD_VER >= 20 template <class _Tp> requires is_floating_point_v<_Tp> struct atomic<_Tp> : __atomic_base<_Tp> { private: - _LIBCPP_HIDE_FROM_ABI static constexpr bool __is_fp80_long_double() { - // Only x87-fp80 long double has 64-bit mantissa - return __LDBL_MANT_DIG__ == 64 && std::is_same_v<_Tp, long double>; - } - - _LIBCPP_HIDE_FROM_ABI static constexpr bool __has_rmw_builtin() { -# ifndef _LIBCPP_COMPILER_CLANG_BASED - return false; -# else - // The builtin __cxx_atomic_fetch_add errors during compilation for - // long double on platforms with fp80 format. - // For more details, see - // lib/Sema/SemaChecking.cpp function IsAllowedValueType - // LLVM Parser does not allow atomicrmw with x86_fp80 type. - // if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && - // &Context.getTargetInfo().getLongDoubleFormat() == - // &llvm::APFloat::x87DoubleExtended()) - // For more info - // https://github.com/llvm/llvm-project/issues/68602 - // https://reviews.llvm.org/D53965 - return !__is_fp80_long_double(); -# endif - } - template <class _This, class _Operation, class _BuiltinOp> _LIBCPP_HIDE_FROM_ABI static _Tp __rmw_op(_This&& __self, _Tp __operand, memory_order __m, _Operation __operation, _BuiltinOp __builtin_op) { - if constexpr (__has_rmw_builtin()) { + if constexpr (std::__has_rmw_builtin<_Tp>()) { return __builtin_op(std::addressof(std::forward<_This>(__self).__a_), __operand, __m); } else { _Tp __old = __self.load(memory_order_relaxed); _Tp __new = __operation(__old, __operand); while (!__self.compare_exchange_weak(__old, __new, __m, memory_order_relaxed)) { # ifdef _LIBCPP_COMPILER_CLANG_BASED - if constexpr (__is_fp80_long_double()) { - // https://github.com/llvm/llvm-project/issues/47978 + if constexpr (std::__is_fp80_long_double<_Tp>()) { + // https://llvm.org/PR47978 // clang bug: __old is not updated on failure for atomic<long double>::compare_exchange_weak // Note __old = __self.load(memory_order_relaxed) will not work std::__cxx_atomic_load_inplace(std::addressof(__self.__a_), std::addressof(__old), memory_order_relaxed); @@ -462,12 +439,12 @@ public: // atomic_is_lock_free template <class _Tp> -_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const volatile atomic<_Tp>* __o) _NOEXCEPT { return __o->is_lock_free(); } template <class _Tp> -_LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const atomic<_Tp>* __o) _NOEXCEPT { return __o->is_lock_free(); } @@ -516,25 +493,25 @@ atomic_store_explicit(atomic<_Tp>* __o, typename atomic<_Tp>::value_type __d, me // atomic_load template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const volatile atomic<_Tp>* __o) _NOEXCEPT { return __o->load(); } template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load(const atomic<_Tp>* __o) _NOEXCEPT { return __o->load(); } // atomic_load_explicit template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT - _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp +atomic_load_explicit(const volatile atomic<_Tp>* __o, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return __o->load(__m); } template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp atomic_load_explicit(const atomic<_Tp>* __o, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return __o->load(__m); } @@ -642,28 +619,27 @@ _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit( // atomic_wait template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI void atomic_wait(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) _NOEXCEPT { return __o->wait(__v); } template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void -atomic_wait(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_wait(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v) _NOEXCEPT { return __o->wait(__v); } // atomic_wait_explicit template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI void atomic_wait_explicit(const volatile atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return __o->wait(__v, __m); } template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void +_LIBCPP_HIDE_FROM_ABI void atomic_wait_explicit(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __v, memory_order __m) _NOEXCEPT _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__m) { return __o->wait(__v, __m); @@ -672,22 +648,22 @@ atomic_wait_explicit(const atomic<_Tp>* __o, typename atomic<_Tp>::value_type __ // atomic_notify_one template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void atomic_notify_one(volatile atomic<_Tp>* __o) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_notify_one(volatile atomic<_Tp>* __o) _NOEXCEPT { __o->notify_one(); } template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void atomic_notify_one(atomic<_Tp>* __o) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_notify_one(atomic<_Tp>* __o) _NOEXCEPT { __o->notify_one(); } // atomic_notify_all template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void atomic_notify_all(volatile atomic<_Tp>* __o) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_notify_all(volatile atomic<_Tp>* __o) _NOEXCEPT { __o->notify_all(); } template <class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void atomic_notify_all(atomic<_Tp>* __o) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI void atomic_notify_all(atomic<_Tp>* __o) _NOEXCEPT { __o->notify_all(); } diff --git a/lib/libcxx/include/__atomic/atomic_flag.h b/lib/libcxx/include/__atomic/atomic_flag.h @@ -10,6 +10,7 @@ #define _LIBCPP___ATOMIC_ATOMIC_FLAG_H #include <__atomic/atomic_sync.h> +#include <__atomic/atomic_waitable_traits.h> #include <__atomic/contention_t.h> #include <__atomic/memory_order.h> #include <__atomic/support.h> @@ -49,22 +50,16 @@ struct atomic_flag { } #if _LIBCPP_STD_VER >= 20 - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(bool __v, memory_order __m = memory_order_seq_cst) const - volatile _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI void wait(bool __v, memory_order __m = memory_order_seq_cst) const volatile _NOEXCEPT { std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void - wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI void wait(bool __v, memory_order __m = memory_order_seq_cst) const _NOEXCEPT { std::__atomic_wait(*this, _LIBCPP_ATOMIC_FLAG_TYPE(__v), __m); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { - std::__atomic_notify_one(*this); - } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { - std::__atomic_notify_all(*this); - } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_one() volatile _NOEXCEPT { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_one() _NOEXCEPT { std::__atomic_notify_one(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() volatile _NOEXCEPT { std::__atomic_notify_all(*this); } + _LIBCPP_HIDE_FROM_ABI void notify_all() _NOEXCEPT { std::__atomic_notify_all(*this); } #endif #if _LIBCPP_STD_VER >= 20 @@ -80,8 +75,11 @@ struct atomic_flag { atomic_flag& operator=(const atomic_flag&) volatile = delete; }; +#if _LIBCPP_STD_VER >= 20 template <> struct __atomic_waitable_traits<atomic_flag> { + using __value_type _LIBCPP_NODEBUG = _LIBCPP_ATOMIC_FLAG_TYPE; + static _LIBCPP_HIDE_FROM_ABI _LIBCPP_ATOMIC_FLAG_TYPE __atomic_load(const atomic_flag& __a, memory_order __order) { return std::__cxx_atomic_load(&__a.__a_, __order); } @@ -101,6 +99,7 @@ struct __atomic_waitable_traits<atomic_flag> { return std::addressof(__a.__a_); } }; +#endif // _LIBCPP_STD_VER >= 20 inline _LIBCPP_HIDE_FROM_ABI bool atomic_flag_test(const volatile atomic_flag* __o) _NOEXCEPT { return __o->test(); } @@ -143,43 +142,26 @@ inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_clear_explicit(atomic_flag* __o, m } #if _LIBCPP_STD_VER >= 20 -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void -atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT { +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_wait(const volatile atomic_flag* __o, bool __v) _NOEXCEPT { __o->wait(__v); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void -atomic_flag_wait(const atomic_flag* __o, bool __v) _NOEXCEPT { - __o->wait(__v); -} +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_wait(const atomic_flag* __o, bool __v) _NOEXCEPT { __o->wait(__v); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_wait_explicit(const volatile atomic_flag* __o, bool __v, memory_order __m) _NOEXCEPT { __o->wait(__v, __m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_wait_explicit(const atomic_flag* __o, bool __v, memory_order __m) _NOEXCEPT { __o->wait(__v, __m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void -atomic_flag_notify_one(volatile atomic_flag* __o) _NOEXCEPT { - __o->notify_one(); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void atomic_flag_notify_one(atomic_flag* __o) _NOEXCEPT { - __o->notify_one(); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void -atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT { - __o->notify_all(); -} - -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_SYNC void atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT { - __o->notify_all(); -} +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_notify_one(volatile atomic_flag* __o) _NOEXCEPT { __o->notify_one(); } +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_notify_one(atomic_flag* __o) _NOEXCEPT { __o->notify_one(); } +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_notify_all(volatile atomic_flag* __o) _NOEXCEPT { __o->notify_all(); } +inline _LIBCPP_HIDE_FROM_ABI void atomic_flag_notify_all(atomic_flag* __o) _NOEXCEPT { __o->notify_all(); } #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__atomic/atomic_ref.h b/lib/libcxx/include/__atomic/atomic_ref.h @@ -19,7 +19,9 @@ #include <__assert> #include <__atomic/atomic_sync.h> +#include <__atomic/atomic_waitable_traits.h> #include <__atomic/check_memory_order.h> +#include <__atomic/floating_point_helper.h> #include <__atomic/memory_order.h> #include <__atomic/to_gcc_order.h> #include <__concepts/arithmetic.h> @@ -121,7 +123,9 @@ public: static constexpr bool is_always_lock_free = __atomic_always_lock_free(sizeof(_Tp), std::addressof(__get_aligner_instance<required_alignment>::__instance)); - _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return __atomic_is_lock_free(sizeof(_Tp), __ptr_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { + return __atomic_is_lock_free(sizeof(_Tp), __ptr_); + } _LIBCPP_HIDE_FROM_ABI void store(_Tp __desired, memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_STORE_MEMORY_ORDER(__order) { @@ -136,7 +140,7 @@ public: return __desired; } - _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order __order = memory_order::seq_cst) const noexcept _LIBCPP_CHECK_LOAD_MEMORY_ORDER(__order) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __order == memory_order::relaxed || __order == memory_order::consume || __order == memory_order::acquire || @@ -219,6 +223,9 @@ public: } _LIBCPP_HIDE_FROM_ABI void notify_one() const noexcept { std::__atomic_notify_one(*this); } _LIBCPP_HIDE_FROM_ABI void notify_all() const noexcept { std::__atomic_notify_all(*this); } +# if _LIBCPP_STD_VER >= 26 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* address() const noexcept { return __ptr_; } +# endif protected: using _Aligned_Tp [[__gnu__::__aligned__(required_alignment), __gnu__::__nodebug__]] = _Tp; @@ -229,6 +236,8 @@ protected: template <class _Tp> struct __atomic_waitable_traits<__atomic_ref_base<_Tp>> { + using __value_type _LIBCPP_NODEBUG = _Tp; + static _LIBCPP_HIDE_FROM_ABI _Tp __atomic_load(const __atomic_ref_base<_Tp>& __a, memory_order __order) { return __a.load(__order); } @@ -322,20 +331,28 @@ struct atomic_ref<_Tp> : public __atomic_ref_base<_Tp> { atomic_ref& operator=(const atomic_ref&) = delete; _LIBCPP_HIDE_FROM_ABI _Tp fetch_add(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - _Tp __old = this->load(memory_order_relaxed); - _Tp __new = __old + __arg; - while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { - __new = __old + __arg; + if constexpr (std::__has_rmw_builtin<_Tp>()) { + return __atomic_fetch_add(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } else { + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old + __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old + __arg; + } + return __old; } - return __old; } _LIBCPP_HIDE_FROM_ABI _Tp fetch_sub(_Tp __arg, memory_order __order = memory_order_seq_cst) const noexcept { - _Tp __old = this->load(memory_order_relaxed); - _Tp __new = __old - __arg; - while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { - __new = __old - __arg; + if constexpr (std::__has_rmw_builtin<_Tp>()) { + return __atomic_fetch_sub(this->__ptr_, __arg, std::__to_gcc_order(__order)); + } else { + _Tp __old = this->load(memory_order_relaxed); + _Tp __new = __old - __arg; + while (!this->compare_exchange_weak(__old, __new, __order, memory_order_relaxed)) { + __new = __old - __arg; + } + return __old; } - return __old; } _LIBCPP_HIDE_FROM_ABI _Tp operator+=(_Tp __arg) const noexcept { return fetch_add(__arg) + __arg; } diff --git a/lib/libcxx/include/__atomic/atomic_sync.h b/lib/libcxx/include/__atomic/atomic_sync.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___ATOMIC_ATOMIC_SYNC_H #define _LIBCPP___ATOMIC_ATOMIC_SYNC_H +#include <__atomic/atomic_waitable_traits.h> #include <__atomic/contention_t.h> #include <__atomic/memory_order.h> #include <__atomic/to_gcc_order.h> @@ -19,6 +20,7 @@ #include <__type_traits/conjunction.h> #include <__type_traits/decay.h> #include <__type_traits/invoke.h> +#include <__type_traits/is_same.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> #include <cstring> @@ -29,50 +31,89 @@ _LIBCPP_BEGIN_NAMESPACE_STD -// The customisation points to enable the following functions: -// - __atomic_wait -// - __atomic_wait_unless -// - __atomic_notify_one -// - __atomic_notify_all -// Note that std::atomic<T>::wait was back-ported to C++03 -// The below implementations look ugly to support C++03 -template <class _Tp, class = void> -struct __atomic_waitable_traits { - template <class _AtomicWaitable> - static void __atomic_load(_AtomicWaitable&&, memory_order) = delete; - - template <class _AtomicWaitable> - static void __atomic_contention_address(_AtomicWaitable&&) = delete; -}; - -template <class _Tp, class = void> -struct __atomic_waitable : false_type {}; - -template <class _Tp> -struct __atomic_waitable< _Tp, - __void_t<decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load( - std::declval<const _Tp&>(), std::declval<memory_order>())), - decltype(__atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address( - std::declval<const _Tp&>()))> > : true_type {}; - #if _LIBCPP_STD_VER >= 20 # if _LIBCPP_HAS_THREADS -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t -__libcpp_atomic_monitor(void const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void -__libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT; - -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void -__cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void -__cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t +# if !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +// old dylib interface kept for backwards compatibility +_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile*) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile*) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile*) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(void const volatile*, __cxx_contention_t) _NOEXCEPT; + +_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; +_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile*) _NOEXCEPT; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void +_LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile*, __cxx_contention_t) _NOEXCEPT; +# endif // !_LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +// new dylib interface + +// return the global contention state's current value for the address +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t +__atomic_monitor_global(void const* __address) _NOEXCEPT; + +// wait on the global contention state to be changed from the given value for the address +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_global_table(void const* __address, __cxx_contention_t __monitor_value) _NOEXCEPT; + +// notify one waiter waiting on the global contention state for the address +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_global_table(void const*) _NOEXCEPT; + +// notify all waiters waiting on the global contention state for the address +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_global_table(void const*) _NOEXCEPT; + +// wait on the address directly with the native platform wait +template <std::size_t _Size> +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_native(void const* __address, void const* __old_value) _NOEXCEPT; + +// notify one waiter waiting on the address directly with the native platform wait +template <std::size_t _Size> +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native(const void*) _NOEXCEPT; + +// notify all waiters waiting on the address directly with the native platform wait +template <std::size_t _Size> +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native(const void*) _NOEXCEPT; + +# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +template <class _AtomicWaitable, class _Poll> +struct __atomic_wait_backoff_impl { + const _AtomicWaitable& __a_; + _Poll __poll_; + memory_order __order_; + + using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; + using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type; + + _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const { + if (__elapsed > chrono::microseconds(4)) { + auto __contention_address = const_cast<const void*>( + static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a_))); + + if constexpr (__has_native_atomic_wait<__value_type>) { + auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); + if (__poll_(__atomic_value)) + return __backoff_results::__poll_success; + std::__atomic_wait_native<sizeof(__value_type)>(__contention_address, std::addressof(__atomic_value)); + } else { + __cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address); + auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); + if (__poll_(__atomic_value)) + return __backoff_results::__poll_success; + std::__atomic_wait_global_table(__contention_address, __monitor_val); + } + } else { + } // poll + return __backoff_results::__continue_poll; + } +}; + +# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC template <class _AtomicWaitable, class _Poll> struct __atomic_wait_backoff_impl { @@ -82,7 +123,6 @@ struct __atomic_wait_backoff_impl { using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __update_monitor_val_and_poll(__cxx_atomic_contention_t const volatile*, __cxx_contention_t& __monitor_val) const { // In case the contention type happens to be __cxx_atomic_contention_t, i.e. __cxx_atomic_impl<int64_t>, @@ -95,7 +135,6 @@ struct __atomic_wait_backoff_impl { return __poll_(__monitor_val); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __update_monitor_val_and_poll(void const volatile* __contention_address, __cxx_contention_t& __monitor_val) const { // In case the contention type is anything else, platform wait is monitoring a __cxx_atomic_contention_t @@ -105,20 +144,21 @@ struct __atomic_wait_backoff_impl { return __poll_(__current_val); } - _LIBCPP_AVAILABILITY_SYNC - _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const { + _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const { if (__elapsed > chrono::microseconds(4)) { auto __contention_address = __waitable_traits::__atomic_contention_address(__a_); __cxx_contention_t __monitor_val; if (__update_monitor_val_and_poll(__contention_address, __monitor_val)) - return true; + return __backoff_results::__poll_success; std::__libcpp_atomic_wait(__contention_address, __monitor_val); } else { } // poll - return false; + return __backoff_results::__continue_poll; } }; +# endif // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + // The semantics of this function are similar to `atomic`'s // `.wait(T old, std::memory_order order)`, but instead of having a hardcoded // predicate (is the loaded value unequal to `old`?), the predicate function is @@ -128,9 +168,8 @@ struct __atomic_wait_backoff_impl { // `false`, it must set the argument to its current understanding of the atomic // value. The predicate function must not return `false` spuriously. template <class _AtomicWaitable, class _Poll> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void -__atomic_wait_unless(const _AtomicWaitable& __a, memory_order __order, _Poll&& __poll) { - static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); +_LIBCPP_HIDE_FROM_ABI void __atomic_wait_unless(const _AtomicWaitable& __a, memory_order __order, _Poll&& __poll) { + static_assert(__atomic_waitable<_AtomicWaitable>); __atomic_wait_backoff_impl<_AtomicWaitable, __decay_t<_Poll> > __backoff_fn = {__a, __poll, __order}; std::__libcpp_thread_poll_with_backoff( /* poll */ @@ -141,18 +180,52 @@ __atomic_wait_unless(const _AtomicWaitable& __a, memory_order __order, _Poll&& _ /* backoff */ __backoff_fn); } +# if _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + template <class _AtomicWaitable> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { - static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>); + using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type; + using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; + auto __contention_address = + const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a))); + if constexpr (__has_native_atomic_wait<__value_type>) { + std::__atomic_notify_one_native<sizeof(__value_type)>(__contention_address); + } else { + std::__atomic_notify_one_global_table(__contention_address); + } +} + +template <class _AtomicWaitable> +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>); + using __value_type _LIBCPP_NODEBUG = typename __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__value_type; + using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; + auto __contention_address = + const_cast<const void*>(static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a))); + if constexpr (__has_native_atomic_wait<__value_type>) { + std::__atomic_notify_all_native<sizeof(__value_type)>(__contention_address); + } else { + std::__atomic_notify_all_global_table(__contention_address); + } +} + +# else // _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +template <class _AtomicWaitable> +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_one(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>); std::__cxx_atomic_notify_one(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); } template <class _AtomicWaitable> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { - static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); +_LIBCPP_HIDE_FROM_ABI void __atomic_notify_all(const _AtomicWaitable& __a) { + static_assert(__atomic_waitable<_AtomicWaitable>); std::__cxx_atomic_notify_all(__atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_contention_address(__a)); } +# endif + # else // _LIBCPP_HAS_THREADS template <class _AtomicWaitable, class _Poll> @@ -180,9 +253,8 @@ _LIBCPP_HIDE_FROM_ABI bool __cxx_nonatomic_compare_equal(_Tp const& __lhs, _Tp c } template <class _AtomicWaitable, class _Tp> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void -__atomic_wait(_AtomicWaitable& __a, _Tp __val, memory_order __order) { - static_assert(__atomic_waitable<_AtomicWaitable>::value, ""); +_LIBCPP_HIDE_FROM_ABI void __atomic_wait(_AtomicWaitable& __a, _Tp __val, memory_order __order) { + static_assert(__atomic_waitable<_AtomicWaitable>); std::__atomic_wait_unless(__a, __order, [&](_Tp const& __current) { return !std::__cxx_nonatomic_compare_equal(__current, __val); }); diff --git a/lib/libcxx/include/__atomic/atomic_sync_timed.h b/lib/libcxx/include/__atomic/atomic_sync_timed.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_ATOMIC_SYNC_TIMED_H +#define _LIBCPP___ATOMIC_ATOMIC_SYNC_TIMED_H + +#include <__atomic/atomic_waitable_traits.h> +#include <__atomic/contention_t.h> +#include <__atomic/memory_order.h> +#include <__atomic/to_gcc_order.h> +#include <__chrono/duration.h> +#include <__config> +#include <__memory/addressof.h> +#include <__thread/poll_with_backoff.h> +#include <__thread/timed_backoff_policy.h> +#include <__type_traits/conjunction.h> +#include <__type_traits/decay.h> +#include <__type_traits/has_unique_object_representation.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include <cstdint> +#include <cstring> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 +# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +_LIBCPP_AVAILABILITY_NEW_SYNC +_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __atomic_monitor_global(void const* __address) _NOEXCEPT; + +// wait on the global contention state to be changed from the given value for the address +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_global_table_with_timeout( + void const* __address, __cxx_contention_t __monitor_value, uint64_t __timeout_ns) _NOEXCEPT; + +// wait on the address directly with the native platform wait +template <std::size_t _Size> +_LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_native_with_timeout(void const* __address, void const* __old_value, uint64_t __timeout_ns) _NOEXCEPT; + +template <class _AtomicWaitable, class _Poll, class _Rep, class _Period> +struct __atomic_wait_timed_backoff_impl { + const _AtomicWaitable& __a_; + _Poll __poll_; + memory_order __order_; + chrono::duration<_Rep, _Period> __rel_time_; + + using __waitable_traits _LIBCPP_NODEBUG = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >; + using __value_type _LIBCPP_NODEBUG = typename __waitable_traits::__value_type; + + _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const { + if (__elapsed > chrono::microseconds(4)) { + auto __contention_address = const_cast<const void*>( + static_cast<const volatile void*>(__waitable_traits::__atomic_contention_address(__a_))); + + uint64_t __timeout_ns = + static_cast<uint64_t>((chrono::duration_cast<chrono::nanoseconds>(__rel_time_) - __elapsed).count()); + + if constexpr (__has_native_atomic_wait<__value_type>) { + auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); + if (__poll_(__atomic_value)) + return __backoff_results::__poll_success; + std::__atomic_wait_native_with_timeout<sizeof(__value_type)>( + __contention_address, std::addressof(__atomic_value), __timeout_ns); + } else { + __cxx_contention_t __monitor_val = std::__atomic_monitor_global(__contention_address); + auto __atomic_value = __waitable_traits::__atomic_load(__a_, __order_); + if (__poll_(__atomic_value)) + return __backoff_results::__poll_success; + std::__atomic_wait_global_table_with_timeout(__contention_address, __monitor_val, __timeout_ns); + } + } else { + } // poll + return __backoff_results::__continue_poll; + } +}; + +// The semantics of this function are similar to `atomic`'s +// `.wait(T old, std::memory_order order)` with a timeout, but instead of having a hardcoded +// predicate (is the loaded value unequal to `old`?), the predicate function is +// specified as an argument. The loaded value is given as an in-out argument to +// the predicate. If the predicate function returns `true`, +// `__atomic_wait_unless_with_timeout` will return. If the predicate function returns +// `false`, it must set the argument to its current understanding of the atomic +// value. The predicate function must not return `false` spuriously. +template <class _AtomicWaitable, class _Poll, class _Rep, class _Period> +_LIBCPP_HIDE_FROM_ABI bool __atomic_wait_unless_with_timeout( + const _AtomicWaitable& __a, + memory_order __order, + _Poll&& __poll, + chrono::duration<_Rep, _Period> const& __rel_time) { + static_assert(__atomic_waitable<_AtomicWaitable>, ""); + __atomic_wait_timed_backoff_impl<_AtomicWaitable, __decay_t<_Poll>, _Rep, _Period> __backoff_fn = { + __a, __poll, __order, __rel_time}; + auto __poll_result = std::__libcpp_thread_poll_with_backoff( + /* poll */ + [&]() { + auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a, __order); + return __poll(__current_val); + }, + /* backoff */ __backoff_fn, + __rel_time); + + return __poll_result == __poll_with_backoff_results::__poll_success; +} + +# elif _LIBCPP_HAS_THREADS // _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +template <class _AtomicWaitable, class _Poll, class _Rep, class _Period> +_LIBCPP_HIDE_FROM_ABI bool __atomic_wait_unless_with_timeout( + const _AtomicWaitable& __a, + memory_order __order, + _Poll&& __poll, + chrono::duration<_Rep, _Period> const& __rel_time) { + auto __res = std::__libcpp_thread_poll_with_backoff( + /* poll */ + [&]() { + auto __current_val = __atomic_waitable_traits<__decay_t<_AtomicWaitable> >::__atomic_load(__a, __order); + return __poll(__current_val); + }, + /* backoff */ __libcpp_timed_backoff_policy(), + __rel_time); + return __res == __poll_with_backoff_results::__poll_success; +} + +# endif // _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_NEW_SYNC + +#endif // C++20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_SYNC_TIMED_H diff --git a/lib/libcxx/include/__atomic/atomic_waitable_traits.h b/lib/libcxx/include/__atomic/atomic_waitable_traits.h @@ -0,0 +1,103 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___ATOMIC_ATOMIC_WAITABLE_TRAITS_H +#define _LIBCPP___ATOMIC_ATOMIC_WAITABLE_TRAITS_H + +#include <__atomic/contention_t.h> +#include <__atomic/memory_order.h> +#include <__config> +#include <__type_traits/decay.h> +#include <__type_traits/has_unique_object_representation.h> +#include <__type_traits/is_same.h> +#include <__type_traits/is_trivially_copyable.h> +#include <__type_traits/void_t.h> +#include <__utility/declval.h> +#include <cstring> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +// The customisation points to enable the following functions: +// - __atomic_wait +// - __atomic_wait_unless +// - __atomic_notify_one +// - __atomic_notify_all +template <class _Tp, class = void> +struct __atomic_waitable_traits { + using __value_type _LIBCPP_NODEBUG = void; + + template <class _AtomicWaitable> + static void __atomic_load(_AtomicWaitable&&, memory_order) = delete; + + template <class _AtomicWaitable> + static void __atomic_contention_address(_AtomicWaitable&&) = delete; +}; + +template <class _Tp> +concept __atomic_waitable = requires(const _Tp __t, memory_order __order) { + typename __atomic_waitable_traits<__decay_t<_Tp> >::__value_type; + { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_load(__t, __order) }; + { __atomic_waitable_traits<__decay_t<_Tp> >::__atomic_contention_address(__t) }; +}; + +# ifdef __linux__ +# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(4) +# elif defined(__APPLE__) +# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) \ + _APPLY(4) \ + _APPLY(8) +# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8 +# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8) +# elif defined(_WIN32) +# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(8) +# else +# define _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_APPLY) _APPLY(sizeof(__cxx_contention_t)) +# endif // __linux__ + +// concepts defines the types are supported natively by the platform's wait + +# if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE) + +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr bool __has_native_atomic_wait_impl() { + if (alignof(_Tp) % sizeof(_Tp) != 0) + return false; + switch (sizeof(_Tp)) { +# define _LIBCPP_MAKE_CASE(n) \ + case n: \ + return true; + _LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_LIBCPP_MAKE_CASE) + default: + return false; +# undef _LIBCPP_MAKE_CASE + }; +} + +template <class _Tp> +concept __has_native_atomic_wait = + has_unique_object_representations_v<_Tp> && is_trivially_copyable_v<_Tp> && + std::__has_native_atomic_wait_impl<_Tp>(); + +# else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE + +template <class _Tp> +concept __has_native_atomic_wait = is_same_v<_Tp, __cxx_contention_t>; + +# endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE + +#endif // C++20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_ATOMIC_WAITABLE_TRAITS_H diff --git a/lib/libcxx/include/__atomic/contention_t.h b/lib/libcxx/include/__atomic/contention_t.h @@ -19,11 +19,35 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__)) +// The original definition of `__cxx_contention_t` seemed a bit arbitrary. +// When we enable the _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE ABI, +// use definitions that are based on what the underlying platform supports +// instead. +#if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE) + +# ifdef __linux__ +using __cxx_contention_t _LIBCPP_NODEBUG = int32_t; +# elif defined(__APPLE__) +using __cxx_contention_t _LIBCPP_NODEBUG = int64_t; +# elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8 +using __cxx_contention_t _LIBCPP_NODEBUG = int64_t; +# elif defined(_AIX) && !defined(__64BIT__) +using __cxx_contention_t _LIBCPP_NODEBUG = int32_t; +# elif defined(_WIN32) +using __cxx_contention_t _LIBCPP_NODEBUG = int64_t; +# else +using __cxx_contention_t _LIBCPP_NODEBUG = int64_t; +# endif // __linux__ + +#else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE + +# if defined(__linux__) || (defined(_AIX) && !defined(__64BIT__)) using __cxx_contention_t _LIBCPP_NODEBUG = int32_t; -#else +# else using __cxx_contention_t _LIBCPP_NODEBUG = int64_t; -#endif // __linux__ || (_AIX && !__64BIT__) +# endif // __linux__ || (_AIX && !__64BIT__) + +#endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE using __cxx_atomic_contention_t _LIBCPP_NODEBUG = __cxx_atomic_impl<__cxx_contention_t>; diff --git a/lib/libcxx/include/__atomic/floating_point_helper.h b/lib/libcxx/include/__atomic/floating_point_helper.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ATOMIC_FLOATING_POINT_HELPER_H +#define _LIBCPP___ATOMIC_FLOATING_POINT_HELPER_H + +#include <__config> +#include <__type_traits/is_floating_point.h> +#include <__type_traits/is_same.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr bool __is_fp80_long_double() { + // Only x87-fp80 long double has 64-bit mantissa + return __LDBL_MANT_DIG__ == 64 && std::is_same_v<_Tp, long double>; +} + +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr bool __has_rmw_builtin() { + static_assert(std::is_floating_point_v<_Tp>); +# ifndef _LIBCPP_COMPILER_CLANG_BASED + return false; +# else + // The builtin __cxx_atomic_fetch_add errors during compilation for + // long double on platforms with fp80 format. + // For more details, see + // lib/Sema/SemaChecking.cpp function IsAllowedValueType + // LLVM Parser does not allow atomicrmw with x86_fp80 type. + // if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) && + // &Context.getTargetInfo().getLongDoubleFormat() == + // &llvm::APFloat::x87DoubleExtended()) + // For more info + // https://llvm.org/PR68602 + // https://reviews.llvm.org/D53965 + return !std::__is_fp80_long_double<_Tp>(); +# endif +} + +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ATOMIC_FLOATING_POINT_HELPER_H diff --git a/lib/libcxx/include/__bit/countl.h b/lib/libcxx/include/__bit/countl.h @@ -24,7 +24,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countl_zero(_Tp __t) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__countl_zero requires an unsigned integer type"); return __builtin_clzg(__t, numeric_limits<_Tp>::digits); } @@ -37,7 +36,7 @@ template <__unsigned_integer _Tp> template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countl_one(_Tp __t) noexcept { - return __t != numeric_limits<_Tp>::max() ? std::countl_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; + return std::countl_zero(static_cast<_Tp>(~__t)); } #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__bit/countr.h b/lib/libcxx/include/__bit/countr.h @@ -24,7 +24,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero(_Tp __t) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__countr_zero only works with unsigned types"); return __builtin_ctzg(__t, numeric_limits<_Tp>::digits); } @@ -37,7 +36,7 @@ template <__unsigned_integer _Tp> template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one(_Tp __t) noexcept { - return __t != numeric_limits<_Tp>::max() ? std::countr_zero(static_cast<_Tp>(~__t)) : numeric_limits<_Tp>::digits; + return std::countr_zero(static_cast<_Tp>(~__t)); } #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__bit/has_single_bit.h b/lib/libcxx/include/__bit/has_single_bit.h @@ -25,7 +25,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__unsigned_integer _Tp> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_single_bit(_Tp __t) noexcept { - return __t != 0 && (((__t & (__t - 1)) == 0)); + return __builtin_popcountg(__t) == 1; } _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__bit/popcount.h b/lib/libcxx/include/__bit/popcount.h @@ -23,7 +23,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount(_Tp __t) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__popcount only works with unsigned types"); return __builtin_popcountg(__t); } diff --git a/lib/libcxx/include/__bit/rotate.h b/lib/libcxx/include/__bit/rotate.h @@ -22,46 +22,35 @@ _LIBCPP_BEGIN_NAMESPACE_STD // Writing two full functions for rotl and rotr makes it easier for the compiler // to optimize the code. On x86 this function becomes the ROL instruction and // the rotr function becomes the ROR instruction. -template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__rotl requires an unsigned integer type"); + +#if _LIBCPP_STD_VER >= 20 + +template <__unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, int __cnt) noexcept { const int __n = numeric_limits<_Tp>::digits; - int __r = __s % __n; + int __r = __cnt % __n; if (__r == 0) - return __x; + return __t; if (__r > 0) - return (__x << __r) | (__x >> (__n - __r)); + return (__t << __r) | (__t >> (__n - __r)); - return (__x >> -__r) | (__x << (__n + __r)); + return (__t >> -__r) | (__t << (__n + __r)); } -template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) _NOEXCEPT { - static_assert(__is_unsigned_integer_v<_Tp>, "__rotr requires an unsigned integer type"); +template <__unsigned_integer _Tp> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, int __cnt) noexcept { const int __n = numeric_limits<_Tp>::digits; - int __r = __s % __n; + int __r = __cnt % __n; if (__r == 0) - return __x; + return __t; if (__r > 0) - return (__x >> __r) | (__x << (__n - __r)); - - return (__x << -__r) | (__x >> (__n + __r)); -} + return (__t >> __r) | (__t << (__n - __r)); -#if _LIBCPP_STD_VER >= 20 - -template <__unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotl(_Tp __t, int __cnt) noexcept { - return std::__rotl(__t, __cnt); -} - -template <__unsigned_integer _Tp> -[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp rotr(_Tp __t, int __cnt) noexcept { - return std::__rotr(__t, __cnt); + return (__t << -__r) | (__t >> (__n + __r)); } #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__bit_reference b/lib/libcxx/include/__bit_reference @@ -15,8 +15,10 @@ #include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/equal.h> +#include <__algorithm/fill_n.h> #include <__algorithm/min.h> #include <__algorithm/rotate.h> +#include <__algorithm/specialized_algorithms.h> #include <__algorithm/swap_ranges.h> #include <__assert> #include <__bit/countr.h> @@ -137,7 +139,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator bool() const _NOEXCEPT { return static_cast<bool>(*__seg_ & __mask_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool operator~() const _NOEXCEPT { return !static_cast<bool>(*this); } @@ -307,6 +309,15 @@ public: { } +#ifdef _LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR + template <bool _IsConstDep = _IsConst, __enable_if_t<_IsConstDep, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator(const __bit_iterator<_Cp, false>& __it) _NOEXCEPT + : __seg_(__it.__seg_), + __ctz_(__it.__ctz_) {} + + _LIBCPP_HIDE_FROM_ABI __bit_iterator(const __bit_iterator&) = default; + _LIBCPP_HIDE_FROM_ABI __bit_iterator& operator=(const __bit_iterator&) = default; +#else // When _IsConst=false, this is the copy constructor. // It is non-trivial. Making it trivial would break ABI. // When _IsConst=true, this is a converting constructor; @@ -327,6 +338,7 @@ public: __ctz_ = __it.__ctz_; return *this; } +#endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator*() const _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__ctz_ < __bits_per_word, "Dereferencing an invalid __bit_iterator."); @@ -467,20 +479,6 @@ private: template <class _Dp> friend struct __bit_array; - template <bool _FillVal, class _Dp> - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend void - __fill_n_bool(__bit_iterator<_Dp, false> __first, typename __size_difference_type_traits<_Dp>::size_type __n); - - template <class _Dp, bool _IC> - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_aligned( - __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); - template <class _Dp, bool _IC> - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_unaligned( - __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); - template <class _Dp, bool _IC> - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend pair<__bit_iterator<_Dp, _IC>, __bit_iterator<_Dp, false> > - __copy_impl::operator()( - __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result) const; template <class _Dp, bool _IC> _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_aligned( __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); @@ -511,10 +509,20 @@ private: bool _IsConst1, bool _IsConst2, class _BinaryPredicate, - __enable_if_t<__desugars_to_v<__equal_tag, _BinaryPredicate, bool, bool>, int> > + class _Proj1, + class _Proj2, + __enable_if_t<__is_identity<_Proj1>::value && __is_identity<_Proj2>::value && + __desugars_to_v<__equal_tag, _BinaryPredicate, bool, bool>, + int> > _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool __equal_iter_impl( - __bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst1>, __bit_iterator<_Dp, _IsConst2>, _BinaryPredicate); - template <class _Dp, + __bit_iterator<_Dp, _IsConst1>, + __bit_iterator<_Dp, _IsConst1>, + __bit_iterator<_Dp, _IsConst2>, + _BinaryPredicate, + _Proj1&, + _Proj2&); + template <bool, + class _Dp, bool _IsConst1, bool _IsConst2, class _Pred, @@ -537,6 +545,187 @@ private: template <bool _ToCount, class _Dp, bool _IC> friend typename __bit_iterator<_Dp, _IC>::difference_type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __count_bool(__bit_iterator<_Dp, _IC>, typename __size_difference_type_traits<_Dp>::size_type); + + template <class, class...> + friend struct __specialized_algorithm; +}; + +template <class _Cp> +struct __specialized_algorithm<_Algorithm::__fill_n, __single_iterator<__bit_iterator<_Cp, false> > > { + static const bool __has_algorithm = true; + + template <bool _FillVal> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void + __impl(__bit_iterator<_Cp, false> __first, typename __size_difference_type_traits<_Cp>::size_type __n) { + using _It = __bit_iterator<_Cp, false>; + using __storage_type = typename _It::__storage_type; + + const int __bits_per_word = _It::__bits_per_word; + // do first partial word + if (__first.__ctz_ != 0) { + __storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_); + __storage_type __dn = std::min(__clz_f, __n); + std::__fill_masked_range(std::__to_address(__first.__seg_), __clz_f - __dn, __first.__ctz_, _FillVal); + __n -= __dn; + ++__first.__seg_; + } + // do middle whole words + __storage_type __nw = __n / __bits_per_word; + std::__fill_n(std::__to_address(__first.__seg_), __nw, _FillVal ? static_cast<__storage_type>(-1) : 0); + __n -= __nw * __bits_per_word; + // do last partial word + if (__n > 0) { + __first.__seg_ += __nw; + std::__fill_masked_range(std::__to_address(__first.__seg_), __bits_per_word - __n, 0u, _FillVal); + } + } + + template <class _Size, class _Tp> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false> + operator()(__bit_iterator<_Cp, false> __first, _Size __n, const _Tp& __value) { + if (__n > 0) { + if (__value) + __impl<true>(__first, __n); + else + __impl<false>(__first, __n); + } + return __first + __n; + } +}; + +template <class _Cp, bool _IsConst> +struct __specialized_algorithm<_Algorithm::__copy, + __iterator_pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, _IsConst> >, + __single_iterator<__bit_iterator<_Cp, false> > > { + static const bool __has_algorithm = true; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false> + __aligned_impl(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast<difference_type>(__clz), __n); + __n -= __dn; + __storage_type __m = std::__middle_mask<__storage_type>(__clz - __dn, __first.__ctz_); + __storage_type __b = *__first.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word); + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + __storage_type __nw = __n / __bits_per_word; + std::copy(std::__to_address(__first.__seg_), + std::__to_address(__first.__seg_ + __nw), + std::__to_address(__result.__seg_)); + __n -= __nw * __bits_per_word; + __result.__seg_ += __nw; + // do last word + if (__n > 0) { + __first.__seg_ += __nw; + __storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + __storage_type __b = *__first.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast<unsigned>(__n); + } + } + return __result; + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static __bit_iterator<_Cp, false> + __unaligned_impl(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__first.__ctz_ != 0) { + unsigned __clz_f = __bits_per_word - __first.__ctz_; + difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n); + __n -= __dn; + __storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_); + __storage_type __b = *__first.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min<__storage_type>(__dn, __clz_r); + __m = std::__middle_mask<__storage_type>(__clz_r - __ddn, __result.__ctz_); + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __first.__ctz_) + *__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_); + else + *__result.__seg_ |= __b >> (__first.__ctz_ - __result.__ctz_); + __result.__seg_ += (__ddn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + if (__dn > 0) { + __m = std::__trailing_mask<__storage_type>(__bits_per_word - __dn); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> (__first.__ctz_ + __ddn); + __result.__ctz_ = static_cast<unsigned>(__dn); + } + ++__first.__seg_; + // __first.__ctz_ = 0; + } + // __first.__ctz_ == 0; + // do middle words + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __m = std::__leading_mask<__storage_type>(__result.__ctz_); + for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) { + __storage_type __b = *__first.__seg_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << __result.__ctz_; + ++__result.__seg_; + *__result.__seg_ &= __m; + *__result.__seg_ |= __b >> __clz_r; + } + // do last word + if (__n > 0) { + __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + __storage_type __b = *__first.__seg_ & __m; + __storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r)); + __m = std::__middle_mask<__storage_type>(__clz_r - __dn, __result.__ctz_); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << __result.__ctz_; + __result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word; + __result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> __dn; + __result.__ctz_ = static_cast<unsigned>(__n); + } + } + } + return __result; + } + + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX20 static pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + if (__first.__ctz_ == __result.__ctz_) + return std::make_pair(__last, __aligned_impl(__first, __last, __result)); + return std::make_pair(__last, __unaligned_impl(__first, __last, __result)); + } }; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__charconv/from_chars_integral.h b/lib/libcxx/include/__charconv/from_chars_integral.h @@ -18,8 +18,8 @@ #include <__memory/addressof.h> #include <__system_error/errc.h> #include <__type_traits/enable_if.h> -#include <__type_traits/integral_constant.h> #include <__type_traits/is_integral.h> +#include <__type_traits/is_signed.h> #include <__type_traits/is_unsigned.h> #include <__type_traits/make_unsigned.h> #include <limits> diff --git a/lib/libcxx/include/__charconv/from_chars_result.h b/lib/libcxx/include/__charconv/from_chars_result.h @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -struct _LIBCPP_EXPORTED_FROM_ABI from_chars_result { +struct from_chars_result { const char* ptr; errc ec; # if _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__charconv/to_chars_integral.h b/lib/libcxx/include/__charconv/to_chars_integral.h @@ -24,6 +24,7 @@ #include <__type_traits/integral_constant.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_signed.h> #include <__type_traits/make_32_64_or_128_bit.h> #include <__type_traits/make_unsigned.h> #include <__utility/unreachable.h> diff --git a/lib/libcxx/include/__charconv/to_chars_result.h b/lib/libcxx/include/__charconv/to_chars_result.h @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -struct _LIBCPP_EXPORTED_FROM_ABI to_chars_result { +struct to_chars_result { char* ptr; errc ec; # if _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__charconv/traits.h b/lib/libcxx/include/__charconv/traits.h @@ -113,31 +113,10 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__u }; # endif -template <typename _Tp> -inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool -__mul_overflowed(unsigned char __a, _Tp __b, unsigned char& __r) { - auto __c = __a * __b; - __r = __c; - return __c > numeric_limits<unsigned char>::max(); -} - -template <typename _Tp> -inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool -__mul_overflowed(unsigned short __a, _Tp __b, unsigned short& __r) { - auto __c = __a * __b; - __r = __c; - return __c > numeric_limits<unsigned short>::max(); -} - -template <typename _Tp> -inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool __mul_overflowed(_Tp __a, _Tp __b, _Tp& __r) { - static_assert(is_unsigned<_Tp>::value, ""); - return __builtin_mul_overflow(__a, __b, std::addressof(__r)); -} - template <typename _Tp, typename _Up> -inline _LIBCPP_HIDE_FROM_ABI bool _LIBCPP_CONSTEXPR_SINCE_CXX23 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r) { - return __itoa::__mul_overflowed(__a, static_cast<_Tp>(__b), __r); +_LIBCPP_HIDE_FROM_ABI bool _LIBCPP_CONSTEXPR_SINCE_CXX23 __mul_overflowed(_Tp __a, _Up __b, _Tp& __r) { + static_assert(is_unsigned<_Tp>::value); + return __builtin_mul_overflow(__a, static_cast<_Tp>(__b), std::addressof(__r)); } template <typename _Tp> diff --git a/lib/libcxx/include/__chrono/day.h b/lib/libcxx/include/__chrono/day.h @@ -13,6 +13,8 @@ #include <__chrono/duration.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -92,6 +94,15 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr day& day::operator-=(const days& __dd) no } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::day> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::day& __d) noexcept { return static_cast<unsigned>(__d); } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/duration.h b/lib/libcxx/include/__chrono/duration.h @@ -13,6 +13,8 @@ #include <__compare/ordering.h> #include <__compare/three_way_comparable.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_convertible.h> @@ -102,7 +104,8 @@ struct __duration_cast<_FromDuration, _ToDuration, _Period, false, false> { }; template <class _ToDuration, class _Rep, class _Period, __enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration duration_cast(const duration<_Rep, _Period>& __fd) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration +duration_cast(const duration<_Rep, _Period>& __fd) { return __duration_cast<duration<_Rep, _Period>, _ToDuration>()(__fd); } @@ -117,14 +120,18 @@ inline constexpr bool treat_as_floating_point_v = treat_as_floating_point<_Rep>: template <class _Rep> struct duration_values { public: - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep zero() _NOEXCEPT { return _Rep(0); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep max() _NOEXCEPT { return numeric_limits<_Rep>::max(); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep min() _NOEXCEPT { return numeric_limits<_Rep>::lowest(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep zero() _NOEXCEPT { return _Rep(0); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep max() _NOEXCEPT { + return numeric_limits<_Rep>::max(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _Rep min() _NOEXCEPT { + return numeric_limits<_Rep>::lowest(); + } }; #if _LIBCPP_STD_VER >= 17 template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<_Rep, _Period>& __d) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration<_Rep, _Period>& __d) { _ToDuration __t = chrono::duration_cast<_ToDuration>(__d); if (__t > __d) __t = __t - _ToDuration{1}; @@ -132,7 +139,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration floor(const duration< } template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_Rep, _Period>& __d) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_Rep, _Period>& __d) { _ToDuration __t = chrono::duration_cast<_ToDuration>(__d); if (__t < __d) __t = __t + _ToDuration{1}; @@ -140,7 +147,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration ceil(const duration<_ } template <class _ToDuration, class _Rep, class _Period, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration round(const duration<_Rep, _Period>& __d) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToDuration round(const duration<_Rep, _Period>& __d) { _ToDuration __lower = chrono::floor<_ToDuration>(__d); _ToDuration __upper = __lower + _ToDuration{1}; auto __lower_diff = __d - __lower; @@ -220,14 +227,14 @@ public: // observer - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR rep count() const { return __rep_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR rep count() const { return __rep_; } // arithmetic - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator+() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator+() const { return typename common_type<duration>::type(*this); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator-() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration>::type operator-() const { return typename common_type<duration>::type(-__rep_); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 duration& operator++() { @@ -269,13 +276,13 @@ public: // special values - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration zero() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration zero() _NOEXCEPT { return duration(duration_values<rep>::zero()); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration min() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration min() _NOEXCEPT { return duration(duration_values<rep>::min()); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration max() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR duration max() _NOEXCEPT { return duration(duration_values<rep>::max()); } }; @@ -389,7 +396,7 @@ operator<=>(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Perio // Duration + template <class _Rep1, class _Period1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type operator+(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Cd; @@ -399,7 +406,7 @@ operator+(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2 // Duration - template <class _Rep1, class _Period1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type operator-(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Cd; @@ -412,7 +419,8 @@ template <class _Rep1, class _Period, class _Rep2, __enable_if_t<is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> operator*(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; typedef duration<_Cr, _Period> _Cd; @@ -423,7 +431,8 @@ template <class _Rep1, class _Period, class _Rep2, __enable_if_t<is_convertible<const _Rep1&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> operator*(const _Rep1& __s, const duration<_Rep2, _Period>& __d) { return __d * __s; } @@ -436,7 +445,8 @@ template <class _Rep1, __enable_if_t<!__is_duration_v<_Rep2> && is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; typedef duration<_Cr, _Period> _Cd; @@ -444,7 +454,7 @@ operator/(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { } template <class _Rep1, class _Period1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<_Rep1, _Rep2>::type +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<_Rep1, _Rep2>::type operator/(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type _Ct; return _Ct(__lhs).count() / _Ct(__rhs).count(); @@ -458,7 +468,8 @@ template <class _Rep1, __enable_if_t<!__is_duration_v<_Rep2> && is_convertible<const _Rep2&, typename common_type<_Rep1, _Rep2>::type>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR duration<typename common_type<_Rep1, _Rep2>::type, _Period> operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; typedef duration<_Cr, _Period> _Cd; @@ -466,7 +477,7 @@ operator%(const duration<_Rep1, _Period>& __d, const _Rep2& __s) { } template <class _Rep1, class _Period1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR typename common_type<duration<_Rep1, _Period1>, duration<_Rep2, _Period2> >::type operator%(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef typename common_type<_Rep1, _Rep2>::type _Cr; @@ -481,51 +492,53 @@ operator%(const duration<_Rep1, _Period1>& __lhs, const duration<_Rep2, _Period2 inline namespace literals { inline namespace chrono_literals { -_LIBCPP_HIDE_FROM_ABI constexpr chrono::hours operator""h(unsigned long long __h) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::hours operator""h(unsigned long long __h) { return chrono::hours(static_cast<chrono::hours::rep>(__h)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<3600, 1>> operator""h(long double __h) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<3600, 1>> +operator""h(long double __h) { return chrono::duration<long double, ratio<3600, 1>>(__h); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes operator""min(unsigned long long __m) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::minutes operator""min(unsigned long long __m) { return chrono::minutes(static_cast<chrono::minutes::rep>(__m)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<60, 1>> operator""min(long double __m) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, ratio<60, 1>> +operator""min(long double __m) { return chrono::duration<long double, ratio<60, 1>>(__m); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds operator""s(unsigned long long __s) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::seconds operator""s(unsigned long long __s) { return chrono::seconds(static_cast<chrono::seconds::rep>(__s)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double> operator""s(long double __s) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double> operator""s(long double __s) { return chrono::duration<long double>(__s); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::milliseconds operator""ms(unsigned long long __ms) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::milliseconds operator""ms(unsigned long long __ms) { return chrono::milliseconds(static_cast<chrono::milliseconds::rep>(__ms)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, milli> operator""ms(long double __ms) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, milli> operator""ms(long double __ms) { return chrono::duration<long double, milli>(__ms); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::microseconds operator""us(unsigned long long __us) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::microseconds operator""us(unsigned long long __us) { return chrono::microseconds(static_cast<chrono::microseconds::rep>(__us)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, micro> operator""us(long double __us) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, micro> operator""us(long double __us) { return chrono::duration<long double, micro>(__us); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::nanoseconds operator""ns(unsigned long long __ns) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::nanoseconds operator""ns(unsigned long long __ns) { return chrono::nanoseconds(static_cast<chrono::nanoseconds::rep>(__ns)); } -_LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, nano> operator""ns(long double __ns) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr chrono::duration<long double, nano> operator""ns(long double __ns) { return chrono::duration<long double, nano>(__ns); } @@ -538,6 +551,18 @@ using namespace literals::chrono_literals; #endif // _LIBCPP_STD_VER >= 14 +#if _LIBCPP_STD_VER >= 26 + +template <class _Rep, class _Period> + requires __has_enabled_hash<_Rep>::value +struct hash<chrono::duration<_Rep, _Period>> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::duration<_Rep, _Period>& __d) { + return hash<_Rep>{}(__d.count()); + } +}; + +#endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/lib/libcxx/include/__chrono/file_clock.h b/lib/libcxx/include/__chrono/file_clock.h @@ -60,16 +60,18 @@ struct _FilesystemClock { _LIBCPP_EXPORTED_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false; - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_EXPORTED_FROM_ABI static time_point now() noexcept; + [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI static time_point now() noexcept; # if _LIBCPP_STD_VER >= 20 template <class _Duration> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static chrono::sys_time<_Duration> to_sys(const chrono::file_time<_Duration>& __t) { return chrono::sys_time<_Duration>(__t.time_since_epoch()); } template <class _Duration> - _LIBCPP_HIDE_FROM_ABI static chrono::file_time<_Duration> from_sys(const chrono::sys_time<_Duration>& __t) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static chrono::file_time<_Duration> + from_sys(const chrono::sys_time<_Duration>& __t) { return chrono::file_time<_Duration>(__t.time_since_epoch()); } # endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/is_clock.h b/lib/libcxx/include/__chrono/is_clock.h @@ -0,0 +1,72 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___CHRONO_IS_CLOCK_H +#define _LIBCPP___CHRONO_IS_CLOCK_H + +#include <__config> + +#include <__chrono/duration.h> +#include <__chrono/time_point.h> +#include <__concepts/same_as.h> +#include <__type_traits/integral_constant.h> +#include <__type_traits/is_arithmetic.h> +#include <__type_traits/is_class.h> +#include <__type_traits/is_union.h> +#include <ratio> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +// Helper to check that _Tp::time_point has the form time_point<_, typename _Tp::duration>. +template <class _TimePoint, class _ClockType> +inline constexpr bool __is_valid_clock_time_point_v = false; + +template <class _TimePointClock, class _ClockType> +inline constexpr bool + __is_valid_clock_time_point_v<time_point<_TimePointClock, typename _ClockType::duration>, _ClockType> = true; + +// Check if a clock satisfies the Cpp17Clock requirements as defined in [time.clock.req] +template <class _Tp> +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_clock_v = requires { + typename _Tp::rep; + requires is_arithmetic_v<typename _Tp::rep> || is_class_v<typename _Tp::rep> || is_union_v<typename _Tp::rep>; + + typename _Tp::period; + requires __is_ratio_v<typename _Tp::period>; + + typename _Tp::duration; + requires same_as<typename _Tp::duration, duration<typename _Tp::rep, typename _Tp::period>>; + + typename _Tp::time_point; + requires __is_valid_clock_time_point_v<typename _Tp::time_point, _Tp>; + + _Tp::is_steady; + requires same_as<decltype((_Tp::is_steady)), const bool&>; + + _Tp::now(); + requires same_as<decltype(_Tp::now()), typename _Tp::time_point>; +}; + +template <class _Tp> +struct _LIBCPP_NO_SPECIALIZATIONS is_clock : bool_constant<is_clock_v<_Tp>> {}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER +#endif // _LIBCPP___CHRONO_IS_CLOCK_H diff --git a/lib/libcxx/include/__chrono/leap_second.h b/lib/libcxx/include/__chrono/leap_second.h @@ -22,6 +22,8 @@ # include <__compare/ordering.h> # include <__compare/three_way_comparable.h> # include <__config> +# include <__cstddef/size_t.h> +# include <__functional/hash.h> # include <__utility/private_constructor_tag.h> # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -122,6 +124,17 @@ private: } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::leap_second> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::leap_second& __lp) noexcept { + return std::__hash_combine(hash<chrono::sys_seconds>{}(__lp.date()), hash<chrono::seconds>{}(__lp.value())); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + # endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__chrono/month.h b/lib/libcxx/include/__chrono/month.h @@ -13,6 +13,8 @@ #include <__chrono/duration.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -108,6 +110,17 @@ inline constexpr month December{12}; } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::month> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::month& __m) noexcept { + return static_cast<unsigned>(__m); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/month_weekday.h b/lib/libcxx/include/__chrono/month_weekday.h @@ -13,6 +13,8 @@ #include <__chrono/month.h> #include <__chrono/weekday.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -98,6 +100,26 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_weekday_last operator/(const weekda } } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::month_weekday> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::month_weekday& __mw) noexcept { + return std::__hash_combine( + hash<chrono::month>{}(__mw.month()), hash<chrono::weekday_indexed>{}(__mw.weekday_indexed())); + } +}; + +template <> +struct hash<chrono::month_weekday_last> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::month_weekday_last& __mwl) noexcept { + return std::__hash_combine( + hash<chrono::month>{}(__mwl.month()), hash<chrono::weekday_last>{}(__mwl.weekday_last())); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/monthday.h b/lib/libcxx/include/__chrono/monthday.h @@ -15,6 +15,8 @@ #include <__chrono/month.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -126,6 +128,24 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr month_day_last operator/(last_spec, int _ } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::month_day> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::month_day& __md) noexcept { + return std::__hash_combine(hash<chrono::month>{}(__md.month()), hash<chrono::day>{}(__md.day())); + } +}; + +template <> +struct hash<chrono::month_day_last> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::month_day_last& __mdl) noexcept { + return hash<chrono::month>{}(__mdl.month()); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/steady_clock.h b/lib/libcxx/include/__chrono/steady_clock.h @@ -31,7 +31,7 @@ public: typedef chrono::time_point<steady_clock, duration> time_point; static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = true; - static time_point now() _NOEXCEPT; + [[__nodiscard__]] static time_point now() _NOEXCEPT; }; #endif diff --git a/lib/libcxx/include/__chrono/system_clock.h b/lib/libcxx/include/__chrono/system_clock.h @@ -31,9 +31,9 @@ public: typedef chrono::time_point<system_clock> time_point; static _LIBCPP_CONSTEXPR_SINCE_CXX14 const bool is_steady = false; - static time_point now() _NOEXCEPT; - static time_t to_time_t(const time_point& __t) _NOEXCEPT; - static time_point from_time_t(time_t __t) _NOEXCEPT; + [[__nodiscard__]] static time_point now() _NOEXCEPT; + [[__nodiscard__]] static time_t to_time_t(const time_point& __t) _NOEXCEPT; + [[__nodiscard__]] static time_point from_time_t(time_t __t) _NOEXCEPT; }; #if _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/time_point.h b/lib/libcxx/include/__chrono/time_point.h @@ -14,6 +14,8 @@ #include <__compare/ordering.h> #include <__compare/three_way_comparable.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_convertible.h> @@ -54,7 +56,9 @@ public: // observer - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 duration time_since_epoch() const { return __d_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 duration time_since_epoch() const { + return __d_; + } // arithmetic @@ -82,8 +86,12 @@ public: // special values - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point min() _NOEXCEPT { return time_point(duration::min()); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point max() _NOEXCEPT { return time_point(duration::max()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point min() _NOEXCEPT { + return time_point(duration::min()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR time_point max() _NOEXCEPT { + return time_point(duration::max()); + } }; } // namespace chrono @@ -95,30 +103,33 @@ struct common_type<chrono::time_point<_Clock, _Duration1>, chrono::time_point<_C namespace chrono { -template <class _ToDuration, class _Clock, class _Duration> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, _ToDuration> +template <class _ToDuration, class _Clock, class _Duration, __enable_if_t<__is_duration_v<_ToDuration>, int> = 0> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, _ToDuration> time_point_cast(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>(chrono::duration_cast<_ToDuration>(__t.time_since_epoch())); } #if _LIBCPP_STD_VER >= 17 template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) { +[[nodiscard]] inline + _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> floor(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::floor<_ToDuration>(__t.time_since_epoch())}; } template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> ceil(const time_point<_Clock, _Duration>& __t) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> +ceil(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::ceil<_ToDuration>(__t.time_since_epoch())}; } template <class _ToDuration, class _Clock, class _Duration, enable_if_t<__is_duration_v<_ToDuration>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> round(const time_point<_Clock, _Duration>& __t) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr time_point<_Clock, _ToDuration> +round(const time_point<_Clock, _Duration>& __t) { return time_point<_Clock, _ToDuration>{chrono::round<_ToDuration>(__t.time_since_epoch())}; } template <class _Rep, class _Period, enable_if_t<numeric_limits<_Rep>::is_signed, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr duration<_Rep, _Period> abs(duration<_Rep, _Period> __d) { return __d >= __d.zero() ? +__d : -__d; } #endif // _LIBCPP_STD_VER >= 17 @@ -188,7 +199,7 @@ operator<=>(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock // time_point operator+(time_point x, duration y); template <class _Clock, class _Duration1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Tr; @@ -198,7 +209,7 @@ operator+(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Pe // time_point operator+(duration x, time_point y); template <class _Rep1, class _Period1, class _Clock, class _Duration2> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<duration<_Rep1, _Period1>, _Duration2>::type> operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { return __rhs + __lhs; @@ -207,7 +218,7 @@ operator+(const duration<_Rep1, _Period1>& __lhs, const time_point<_Clock, _Dura // time_point operator-(time_point x, duration y); template <class _Clock, class _Duration1, class _Rep2, class _Period2> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Period2>& __rhs) { typedef time_point<_Clock, typename common_type<_Duration1, duration<_Rep2, _Period2> >::type> _Ret; @@ -217,13 +228,26 @@ operator-(const time_point<_Clock, _Duration1>& __lhs, const duration<_Rep2, _Pe // duration operator-(time_point x, time_point y); template <class _Clock, class _Duration1, class _Duration2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename common_type<_Duration1, _Duration2>::type +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename common_type<_Duration1, _Duration2>::type operator-(const time_point<_Clock, _Duration1>& __lhs, const time_point<_Clock, _Duration2>& __rhs) { return __lhs.time_since_epoch() - __rhs.time_since_epoch(); } } // namespace chrono +#if _LIBCPP_STD_VER >= 26 + +template <class _Clock, class _Duration> + requires __has_enabled_hash<_Duration>::value +struct hash<chrono::time_point<_Clock, _Duration>> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::time_point<_Clock, _Duration>& __tp) { + return hash<_Duration>{}(__tp.time_since_epoch()); + } +}; + +#endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS diff --git a/lib/libcxx/include/__chrono/weekday.h b/lib/libcxx/include/__chrono/weekday.h @@ -15,6 +15,8 @@ #include <__chrono/system_clock.h> #include <__chrono/time_point.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -160,6 +162,29 @@ inline constexpr weekday Saturday{6}; } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::weekday> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::weekday& __w) noexcept { return __w.c_encoding(); } +}; + +template <> +struct hash<chrono::weekday_indexed> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::weekday_indexed& __wi) noexcept { + return std::__hash_combine(hash<chrono::weekday>{}(__wi.weekday()), __wi.index()); + } +}; + +template <> +struct hash<chrono::weekday_last> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::weekday_last& __wl) noexcept { + return hash<chrono::weekday>{}(__wl.weekday()); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/year.h b/lib/libcxx/include/__chrono/year.h @@ -13,6 +13,8 @@ #include <__chrono/duration.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #include <limits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -109,6 +111,15 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool year::ok() const noexcept { } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::year> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year& __y) noexcept { return static_cast<int>(__y); } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/year_month.h b/lib/libcxx/include/__chrono/year_month.h @@ -15,6 +15,8 @@ #include <__chrono/year.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -116,6 +118,17 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr year_month& year_month::operator-=(const } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::year_month> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year_month& __ym) noexcept { + return std::__hash_combine(hash<chrono::year>{}(__ym.year()), hash<chrono::month>{}(__ym.month())); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/year_month_day.h b/lib/libcxx/include/__chrono/year_month_day.h @@ -21,6 +21,8 @@ #include <__chrono/year_month.h> #include <__compare/ordering.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #include <limits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -330,6 +332,27 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr bool year_month_day::ok() const noexcept } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::year_month_day> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year_month_day& __ymd) noexcept { + return std::__hash_combine( + hash<chrono::year>{}(__ymd.year()), + std::__hash_combine(hash<chrono::month>{}(__ymd.month()), hash<chrono::day>{}(__ymd.day()))); + } +}; + +template <> +struct hash<chrono::year_month_day_last> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year_month_day_last& __ymdl) noexcept { + return std::__hash_combine( + hash<chrono::year>{}(__ymdl.year()), hash<chrono::month_day_last>{}(__ymdl.month_day_last())); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/year_month_weekday.h b/lib/libcxx/include/__chrono/year_month_weekday.h @@ -22,6 +22,8 @@ #include <__chrono/year_month.h> #include <__chrono/year_month_day.h> #include <__config> +#include <__cstddef/size_t.h> +#include <__functional/hash.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -280,6 +282,30 @@ year_month_weekday_last::operator-=(const years& __dy) noexcept { } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <> +struct hash<chrono::year_month_weekday> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year_month_weekday& __ymw) noexcept { + return std::__hash_combine( + hash<chrono::year>{}(__ymw.year()), + std::__hash_combine( + hash<chrono::month>{}(__ymw.month()), hash<chrono::weekday_indexed>{}(__ymw.weekday_indexed()))); + } +}; + +template <> +struct hash<chrono::year_month_weekday_last> { + _LIBCPP_HIDE_FROM_ABI static size_t operator()(const chrono::year_month_weekday_last& __ymwl) noexcept { + return std::__hash_combine( + hash<chrono::year>{}(__ymwl.year()), + std::__hash_combine( + hash<chrono::month>{}(__ymwl.month()), hash<chrono::weekday_last>{}(__ymwl.weekday_last()))); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__chrono/zoned_time.h b/lib/libcxx/include/__chrono/zoned_time.h @@ -24,6 +24,8 @@ # include <__chrono/tzdb_list.h> # include <__concepts/constructible.h> # include <__config> +# include <__cstddef/size_t.h> +# include <__functional/hash.h> # include <__type_traits/common_type.h> # include <__type_traits/conditional.h> # include <__type_traits/remove_cvref.h> @@ -216,6 +218,20 @@ operator==(const zoned_time<_Duration1, _TimeZonePtr>& __lhs, const zoned_time<_ } // namespace chrono +# if _LIBCPP_STD_VER >= 26 + +template <class _Duration, class _TimeZonePtr> + requires __has_enabled_hash<_Duration>::value && __has_enabled_hash<_TimeZonePtr>::value +struct hash<chrono::zoned_time<_Duration, _TimeZonePtr>> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static size_t + operator()(const chrono::zoned_time<_Duration, _TimeZonePtr>& __zt) { + return std::__hash_combine( + hash<chrono::sys_time<_Duration>>{}(__zt.get_sys_time()), hash<_TimeZonePtr>{}(__zt.get_time_zone())); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 + # endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && // _LIBCPP_HAS_LOCALIZATION diff --git a/lib/libcxx/include/__compare/is_eq.h b/lib/libcxx/include/__compare/is_eq.h @@ -20,12 +20,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_eq(partial_ordering __c) noexcept { return __c == 0; } -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_neq(partial_ordering __c) noexcept { return __c != 0; } -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lt(partial_ordering __c) noexcept { return __c < 0; } -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lteq(partial_ordering __c) noexcept { return __c <= 0; } -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gt(partial_ordering __c) noexcept { return __c > 0; } -_LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gteq(partial_ordering __c) noexcept { return __c >= 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_eq(partial_ordering __c) noexcept { return __c == 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_neq(partial_ordering __c) noexcept { return __c != 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lt(partial_ordering __c) noexcept { return __c < 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_lteq(partial_ordering __c) noexcept { return __c <= 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gt(partial_ordering __c) noexcept { return __c > 0; } +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr bool is_gteq(partial_ordering __c) noexcept { return __c >= 0; } #endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__compare/strong_order.h b/lib/libcxx/include/__compare/strong_order.h @@ -13,7 +13,6 @@ #include <__compare/compare_three_way.h> #include <__compare/ordering.h> #include <__config> -#include <__math/exponential_functions.h> #include <__math/traits.h> #include <__type_traits/conditional.h> #include <__type_traits/decay.h> @@ -53,38 +52,21 @@ struct __fn { template <class _Tp, class _Up, class _Dp = decay_t<_Tp>> requires is_same_v<_Dp, decay_t<_Up>> && is_floating_point_v<_Dp> _LIBCPP_HIDE_FROM_ABI static constexpr strong_ordering __go(_Tp&& __t, _Up&& __u, __priority_tag<1>) noexcept { - if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int32_t)) { - int32_t __rx = std::bit_cast<int32_t>(__t); - int32_t __ry = std::bit_cast<int32_t>(__u); - __rx = (__rx < 0) ? (numeric_limits<int32_t>::min() - __rx - 1) : __rx; - __ry = (__ry < 0) ? (numeric_limits<int32_t>::min() - __ry - 1) : __ry; - return (__rx <=> __ry); - } else if constexpr (numeric_limits<_Dp>::is_iec559 && sizeof(_Dp) == sizeof(int64_t)) { - int64_t __rx = std::bit_cast<int64_t>(__t); - int64_t __ry = std::bit_cast<int64_t>(__u); - __rx = (__rx < 0) ? (numeric_limits<int64_t>::min() - __rx - 1) : __rx; - __ry = (__ry < 0) ? (numeric_limits<int64_t>::min() - __ry - 1) : __ry; + if constexpr (numeric_limits<_Dp>::is_iec559 && + (sizeof(_Dp) == sizeof(int32_t) || sizeof(_Dp) == sizeof(int64_t))) { + using _IntT = conditional_t<sizeof(_Dp) == sizeof(int32_t), int32_t, int64_t>; + _IntT __rx = std::bit_cast<_IntT>(__t); + _IntT __ry = std::bit_cast<_IntT>(__u); + __rx = (__rx < 0) ? (numeric_limits<_IntT>::min() - __rx - 1) : __rx; + __ry = (__ry < 0) ? (numeric_limits<_IntT>::min() - __ry - 1) : __ry; return (__rx <=> __ry); } else if (__t < __u) { return strong_ordering::less; } else if (__t > __u) { return strong_ordering::greater; } else if (__t == __u) { - if constexpr (numeric_limits<_Dp>::radix == 2) { - return __math::signbit(__u) <=> __math::signbit(__t); - } else { - // This is bullet 3 of the IEEE754 algorithm, relevant - // only for decimal floating-point; - // see https://stackoverflow.com/questions/69068075/ - if (__t == 0 || __math::isinf(__t)) { - return __math::signbit(__u) <=> __math::signbit(__t); - } else { - int __texp, __uexp; - (void)__math::frexp(__t, &__texp); - (void)__math::frexp(__u, &__uexp); - return (__t < 0) ? (__texp <=> __uexp) : (__uexp <=> __texp); - } - } + static_assert(numeric_limits<_Dp>::radix == 2, "floating point type with a radix other than 2?"); + return __math::signbit(__u) <=> __math::signbit(__t); } else { // They're unordered, so one of them must be a NAN. // The order is -QNAN, -SNAN, numbers, +SNAN, +QNAN. @@ -93,9 +75,9 @@ struct __fn { bool __t_is_negative = __math::signbit(__t); bool __u_is_negative = __math::signbit(__u); using _IntType = - conditional_t< sizeof(__t) == sizeof(int32_t), - int32_t, - conditional_t< sizeof(__t) == sizeof(int64_t), int64_t, void> >; + conditional_t<sizeof(__t) == sizeof(int32_t), + int32_t, + conditional_t<sizeof(__t) == sizeof(int64_t), int64_t, void>>; if constexpr (is_same_v<_IntType, void>) { static_assert(sizeof(_Dp) == 0, "std::strong_order is unimplemented for this floating-point type"); } else if (__t_is_nan && __u_is_nan) { diff --git a/lib/libcxx/include/__compare/three_way_comparable.h b/lib/libcxx/include/__compare/three_way_comparable.h @@ -12,6 +12,7 @@ #include <__compare/common_comparison_category.h> #include <__compare/ordering.h> #include <__concepts/common_reference_with.h> +#include <__concepts/comparison_common_type.h> #include <__concepts/equality_comparable.h> #include <__concepts/same_as.h> #include <__concepts/totally_ordered.h> @@ -39,8 +40,7 @@ concept three_way_comparable = template <class _Tp, class _Up, class _Cat = partial_ordering> concept three_way_comparable_with = - three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> && - common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> && + three_way_comparable<_Tp, _Cat> && three_way_comparable<_Up, _Cat> && __comparison_common_type_with<_Tp, _Up> && three_way_comparable<common_reference_t<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>>, _Cat> && __weakly_equality_comparable_with<_Tp, _Up> && __partially_ordered_with<_Tp, _Up> && requires(__make_const_lvalue_ref<_Tp> __t, __make_const_lvalue_ref<_Up> __u) { diff --git a/lib/libcxx/include/__concepts/comparison_common_type.h b/lib/libcxx/include/__concepts/comparison_common_type.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___CONCEPTS_COMPARISON_COMMON_TYPE_H +#define _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H + +#include <__concepts/convertible_to.h> +#include <__concepts/same_as.h> +#include <__config> +#include <__type_traits/common_reference.h> +#include <__type_traits/remove_cvref.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 + +template <class _Tp, class _Up, class _CommonRef = common_reference_t<const _Tp&, const _Up&>> +concept __comparison_common_type_with_impl = + same_as<common_reference_t<const _Tp&, const _Up&>, common_reference_t<const _Up&, const _Tp&>> && requires { + requires convertible_to<const _Tp&, const _CommonRef&> || convertible_to<_Tp, const _CommonRef&>; + requires convertible_to<const _Up&, const _CommonRef&> || convertible_to<_Up, const _CommonRef&>; + }; + +template <class _Tp, class _Up> +concept __comparison_common_type_with = __comparison_common_type_with_impl<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>; + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___CONCEPTS_COMPARISON_COMMON_TYPE_H diff --git a/lib/libcxx/include/__concepts/equality_comparable.h b/lib/libcxx/include/__concepts/equality_comparable.h @@ -11,6 +11,7 @@ #include <__concepts/boolean_testable.h> #include <__concepts/common_reference_with.h> +#include <__concepts/comparison_common_type.h> #include <__config> #include <__type_traits/common_reference.h> #include <__type_traits/make_const_lvalue_ref.h> @@ -41,7 +42,7 @@ concept equality_comparable = __weakly_equality_comparable_with<_Tp, _Tp>; template <class _Tp, class _Up> concept equality_comparable_with = equality_comparable<_Tp> && equality_comparable<_Up> && - common_reference_with<__make_const_lvalue_ref<_Tp>, __make_const_lvalue_ref<_Up>> && + __comparison_common_type_with<_Tp, _Up> && equality_comparable< common_reference_t< __make_const_lvalue_ref<_Tp>, diff --git a/lib/libcxx/include/__condition_variable/condition_variable.h b/lib/libcxx/include/__condition_variable/condition_variable.h @@ -170,7 +170,7 @@ public: wait_for(unique_lock<mutex>& __lk, const chrono::duration<_Rep, _Period>& __d, _Predicate __pred); typedef __libcpp_condvar_t* native_handle_type; - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__cv_; } private: void diff --git a/lib/libcxx/include/__config b/lib/libcxx/include/__config @@ -14,6 +14,8 @@ #include <__configuration/abi.h> #include <__configuration/availability.h> #include <__configuration/compiler.h> +#include <__configuration/experimental.h> +#include <__configuration/hardening.h> #include <__configuration/language.h> #include <__configuration/platform.h> @@ -28,7 +30,7 @@ // _LIBCPP_VERSION represents the version of libc++, which matches the version of LLVM. // Given a LLVM release LLVM XX.YY.ZZ (e.g. LLVM 17.0.1 == 17.00.01), _LIBCPP_VERSION is // defined to XXYYZZ. -# define _LIBCPP_VERSION 210100 +# define _LIBCPP_VERSION 220104 # define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y # define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y) @@ -38,195 +40,6 @@ # 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(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated. -// Since hardening went through several changes (many of which impacted user-facing macros), -// we're keeping these checks around for a bit longer than usual. Failure to properly configure -// hardening results in checks being dropped silently, which is a pretty big deal. -# if defined(_LIBCPP_ENABLE_ASSERTIONS) -# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_HARDENED_MODE) -# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_SAFE_MODE) -# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" -# endif -# if defined(_LIBCPP_ENABLE_DEBUG_MODE) -# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" -# endif - -// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: -// -// - `_LIBCPP_HARDENING_MODE_NONE`; -// - `_LIBCPP_HARDENING_MODE_FAST`; -// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`; -// - `_LIBCPP_HARDENING_MODE_DEBUG`. -// -// These values have the following effects: -// -// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks; -// -// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks -// that can be done with relatively little runtime overhead in constant time; -// -// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of -// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors -// but are not necessarily security-critical; -// -// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive -// mode and enables all checks available in the library, including internal assertions. Checks that are part of the -// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production. - -// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These -// macros are only for internal use -- users should only pick one of the high-level hardening modes described above. -// -// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and -// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid: -// - the sentinel is reachable from the begin iterator; -// - TODO(hardening): both iterators refer to the same container. -// -// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through -// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access -// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like -// `optional` and `function` are considered one-element containers for the purposes of this check. -// -// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero -// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the -// memory security of a program (however, it is still undefined behavior that can result in strange errors due to -// compiler optimizations). -// -// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the -// given ranges do not overlap. -// -// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object -// was allocated by the given allocator). Violating this category typically results in a memory leak. -// -// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in -// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like -// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category -// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or -// otherwise create an immediate security issue. -// -// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure -// the containers have compatible allocators. -// -// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments -// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the -// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. -// a string view where only a subset of elements is possible to access). This category is for assertions violating -// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the -// user code. -// -// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to -// be benign in our implementation. -// -// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed -// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied; -// thus, this would often be a heuristic check and it might be quite expensive. -// -// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on -// user input. -// -// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet. - -// clang-format off -# define _LIBCPP_HARDENING_MODE_NONE (1 << 1) -# define _LIBCPP_HARDENING_MODE_FAST (1 << 2) -# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered. -# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3) -// clang-format on - -# ifndef _LIBCPP_HARDENING_MODE - -# ifndef _LIBCPP_HARDENING_MODE_DEFAULT -# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \ -`__config_site` header, please make sure your installation of libc++ is not broken. -# endif - -# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT -# endif - -# if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && \ - _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \ - _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \ - _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG -# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \ -_LIBCPP_HARDENING_MODE_NONE, \ -_LIBCPP_HARDENING_MODE_FAST, \ -_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) @@ -320,13 +133,6 @@ _LIBCPP_HARDENING_MODE_DEBUG // When this option is used, the token passed to `std::random_device`'s // constructor *must* be "/dev/urandom" -- anything else is an error. // -// _LIBCPP_USING_NACL_RANDOM -// NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access, -// including accesses to the special files under `/dev`. This implementation -// uses the NaCL syscall `nacl_secure_random_init()` to get entropy. -// When this option is used, the token passed to `std::random_device`'s -// constructor *must* be "/dev/urandom" -- anything else is an error. -// // _LIBCPP_USING_WIN32_RANDOM // Use rand_s(), for use on Windows. // When this option is used, the token passed to `std::random_device`'s @@ -338,8 +144,6 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_USING_GETENTROPY # elif defined(__Fuchsia__) # define _LIBCPP_USING_FUCHSIA_CPRNG -# elif defined(__native_client__) -# define _LIBCPP_USING_NACL_RANDOM # elif defined(_LIBCPP_WIN32API) # define _LIBCPP_USING_WIN32_RANDOM # else @@ -348,7 +152,7 @@ _LIBCPP_HARDENING_MODE_DEBUG # ifndef _LIBCPP_CXX03_LANG -# define _LIBCPP_ALIGNOF(_Tp) alignof(_Tp) +# define _LIBCPP_ALIGNOF(...) alignof(__VA_ARGS__) # define _ALIGNAS_TYPE(x) alignas(x) # define _ALIGNAS(x) alignas(x) # define _NOEXCEPT noexcept @@ -357,7 +161,7 @@ _LIBCPP_HARDENING_MODE_DEBUG # else -# define _LIBCPP_ALIGNOF(_Tp) _Alignof(_Tp) +# define _LIBCPP_ALIGNOF(...) _Alignof(__VA_ARGS__) # define _ALIGNAS_TYPE(x) __attribute__((__aligned__(_LIBCPP_ALIGNOF(x)))) # define _ALIGNAS(x) __attribute__((__aligned__(x))) # define nullptr __nullptr @@ -471,6 +275,12 @@ typedef __char32_t char32_t; # define _LIBCPP_GCC_DIAGNOSTIC_IGNORED(str) # endif +// Macros to enter and leave a state where deprecation warnings are suppressed. +# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \ + _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wdeprecated") \ + _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wdeprecated-declarations") +# define _LIBCPP_SUPPRESS_DEPRECATED_POP _LIBCPP_DIAGNOSTIC_POP + # if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST # define _LIBCPP_HARDENING_SIG f # elif _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_EXTENSIVE @@ -481,6 +291,16 @@ typedef __char32_t char32_t; # define _LIBCPP_HARDENING_SIG n // "none" # endif +# if _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_OBSERVE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG o +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG q +# elif _LIBCPP_ASSERTION_SEMANTIC == _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# define _LIBCPP_ASSERTION_SEMANTIC_SIG e +# else +# define _LIBCPP_ASSERTION_SEMANTIC_SIG i // `ignore` +# endif + # if !_LIBCPP_HAS_EXCEPTIONS # define _LIBCPP_EXCEPTIONS_SIG n # else @@ -488,7 +308,9 @@ typedef __char32_t char32_t; # endif # define _LIBCPP_ODR_SIGNATURE \ - _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_EXCEPTIONS_SIG), _LIBCPP_VERSION) + _LIBCPP_CONCAT( \ + _LIBCPP_CONCAT(_LIBCPP_CONCAT(_LIBCPP_HARDENING_SIG, _LIBCPP_ASSERTION_SEMANTIC_SIG), _LIBCPP_EXCEPTIONS_SIG), \ + _LIBCPP_VERSION) // This macro marks a symbol as being hidden from libc++'s ABI. This is achieved // on two levels: @@ -550,16 +372,6 @@ typedef __char32_t char32_t; # endif # define _LIBCPP_HIDE_FROM_ABI_VIRTUAL _LIBCPP_HIDDEN _LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION -# ifdef _LIBCPP_BUILDING_LIBRARY -# if _LIBCPP_ABI_VERSION > 1 -# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI -# else -# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 -# endif -# else -# define _LIBCPP_HIDE_FROM_ABI_AFTER_V1 _LIBCPP_HIDE_FROM_ABI -# endif - // Clang modules take a significant compile time hit when pushing and popping diagnostics. // Since all the headers are marked as system headers unless _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER is defined, we can // simply disable this pushing and popping when _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER isn't defined. @@ -676,27 +488,6 @@ typedef __char32_t char32_t; # endif # endif -// It is not yet possible to use aligned_alloc() on all Apple platforms since -// 10.15 was the first version to ship an implementation of aligned_alloc(). -# if defined(__APPLE__) -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 0 -# else -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 1 -# endif -# elif defined(__ANDROID__) && __ANDROID_API__ < 28 -// Android only provides aligned_alloc when targeting API 28 or higher. -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 0 -# else -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 1 -# endif - # if defined(__APPLE__) || defined(__FreeBSD__) # define _LIBCPP_WCTYPE_IS_MASK # endif @@ -727,6 +518,15 @@ typedef __char32_t char32_t; # define _LIBCPP_DEPRECATED_(m) # endif +// FIXME: using `#warning` causes diagnostics from system headers which include deprecated headers. This can only be +// enabled again once https://github.com/llvm/llvm-project/pull/168041 (or a similar feature) has landed, since that +// allows suppression in system headers. +# if defined(__DEPRECATED) && __DEPRECATED && !defined(_LIBCPP_DISABLE_DEPRECATION_WARNINGS) && 0 +# define _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS 1 +# else +# define _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS 0 +# endif + # if !defined(_LIBCPP_CXX03_LANG) # define _LIBCPP_DEPRECATED_IN_CXX11 _LIBCPP_DEPRECATED # else @@ -771,17 +571,6 @@ typedef __char32_t char32_t; # define _LIBCPP_DEPRECATED_WITH_CHAR8_T # endif -// Macros to enter and leave a state where deprecation warnings are suppressed. -# if defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_COMPILER_GCC) -# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH \ - _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated\"") \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -# define _LIBCPP_SUPPRESS_DEPRECATED_POP _Pragma("GCC diagnostic pop") -# else -# define _LIBCPP_SUPPRESS_DEPRECATED_PUSH -# define _LIBCPP_SUPPRESS_DEPRECATED_POP -# endif - # if _LIBCPP_STD_VER <= 11 # define _LIBCPP_EXPLICIT_SINCE_CXX14 # else @@ -861,18 +650,10 @@ typedef __char32_t char32_t; # endif // _LIBCPP_HAS_THREAD_API # endif // _LIBCPP_HAS_THREADS -# if _LIBCPP_HAS_THREAD_API_PTHREAD -# if defined(__ANDROID__) && __ANDROID_API__ >= 30 -# define _LIBCPP_HAS_COND_CLOCKWAIT 1 -# elif defined(_LIBCPP_GLIBC_PREREQ) -# if _LIBCPP_GLIBC_PREREQ(2, 30) -# define _LIBCPP_HAS_COND_CLOCKWAIT 1 -# else -# define _LIBCPP_HAS_COND_CLOCKWAIT 0 -# endif -# else -# define _LIBCPP_HAS_COND_CLOCKWAIT 0 -# endif +# if !_LIBCPP_HAS_THREAD_API_PTHREAD +# define _LIBCPP_HAS_COND_CLOCKWAIT 0 +# elif (defined(__ANDROID__) && __ANDROID_API__ >= 30) || _LIBCPP_GLIBC_PREREQ(2, 30) +# define _LIBCPP_HAS_COND_CLOCKWAIT 1 # else # define _LIBCPP_HAS_COND_CLOCKWAIT 0 # endif @@ -951,8 +732,8 @@ typedef __char32_t char32_t; # endif # endif -# if defined(__FreeBSD__) && defined(__clang__) && __has_attribute(__no_thread_safety_analysis__) -# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS __attribute__((__no_thread_safety_analysis__)) +# if __has_cpp_attribute(_Clang::__no_thread_safety_analysis__) +# define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS [[_Clang::__no_thread_safety_analysis__]] # else # define _LIBCPP_NO_THREAD_SAFETY_ANALYSIS # endif @@ -1038,12 +819,8 @@ typedef __char32_t char32_t; // the latter depends on internal GNU libc details that are not appropriate // to depend on here, so any declarations present when __cpp_char8_t is not // defined are ignored. -# if defined(_LIBCPP_GLIBC_PREREQ) -# if _LIBCPP_GLIBC_PREREQ(2, 36) && defined(__cpp_char8_t) -# define _LIBCPP_HAS_C8RTOMB_MBRTOC8 1 -# else -# define _LIBCPP_HAS_C8RTOMB_MBRTOC8 0 -# endif +# if _LIBCPP_GLIBC_PREREQ(2, 36) && defined(__cpp_char8_t) +# define _LIBCPP_HAS_C8RTOMB_MBRTOC8 1 # else # define _LIBCPP_HAS_C8RTOMB_MBRTOC8 0 # endif @@ -1067,8 +844,7 @@ typedef __char32_t char32_t; # define _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(_ClassName) static_assert(true, "") # endif -// TODO(LLVM 22): Remove the workaround -# if defined(__OBJC__) && (!defined(_LIBCPP_CLANG_VER) || _LIBCPP_CLANG_VER < 2001) +# if defined(__OBJC__) && defined(_LIBCPP_APPLE_CLANG_VER) # define _LIBCPP_WORKAROUND_OBJCXX_COMPILER_INTRINSICS # endif @@ -1153,12 +929,33 @@ 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 # define _LIBCPP_LIFETIMEBOUND # endif +// This is to work around https://llvm.org/PR156809 +# ifndef _LIBCPP_CXX03_LANG +# define _LIBCPP_CTOR_LIFETIMEBOUND _LIBCPP_LIFETIMEBOUND +# else +# define _LIBCPP_CTOR_LIFETIMEBOUND +# endif + # if __has_cpp_attribute(_Clang::__noescape__) # define _LIBCPP_NOESCAPE [[_Clang::__noescape__]] # else @@ -1172,12 +969,6 @@ typedef __char32_t char32_t; # define _LIBCPP_NO_SPECIALIZATIONS # endif -# if __has_cpp_attribute(_Clang::__standalone_debug__) -# define _LIBCPP_STANDALONE_DEBUG [[_Clang::__standalone_debug__]] -# else -# define _LIBCPP_STANDALONE_DEBUG -# endif - # if __has_cpp_attribute(_Clang::__preferred_name__) # define _LIBCPP_PREFERRED_NAME(x) [[_Clang::__preferred_name__(x)]] # else @@ -1257,14 +1048,6 @@ typedef __char32_t char32_t; # define _LIBCPP_DIAGNOSE_NULLPTR # endif -// TODO(LLVM 22): Remove this macro once LLVM19 support ends. __cpp_explicit_this_parameter has been set in LLVM20. -// Clang-18 has support for deducing this, but it does not set the FTM. -# if defined(__cpp_explicit_this_parameter) || (defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1800) -# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 1 -# else -# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0 -# endif - #endif // __cplusplus #endif // _LIBCPP___CONFIG diff --git a/lib/libcxx/include/__configuration/abi.h b/lib/libcxx/include/__configuration/abi.h @@ -61,19 +61,9 @@ // According to the Standard, `bitset::operator[] const` returns bool # define _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL -// In LLVM 20, we've changed to take these ABI breaks unconditionally. These flags only exist in case someone is running -// into the static_asserts we added to catch the ABI break and don't care that it is one. -// TODO(LLVM 22): Remove these flags -# define _LIBCPP_ABI_LIST_REMOVE_NODE_POINTER_UB -# define _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB -# define _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB -# define _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB - // These flags are documented in ABIGuarantees.rst # define _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT -# define _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON -# define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON -# define _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +# define _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE # define _LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI # define _LIBCPP_ABI_ENABLE_UNIQUE_PTR_TRIVIAL_ABI # define _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION @@ -84,25 +74,16 @@ # define _LIBCPP_ABI_NO_FILESYSTEM_INLINE_NAMESPACE # define _LIBCPP_ABI_NO_ITERATOR_BASES # define _LIBCPP_ABI_NO_RANDOM_DEVICE_COMPATIBILITY_LAYOUT +# define _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER # define _LIBCPP_ABI_OPTIMIZED_FUNCTION # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO # define _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION # define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_ARRAY # define _LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW # define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION +# define _LIBCPP_ABI_TRIVIALLY_COPYABLE_BIT_ITERATOR #elif _LIBCPP_ABI_VERSION == 1 -# if !(defined(_LIBCPP_OBJECT_FORMAT_COFF) || defined(_LIBCPP_OBJECT_FORMAT_XCOFF)) -// Enable compiling copies of now inline methods into the dylib to support -// applications compiled against older libraries. This is unnecessary with -// COFF dllexport semantics, since dllexport forces a non-inline definition -// of inline functions to be emitted anyway. Our own non-inline copy would -// conflict with the dllexport-emitted copy, so we disable it. For XCOFF, -// the linker will take issue with the symbols in the shared object if the -// weak inline methods get visibility (such as from -fvisibility-inlines-hidden), -// so disable it. -# define _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS -# endif // Feature macros for disabling pre ABI v1 features. All of these options // are deprecated. # if defined(__FreeBSD__) @@ -110,11 +91,20 @@ # endif #endif +// TODO(LLVM 22): Remove this check +#if defined(_LIBCPP_ABI_NO_ITERATOR_BASES) && !defined(_LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER) +# ifndef _LIBCPP_ONLY_NO_ITERATOR_BASES +# error "You probably want to define _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER. This has been split out from" \ + " _LIBCPP_ABI_NO_ITERATOR_BASES to allow only removing the second iterator member, since they aren't really related." \ + "If you actually want this ABI configuration, please define _LIBCPP_ONLY_NO_ITERATOR_BASES instead." +# endif +#endif + // We had some bugs where we use [[no_unique_address]] together with construct_at, // which causes UB as the call on construct_at could write to overlapping subobjects // -// https://github.com/llvm/llvm-project/issues/70506 -// https://github.com/llvm/llvm-project/issues/70494 +// https://llvm.org/PR70506 +// https://llvm.org/PR70494 // // To fix the bug we had to change the ABI of some classes to remove [[no_unique_address]] under certain conditions. // The macro below is used for all classes whose ABI have changed as part of fixing these bugs. diff --git a/lib/libcxx/include/__configuration/availability.h b/lib/libcxx/include/__configuration/availability.h @@ -17,62 +17,17 @@ # pragma GCC system_header #endif -// Libc++ is shipped by various vendors. In particular, it is used as a system -// library on macOS, iOS and other Apple platforms. In order for users to be -// able to compile a binary that is intended to be deployed to an older version -// of a platform, Clang provides availability attributes [1]. These attributes -// can be placed on declarations and are used to describe the life cycle of a -// symbol in the library. -// -// The main goal is to ensure a compile-time error if a symbol that hasn't been -// introduced in a previously released library is used in a program that targets -// that previously released library. Normally, this would be a load-time error -// when one tries to launch the program against the older library. -// -// For example, the filesystem library was introduced in the dylib in LLVM 9. -// On Apple platforms, this corresponds to macOS 10.15. If a user compiles on -// a macOS 10.15 host but targets macOS 10.13 with their program, the compiler -// would normally not complain (because the required declarations are in the -// headers), but the dynamic loader would fail to find the symbols when actually -// trying to launch the program on macOS 10.13. To turn this into a compile-time -// issue instead, declarations are annotated with when they were introduced, and -// the compiler can produce a diagnostic if the program references something that -// isn't available on the deployment target. -// -// This mechanism is general in nature, and any vendor can add their markup to -// the library (see below). Whenever a new feature is added that requires support -// in the shared library, two macros are added below to allow marking the feature -// as unavailable: -// 1. A macro named `_LIBCPP_AVAILABILITY_HAS_<feature>` which must be defined -// to `_LIBCPP_INTRODUCED_IN_<version>` for the appropriate LLVM version. -// 2. A macro named `_LIBCPP_AVAILABILITY_<feature>`, which must be defined to -// `_LIBCPP_INTRODUCED_IN_<version>_MARKUP` for the appropriate LLVM version. -// -// When vendors decide to ship the feature as part of their shared library, they -// can update the `_LIBCPP_INTRODUCED_IN_<version>` macro (and the markup counterpart) -// based on the platform version they shipped that version of LLVM in. The library -// will then use this markup to provide an optimal user experience on these platforms. -// -// Furthermore, many features in the standard library have corresponding -// feature-test macros. The `_LIBCPP_AVAILABILITY_HAS_<feature>` macros -// are checked by the corresponding feature-test macros generated by -// generate_feature_test_macro_components.py to ensure that the library -// doesn't announce a feature as being implemented if it is unavailable on -// the deployment target. -// -// Note that this mechanism is disabled by default in the "upstream" libc++. -// Availability annotations are only meaningful when shipping libc++ inside -// a platform (i.e. as a system library), and so vendors that want them should -// turn those annotations on at CMake configuration time. -// -// [1]: https://clang.llvm.org/docs/AttributeReference.html#availability +// This file defines a framework that can be used by vendors to encode the version of an operating system that various +// features of libc++ has been shipped in. This is primarily intended to allow safely deploying an executable built with +// a new version of the library on a platform containing an older version of the built library. +// Detailed documentation for this can be found at https://libcxx.llvm.org/VendorDocumentation.html#availability-markup // Availability markup is disabled when building the library, or when a non-Clang // compiler is used because only Clang supports the necessary attributes. // // We also allow users to force-disable availability markup via the `_LIBCPP_DISABLE_AVAILABILITY` // macro because that is the only way to work around a Clang bug related to availability -// attributes: https://github.com/llvm/llvm-project/issues/134151. +// attributes: https://llvm.org/PR134151. // Once that bug has been fixed, we should remove the macro. #if defined(_LIBCPP_BUILDING_LIBRARY) || defined(_LIBCXXABI_BUILDING_LIBRARY) || \ !defined(_LIBCPP_COMPILER_CLANG_BASED) || defined(_LIBCPP_DISABLE_AVAILABILITY) @@ -84,6 +39,9 @@ // in all versions of the library are available. #if !_LIBCPP_HAS_VENDOR_AVAILABILITY_ANNOTATIONS +# define _LIBCPP_INTRODUCED_IN_LLVM_22 1 +# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE /* nothing */ + # define _LIBCPP_INTRODUCED_IN_LLVM_21 1 # define _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE /* nothing */ @@ -108,32 +66,55 @@ # define _LIBCPP_INTRODUCED_IN_LLVM_12 1 # define _LIBCPP_INTRODUCED_IN_LLVM_12_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE /* nothing */ - -# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH /* nothing */ -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP /* nothing */ - #elif defined(__APPLE__) // clang-format off +// LLVM 22 +// TODO: Fill this in +# define _LIBCPP_INTRODUCED_IN_LLVM_22 0 +# define _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE __attribute__((unavailable)) + // LLVM 21 // TODO: Fill this in # define _LIBCPP_INTRODUCED_IN_LLVM_21 0 # define _LIBCPP_INTRODUCED_IN_LLVM_21_ATTRIBUTE __attribute__((unavailable)) // LLVM 20 -// TODO: Fill this in -# define _LIBCPP_INTRODUCED_IN_LLVM_20 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE __attribute__((unavailable)) +// +// Note that versions for most Apple OSes were bumped forward and aligned in that release. +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 260000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 260000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 260000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 260000) || \ + (defined(__ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__ < 100000) +# define _LIBCPP_INTRODUCED_IN_LLVM_20 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_20 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_20_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 26.0))) \ + __attribute__((availability(ios, strict, introduced = 26.0))) \ + __attribute__((availability(tvos, strict, introduced = 26.0))) \ + __attribute__((availability(watchos, strict, introduced = 26.0))) \ + __attribute__((availability(bridgeos, strict, introduced = 10.0))) // LLVM 19 -// TODO: Fill this in -# define _LIBCPP_INTRODUCED_IN_LLVM_19 0 -# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE __attribute__((unavailable)) +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 150400) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 180400) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 180400) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 110400) || \ + (defined(__ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_BRIDGE_OS_VERSION_MIN_REQUIRED__ < 90400) +# define _LIBCPP_INTRODUCED_IN_LLVM_19 0 +# else +# define _LIBCPP_INTRODUCED_IN_LLVM_19 1 +# endif +# define _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE \ + __attribute__((availability(macos, strict, introduced = 15.4))) \ + __attribute__((availability(ios, strict, introduced = 18.4))) \ + __attribute__((availability(tvos, strict, introduced = 18.4))) \ + __attribute__((availability(watchos, strict, introduced = 11.4))) \ + __attribute__((availability(bridgeos, strict, introduced = 9.4))) // LLVM 18 # if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 150000) || \ @@ -215,47 +196,13 @@ __attribute__((availability(bridgeos, strict, introduced = 6.0))) \ __attribute__((availability(driverkit, strict, introduced = 21.3))) -// LLVM 11 -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 140000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 140000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 70000) -# define _LIBCPP_INTRODUCED_IN_LLVM_11 0 -# else -# define _LIBCPP_INTRODUCED_IN_LLVM_11 1 +# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 110000) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 80000) || \ + (defined(__ENVIRONMENT_DRIVERKIT_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_DRIVERKIT_VERSION_MIN_REQUIRED__ < 200000) +# warning "The selected platform is no longer supported by libc++." # endif -# define _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 11.0))) \ - __attribute__((availability(ios, strict, introduced = 14.0))) \ - __attribute__((availability(tvos, strict, introduced = 14.0))) \ - __attribute__((availability(watchos, strict, introduced = 7.0))) - -// LLVM 9 -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) -# define _LIBCPP_INTRODUCED_IN_LLVM_9 0 -# else -# define _LIBCPP_INTRODUCED_IN_LLVM_9 1 -# endif -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE \ - __attribute__((availability(macos, strict, introduced = 10.15))) \ - __attribute__((availability(ios, strict, introduced = 13.0))) \ - __attribute__((availability(tvos, strict, introduced = 13.0))) \ - __attribute__((availability(watchos, strict, introduced = 6.0))) -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH \ - _Pragma("clang attribute push(__attribute__((availability(macos,strict,introduced=10.15))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(ios,strict,introduced=13.0))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(tvos,strict,introduced=13.0))), apply_to=any(function,record))") \ - _Pragma("clang attribute push(__attribute__((availability(watchos,strict,introduced=6.0))), apply_to=any(function,record))") -# define _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") \ - _Pragma("clang attribute pop") - -// clang-format on #else @@ -266,19 +213,12 @@ #endif -// These macros control the availability of all parts of <filesystem> that -// depend on something in the dylib. -#define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY _LIBCPP_INTRODUCED_IN_LLVM_9 -#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE -#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_PUSH -#define _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP _LIBCPP_INTRODUCED_IN_LLVM_9_ATTRIBUTE_POP - -// This controls the availability of the C++20 synchronization library, -// which requires shared library support for various operations -// (see libcxx/src/atomic.cpp). This includes <barier>, <latch>, -// <semaphore>, and notification functions on std::atomic. -#define _LIBCPP_AVAILABILITY_HAS_SYNC _LIBCPP_INTRODUCED_IN_LLVM_11 -#define _LIBCPP_AVAILABILITY_SYNC _LIBCPP_INTRODUCED_IN_LLVM_11_ATTRIBUTE +// This controls the availability of new implementation of std::atomic's +// wait, notify_one and notify_all. The new implementation uses +// the native atomic wait/notify operations on platforms that support them +// based on the size of the atomic type, instead of the type itself. +#define _LIBCPP_AVAILABILITY_HAS_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22 +#define _LIBCPP_AVAILABILITY_NEW_SYNC _LIBCPP_INTRODUCED_IN_LLVM_22_ATTRIBUTE // Enable additional explicit instantiations of iostreams components. This // reduces the number of weak definitions generated in programs that use @@ -307,7 +247,7 @@ // This controls the availability of the C++17 std::pmr library, // which is implemented in large part in the built library. // -// TODO: Enable std::pmr markup once https://github.com/llvm/llvm-project/issues/40340 has been fixed +// TODO: Enable std::pmr markup once https://llvm.org/PR40340 has been fixed // Until then, it is possible for folks to try to use `std::pmr` when back-deploying to targets that don't support // it and it'll be a load-time error, but we don't have a good alternative because the library won't compile if we // use availability annotations until that bug has been fixed. @@ -364,4 +304,11 @@ # define _LIBCPP_AVAILABILITY_INIT_PRIMARY_EXCEPTION #endif +// Only define a bunch of symbols in the dylib if we need to be compatible with LLVM 7 headers or older +# if defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 8 +# define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 +# else +# define _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 _LIBCPP_HIDE_FROM_ABI +# endif + #endif // _LIBCPP___CONFIGURATION_AVAILABILITY_H diff --git a/lib/libcxx/include/__configuration/compiler.h b/lib/libcxx/include/__configuration/compiler.h @@ -33,16 +33,16 @@ // Warn if a compiler version is used that is not supported anymore // LLVM RELEASE Update the minimum compiler versions # if defined(_LIBCPP_CLANG_VER) -# if _LIBCPP_CLANG_VER < 1900 -# warning "Libc++ only supports Clang 19 and later" +# if _LIBCPP_CLANG_VER < 2001 +# warning "Libc++ only supports Clang 20 and later" # endif # elif defined(_LIBCPP_APPLE_CLANG_VER) -# if _LIBCPP_APPLE_CLANG_VER < 1500 -# warning "Libc++ only supports AppleClang 15 and later" +# if _LIBCPP_APPLE_CLANG_VER < 1700 +# warning "Libc++ only supports AppleClang 26 and later" # endif # elif defined(_LIBCPP_GCC_VER) -# if _LIBCPP_GCC_VER < 1400 -# warning "Libc++ only supports GCC 14 and later" +# if _LIBCPP_GCC_VER < 1500 +# warning "Libc++ only supports GCC 15 and later" # endif # endif diff --git a/lib/libcxx/include/__configuration/experimental.h b/lib/libcxx/include/__configuration/experimental.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___CONFIGURATION_EXPERIMENTAL_H +#define _LIBCPP___CONFIGURATION_EXPERIMENTAL_H + +/* zig patch: instead of including __config_site, zig adds -D flags when compiling */ + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#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 +#define _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR _LIBCPP_HAS_EXPERIMENTAL_LIBRARY + +#endif // _LIBCPP___CONFIGURATION_EXPERIMENTAL_H diff --git a/lib/libcxx/include/__configuration/hardening.h b/lib/libcxx/include/__configuration/hardening.h @@ -0,0 +1,215 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___CONFIGURATION_HARDENING_H +#define _LIBCPP___CONFIGURATION_HARDENING_H + +/* zig patch: instead of including __config_site, zig adds -D flags when compiling */ +#include <__configuration/experimental.h> +#include <__configuration/language.h> + +#ifndef _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +# pragma GCC system_header +#endif + +// TODO(LLVM 23): Remove this. We're making these an error to catch folks who might not have migrated. +// Since hardening went through several changes (many of which impacted user-facing macros), +// we're keeping these checks around for a bit longer than usual. Failure to properly configure +// hardening results in checks being dropped silently, which is a pretty big deal. +#if defined(_LIBCPP_ENABLE_ASSERTIONS) +# error "_LIBCPP_ENABLE_ASSERTIONS has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_HARDENED_MODE) +# error "_LIBCPP_ENABLE_HARDENED_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_SAFE_MODE) +# error "_LIBCPP_ENABLE_SAFE_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +#endif +#if defined(_LIBCPP_ENABLE_DEBUG_MODE) +# error "_LIBCPP_ENABLE_DEBUG_MODE has been removed, please use _LIBCPP_HARDENING_MODE=<mode> instead (see docs)" +#endif + +// The library provides the macro `_LIBCPP_HARDENING_MODE` which can be set to one of the following values: +// +// - `_LIBCPP_HARDENING_MODE_NONE`; +// - `_LIBCPP_HARDENING_MODE_FAST`; +// - `_LIBCPP_HARDENING_MODE_EXTENSIVE`; +// - `_LIBCPP_HARDENING_MODE_DEBUG`. +// +// These values have the following effects: +// +// - `_LIBCPP_HARDENING_MODE_NONE` -- sets the hardening mode to "none" which disables all runtime hardening checks; +// +// - `_LIBCPP_HARDENING_MODE_FAST` -- sets that hardening mode to "fast". The fast mode enables security-critical checks +// that can be done with relatively little runtime overhead in constant time; +// +// - `_LIBCPP_HARDENING_MODE_EXTENSIVE` -- sets the hardening mode to "extensive". The extensive mode is a superset of +// the fast mode that additionally enables checks that are relatively cheap and prevent common types of logic errors +// but are not necessarily security-critical; +// +// - `_LIBCPP_HARDENING_MODE_DEBUG` -- sets the hardening mode to "debug". The debug mode is a superset of the extensive +// mode and enables all checks available in the library, including internal assertions. Checks that are part of the +// debug mode can be very expensive and thus the debug mode is intended to be used for testing, not in production. + +// Inside the library, assertions are categorized so they can be cherry-picked based on the chosen hardening mode. These +// macros are only for internal use -- users should only pick one of the high-level hardening modes described above. +// +// - `_LIBCPP_ASSERT_VALID_INPUT_RANGE` -- checks that ranges (whether expressed as an iterator pair, an iterator and +// a sentinel, an iterator and a count, or a `std::range`) given as input to library functions are valid: +// - the sentinel is reachable from the begin iterator; +// - TODO(hardening): both iterators refer to the same container. +// +// - `_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS` -- checks that any attempts to access a container element, whether through +// the container object or through an iterator, are valid and do not attempt to go out of bounds or otherwise access +// a non-existent element. For iterator checks to work, bounded iterators must be enabled in the ABI. Types like +// `optional` and `function` are considered one-element containers for the purposes of this check. +// +// - `_LIBCPP_ASSERT_NON_NULL` -- checks that the pointer being dereferenced is not null. On most modern platforms zero +// address does not refer to an actual location in memory, so a null pointer dereference would not compromize the +// memory security of a program (however, it is still undefined behavior that can result in strange errors due to +// compiler optimizations). +// +// - `_LIBCPP_ASSERT_NON_OVERLAPPING_RANGES` -- for functions that take several ranges as arguments, checks that the +// given ranges do not overlap. +// +// - `_LIBCPP_ASSERT_VALID_DEALLOCATION` -- checks that an attempt to deallocate memory is valid (e.g. the given object +// was allocated by the given allocator). Violating this category typically results in a memory leak. +// +// - `_LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL` -- checks that a call to an external API doesn't fail in +// an unexpected manner. This includes triggering documented cases of undefined behavior in an external library (like +// attempting to unlock an unlocked mutex in pthreads). Any API external to the library falls under this category +// (from system calls to compiler intrinsics). We generally don't expect these failures to compromize memory safety or +// otherwise create an immediate security issue. +// +// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure +// the containers have compatible allocators. +// +// - `_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN` -- checks that the given argument is within the domain of valid arguments +// for the function. Violating this typically produces an incorrect result (e.g. the clamp algorithm returns the +// original value without clamping it due to incorrect functors) or puts an object into an invalid state (e.g. +// a string view where only a subset of elements is possible to access). This category is for assertions violating +// which doesn't cause any immediate issues in the library -- whatever the consequences are, they will happen in the +// user code. +// +// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to +// be benign in our implementation. +// +// - `_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT` -- checks that the given argument satisfies the semantic requirements imposed +// by the Standard. Typically, there is no simple way to completely prove that a semantic requirement is satisfied; +// thus, this would often be a heuristic check and it might be quite expensive. +// +// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on +// user input. +// +// - `_LIBCPP_ASSERT_UNCATEGORIZED` -- for assertions that haven't been properly classified yet. + +// clang-format off +# define _LIBCPP_HARDENING_MODE_NONE (1 << 1) +# define _LIBCPP_HARDENING_MODE_FAST (1 << 2) +# define _LIBCPP_HARDENING_MODE_EXTENSIVE (1 << 4) // Deliberately not ordered. +# define _LIBCPP_HARDENING_MODE_DEBUG (1 << 3) +// clang-format on + +#ifndef _LIBCPP_HARDENING_MODE + +# ifndef _LIBCPP_HARDENING_MODE_DEFAULT +# error _LIBCPP_HARDENING_MODE_DEFAULT is not defined. This definition should be set at configuration time in the \ +`__config_site` header, please make sure your installation of libc++ is not broken. +# endif + +# define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEFAULT +#endif + +#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_NONE && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_FAST && \ + _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \ + _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG +# error _LIBCPP_HARDENING_MODE must be set to one of the following values: \ +_LIBCPP_HARDENING_MODE_NONE, \ +_LIBCPP_HARDENING_MODE_FAST, \ +_LIBCPP_HARDENING_MODE_EXTENSIVE, \ +_LIBCPP_HARDENING_MODE_DEBUG +#endif + +// The library provides the macro `_LIBCPP_ASSERTION_SEMANTIC` for configuring the assertion semantic used by hardening; +// it can 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`. +// +// libc++ 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. +// +// Additionally, a special `hardening-dependent` value selects the assertion semantic based on the hardening mode in +// effect: the production-capable modes (`fast` and `extensive`) map to `quick_enforce` and the `debug` mode maps to +// `enforce`. The `hardening-dependent` semantic cannot be selected explicitly, it is only used when no assertion +// semantic is provided by the user _and_ the library's default semantic is configured to be dependent on hardening. +// +// 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_HARDENING_DEPENDENT (1 << 1) +# define _LIBCPP_ASSERTION_SEMANTIC_IGNORE (1 << 2) +# define _LIBCPP_ASSERTION_SEMANTIC_OBSERVE (1 << 3) +# define _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE (1 << 4) +# define _LIBCPP_ASSERTION_SEMANTIC_ENFORCE (1 << 5) +// clang-format on + +// If the user attempts to configure the assertion semantic, check that it is allowed in the current environment. +#if defined(_LIBCPP_ASSERTION_SEMANTIC) +# 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 // defined(_LIBCPP_ASSERTION_SEMANTIC) + +// User-provided semantic takes top priority -- don't override if set. +#ifndef _LIBCPP_ASSERTION_SEMANTIC + +# ifndef _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# error _LIBCPP_ASSERTION_SEMANTIC_DEFAULT is not defined. This definition should be set at configuration time in \ +the `__config_site` header, please make sure your installation of libc++ is not broken. +# endif + +# if _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT +# define _LIBCPP_ASSERTION_SEMANTIC _LIBCPP_ASSERTION_SEMANTIC_DEFAULT +# else +# 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 +# endif // _LIBCPP_ASSERTION_SEMANTIC_DEFAULT != _LIBCPP_ASSERTION_SEMANTIC_HARDENING_DEPENDENT + +#endif // #ifndef _LIBCPP_ASSERTION_SEMANTIC + +// Finally, validate the selected semantic (in case the user tries setting it to an incorrect value): +#if _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_IGNORE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_OBSERVE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_QUICK_ENFORCE && \ + _LIBCPP_ASSERTION_SEMANTIC != _LIBCPP_ASSERTION_SEMANTIC_ENFORCE +# 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 + +#endif // _LIBCPP___CONFIGURATION_HARDENING_H diff --git a/lib/libcxx/include/__configuration/language.h b/lib/libcxx/include/__configuration/language.h @@ -18,6 +18,9 @@ // NOLINTBEGIN(libcpp-cpp-version-check) #ifdef __cplusplus +# if __cplusplus < 201103L +# define _LIBCPP_CXX03_LANG +# endif # if __cplusplus <= 201103L # define _LIBCPP_STD_VER 11 # elif __cplusplus <= 201402L diff --git a/lib/libcxx/include/__configuration/platform.h b/lib/libcxx/include/__configuration/platform.h @@ -31,22 +31,15 @@ #endif // Need to detect which libc we're using if we're on Linux. -#if defined(__linux__) || defined(__AMDGPU__) || defined(__NVPTX__) -# if __has_include(<features.h>) -# include <features.h> -# if defined(__GLIBC_PREREQ) -# define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) -# else -# define _LIBCPP_GLIBC_PREREQ(a, b) 0 -# endif // defined(__GLIBC_PREREQ) -# endif -#endif - -// This is required in order for _NEWLIB_VERSION to be defined in places where we use it. -// TODO: We shouldn't be including arbitrarily-named headers from libc++ since this can break valid -// user code. Move code paths that need _NEWLIB_VERSION to another customization mechanism. -#if __has_include(<picolibc.h>) -# include <picolibc.h> +#if (defined(__linux__) || defined(__AMDGPU__) || defined(__NVPTX__)) && __has_include(<features.h>) +# include <features.h> +# if defined(__GLIBC_PREREQ) +# define _LIBCPP_GLIBC_PREREQ(a, b) __GLIBC_PREREQ(a, b) +# else +# define _LIBCPP_GLIBC_PREREQ(a, b) 0 +# endif // defined(__GLIBC_PREREQ) +#else +# define _LIBCPP_GLIBC_PREREQ(a, b) 0 #endif #ifndef __BYTE_ORDER__ diff --git a/lib/libcxx/include/__coroutine/coroutine_handle.h b/lib/libcxx/include/__coroutine/coroutine_handle.h @@ -44,9 +44,9 @@ public: } // [coroutine.handle.export.import], export/import - _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } - _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __addr; return __tmp; @@ -55,7 +55,7 @@ public: // [coroutine.handle.observers], observers _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; } - _LIBCPP_HIDE_FROM_ABI bool done() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool done() const { _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines"); return __builtin_coro_done(__handle_); } @@ -100,7 +100,7 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr coroutine_handle(nullptr_t) noexcept {} - _LIBCPP_HIDE_FROM_ABI static coroutine_handle from_promise(_Promise& __promise) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static coroutine_handle from_promise(_Promise& __promise) { using _RawPromise = __remove_cv_t<_Promise>; coroutine_handle __tmp; __tmp.__handle_ = @@ -114,9 +114,9 @@ public: } // [coroutine.handle.export.import], export/import - _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } - _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr coroutine_handle from_address(void* __addr) noexcept { coroutine_handle __tmp; __tmp.__handle_ = __addr; return __tmp; @@ -130,7 +130,7 @@ public: // [coroutine.handle.observers], observers _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return __handle_ != nullptr; } - _LIBCPP_HIDE_FROM_ABI bool done() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool done() const { _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(__is_suspended(), "done() can be called only on suspended coroutines"); return __builtin_coro_done(__handle_); } @@ -150,7 +150,7 @@ public: } // [coroutine.handle.promise], promise access - _LIBCPP_HIDE_FROM_ABI _Promise& promise() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Promise& promise() const { return *static_cast<_Promise*>(__builtin_coro_promise(this->__handle_, alignof(_Promise), false)); } @@ -165,7 +165,7 @@ private: // [coroutine.handle.hash] template <class _Tp> struct hash<coroutine_handle<_Tp>> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const coroutine_handle<_Tp>& __v) const noexcept { return hash<void*>()(__v.address()); } }; diff --git a/lib/libcxx/include/__coroutine/noop_coroutine_handle.h b/lib/libcxx/include/__coroutine/noop_coroutine_handle.h @@ -20,8 +20,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD -# if __has_builtin(__builtin_coro_noop) || defined(_LIBCPP_COMPILER_GCC) - // [coroutine.noop] // [coroutine.promise.noop] struct noop_coroutine_promise {}; @@ -37,7 +35,7 @@ public: // [coroutine.handle.noop.observers], observers _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return true; } - _LIBCPP_HIDE_FROM_ABI constexpr bool done() const noexcept { return false; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool done() const noexcept { return false; } // [coroutine.handle.noop.resumption], resumption _LIBCPP_HIDE_FROM_ABI constexpr void operator()() const noexcept {} @@ -45,23 +43,23 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr void destroy() const noexcept {} // [coroutine.handle.noop.promise], promise access - _LIBCPP_HIDE_FROM_ABI noop_coroutine_promise& promise() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI noop_coroutine_promise& promise() const noexcept { return *static_cast<noop_coroutine_promise*>( __builtin_coro_promise(this->__handle_, alignof(noop_coroutine_promise), false)); } // [coroutine.handle.noop.address], address - _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr void* address() const noexcept { return __handle_; } private: _LIBCPP_HIDE_FROM_ABI friend coroutine_handle<noop_coroutine_promise> noop_coroutine() noexcept; -# if __has_builtin(__builtin_coro_noop) +# if __has_builtin(__builtin_coro_noop) _LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept { this->__handle_ = __builtin_coro_noop(); } void* __handle_ = nullptr; -# elif defined(_LIBCPP_COMPILER_GCC) +# elif defined(_LIBCPP_COMPILER_GCC) // GCC doesn't implement __builtin_coro_noop(). // Construct the coroutine frame manually instead. struct __noop_coroutine_frame_ty_ { @@ -78,19 +76,19 @@ private: _LIBCPP_HIDE_FROM_ABI coroutine_handle() noexcept = default; -# endif // __has_builtin(__builtin_coro_noop) +# endif // __has_builtin(__builtin_coro_noop) }; using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>; -# if defined(_LIBCPP_COMPILER_GCC) +# if defined(_LIBCPP_COMPILER_GCC) inline noop_coroutine_handle::__noop_coroutine_frame_ty_ noop_coroutine_handle::__noop_coroutine_frame_{}; -# endif +# endif // [coroutine.noop.coroutine] -inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept { return noop_coroutine_handle(); } - -# endif // __has_builtin(__builtin_coro_noop) || defined(_LIBCPP_COMPILER_GCC) +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI noop_coroutine_handle noop_coroutine() noexcept { + return noop_coroutine_handle(); +} _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__debug_utils/strict_weak_ordering_check.h b/lib/libcxx/include/__debug_utils/strict_weak_ordering_check.h @@ -27,7 +27,7 @@ template <class _RandomAccessIterator, class _Comp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __check_strict_weak_ordering_sorted(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) { #if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG - using __diff_t = __iter_diff_t<_RandomAccessIterator>; + using __diff_t = __iterator_difference_type<_RandomAccessIterator>; using _Comp_ref = __comp_ref_type<_Comp>; if (!__libcpp_is_constant_evaluated()) { // Check if the range is actually sorted. diff --git a/lib/libcxx/include/__exception/exception.h b/lib/libcxx/include/__exception/exception.h @@ -48,13 +48,15 @@ public: __data_._DoFree = true; } - exception(exception const&) _NOEXCEPT {} + exception(exception const&) _NOEXCEPT : __data_() {} exception& operator=(exception const&) _NOEXCEPT { return *this; } virtual ~exception() _NOEXCEPT {} - virtual char const* what() const _NOEXCEPT { return __data_._What ? __data_._What : "Unknown exception"; } + [[__nodiscard__]] virtual char const* what() const _NOEXCEPT { + return __data_._What ? __data_._What : "Unknown exception"; + } private: __std_exception_data __data_; @@ -76,7 +78,7 @@ public: _LIBCPP_HIDE_FROM_ABI exception& operator=(const exception&) _NOEXCEPT = default; virtual ~exception() _NOEXCEPT; - virtual const char* what() const _NOEXCEPT; + [[__nodiscard__]] virtual const char* what() const _NOEXCEPT; }; class _LIBCPP_EXPORTED_FROM_ABI bad_exception : public exception { @@ -85,7 +87,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_exception(const bad_exception&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_exception& operator=(const bad_exception&) _NOEXCEPT = default; ~bad_exception() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; #endif // !_LIBCPP_ABI_VCRUNTIME diff --git a/lib/libcxx/include/__exception/exception_ptr.h b/lib/libcxx/include/__exception/exception_ptr.h @@ -11,18 +11,24 @@ #include <__config> #include <__cstddef/nullptr_t.h> +#include <__cstddef/size_t.h> #include <__exception/operations.h> #include <__memory/addressof.h> #include <__memory/construct_at.h> #include <__type_traits/decay.h> #include <__type_traits/is_pointer.h> -#include <cstdlib> +#include <__utility/move.h> +#include <__utility/swap.h> +#include <__verbose_abort> #include <typeinfo> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + #ifndef _LIBCPP_ABI_MICROSOFT # if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION @@ -30,7 +36,7 @@ namespace __cxxabiv1 { extern "C" { -_LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_allocate_exception(size_t) throw(); +_LIBCPP_OVERRIDABLE_FUNC_VIS void* __cxa_allocate_exception(std::size_t) throw(); _LIBCPP_OVERRIDABLE_FUNC_VIS void __cxa_free_exception(void*) throw(); struct __cxa_exception; @@ -57,6 +63,8 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD #ifndef _LIBCPP_ABI_MICROSOFT +inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT; + class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { void* __ptr_; @@ -67,15 +75,21 @@ class _LIBCPP_EXPORTED_FROM_ABI exception_ptr { public: // exception_ptr is basically a COW string so it is trivially relocatable. - // It is also replaceable because assignment has normal value semantics. using __trivially_relocatable _LIBCPP_NODEBUG = exception_ptr; - using __replaceable _LIBCPP_NODEBUG = exception_ptr; _LIBCPP_HIDE_FROM_ABI exception_ptr() _NOEXCEPT : __ptr_() {} _LIBCPP_HIDE_FROM_ABI exception_ptr(nullptr_t) _NOEXCEPT : __ptr_() {} exception_ptr(const exception_ptr&) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI exception_ptr(exception_ptr&& __other) _NOEXCEPT : __ptr_(__other.__ptr_) { + __other.__ptr_ = nullptr; + } exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI exception_ptr& operator=(exception_ptr&& __other) _NOEXCEPT { + exception_ptr __tmp(std::move(__other)); + std::swap(__tmp, *this); + return *this; + } ~exception_ptr() _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __ptr_ != nullptr; } @@ -88,10 +102,16 @@ public: return !(__x == __y); } + friend _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT; + friend _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; friend _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr); }; +inline _LIBCPP_HIDE_FROM_ABI void swap(exception_ptr& __x, exception_ptr& __y) _NOEXCEPT { + std::swap(__x.__ptr_, __y.__ptr_); +} + # if _LIBCPP_HAS_EXCEPTIONS # if _LIBCPP_AVAILABILITY_HAS_INIT_PRIMARY_EXCEPTION template <class _Ep> @@ -153,7 +173,7 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { # else // !_LIBCPP_HAS_EXCEPTIONS template <class _Ep> _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep) _NOEXCEPT { - std::abort(); + _LIBCPP_VERBOSE_ABORT("make_exception_ptr was called in -fno-exceptions mode"); } # endif // _LIBCPP_HAS_EXCEPTIONS @@ -201,4 +221,6 @@ _LIBCPP_HIDE_FROM_ABI exception_ptr make_exception_ptr(_Ep __e) _NOEXCEPT { #endif // _LIBCPP_ABI_MICROSOFT _LIBCPP_END_UNVERSIONED_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___EXCEPTION_EXCEPTION_PTR_H diff --git a/lib/libcxx/include/__exception/nested_exception.h b/lib/libcxx/include/__exception/nested_exception.h @@ -40,7 +40,7 @@ public: // access functions [[__noreturn__]] void rethrow_nested() const; - _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI exception_ptr nested_ptr() const _NOEXCEPT { return __ptr_; } }; template <class _Tp> @@ -73,7 +73,7 @@ template <class _Tp> __throw_with_nested<_Tp, _Up, is_class<_Up>::value && !is_base_of<nested_exception, _Up>::value && - !__libcpp_is_final<_Up>::value>::__do_throw(std::forward<_Tp>(__t)); + !__is_final_v<_Up> >::__do_throw(std::forward<_Tp>(__t)); #else ((void)__t); // FIXME: Make this abort diff --git a/lib/libcxx/include/__exception/operations.h b/lib/libcxx/include/__exception/operations.h @@ -20,22 +20,22 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD defined(_LIBCPP_BUILDING_LIBRARY) using unexpected_handler = void (*)(); _LIBCPP_EXPORTED_FROM_ABI unexpected_handler set_unexpected(unexpected_handler) _NOEXCEPT; -_LIBCPP_EXPORTED_FROM_ABI unexpected_handler get_unexpected() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unexpected_handler get_unexpected() _NOEXCEPT; [[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void unexpected(); #endif using terminate_handler = void (*)(); _LIBCPP_EXPORTED_FROM_ABI terminate_handler set_terminate(terminate_handler) _NOEXCEPT; -_LIBCPP_EXPORTED_FROM_ABI terminate_handler get_terminate() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI terminate_handler get_terminate() _NOEXCEPT; #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION) -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 bool uncaught_exception() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX17 bool uncaught_exception() _NOEXCEPT; #endif // _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION) -_LIBCPP_EXPORTED_FROM_ABI int uncaught_exceptions() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int uncaught_exceptions() _NOEXCEPT; class _LIBCPP_EXPORTED_FROM_ABI exception_ptr; -_LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI exception_ptr current_exception() _NOEXCEPT; [[__noreturn__]] _LIBCPP_EXPORTED_FROM_ABI void rethrow_exception(exception_ptr); _LIBCPP_END_UNVERSIONED_NAMESPACE_STD diff --git a/lib/libcxx/include/__expected/bad_expected_access.h b/lib/libcxx/include/__expected/bad_expected_access.h @@ -43,9 +43,11 @@ protected: public: # if _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION - const char* what() const noexcept override; + [[nodiscard]] const char* what() const noexcept override; # else - _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override { return "bad access to std::expected"; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override { + return "bad access to std::expected"; + } # endif }; _LIBCPP_DIAGNOSTIC_POP @@ -55,10 +57,10 @@ class bad_expected_access : public bad_expected_access<void> { public: _LIBCPP_HIDE_FROM_ABI explicit bad_expected_access(_Err __e) : __unex_(std::move(__e)) {} - _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; } - _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; } - _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); } - _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Err& error() & noexcept { return __unex_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const _Err& error() const& noexcept { return __unex_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Err&& error() && noexcept { return std::move(__unex_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const _Err&& error() const&& noexcept { return std::move(__unex_); } private: _Err __unex_; diff --git a/lib/libcxx/include/__expected/expected.h b/lib/libcxx/include/__expected/expected.h @@ -30,7 +30,6 @@ #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_reference.h> -#include <__type_traits/is_replaceable.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_constructible.h> @@ -472,8 +471,6 @@ public: __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value && __libcpp_is_trivially_relocatable<_Err>::value, expected, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<_Tp> && __is_replaceable_v<_Err>, expected, void>; template <class _Up> using rebind = expected<_Up, error_type>; @@ -555,9 +552,10 @@ public: is_nothrow_constructible_v<_Tp, _Up> && is_nothrow_constructible_v<_Err, _OtherErr>) // strengthened : __base(__other.__has_val(), std::move(__other.__union())) {} - template <class _Up = _Tp> + template <class _Up = remove_cv_t<_Tp>> requires(!is_same_v<remove_cvref_t<_Up>, in_place_t> && !is_same_v<expected, remove_cvref_t<_Up>> && - is_constructible_v<_Tp, _Up> && !__is_std_unexpected<remove_cvref_t<_Up>>::value && + !is_same_v<remove_cvref_t<_Up>, unexpect_t> && is_constructible_v<_Tp, _Up> && + !__is_std_unexpected<remove_cvref_t<_Up>>::value && (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_expected<remove_cvref_t<_Up>>::value)) _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up, _Tp>) expected(_Up&& __u) noexcept(is_nothrow_constructible_v<_Tp, _Up>) // strengthened @@ -668,7 +666,7 @@ public: return *this; } - template <class _Up = _Tp> + template <class _Up = remove_cv_t<_Tp>> _LIBCPP_HIDE_FROM_ABI constexpr expected& operator=(_Up&& __v) requires(!is_same_v<expected, remove_cvref_t<_Up>> && !__is_std_unexpected<remove_cvref_t<_Up>>::value && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> && @@ -800,25 +798,25 @@ public: return std::addressof(this->__val()); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( this->__has_val(), "expected::operator* requires the expected to contain a value"); return this->__val(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( this->__has_val(), "expected::operator* requires the expected to contain a value"); return this->__val(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( this->__has_val(), "expected::operator* requires the expected to contain a value"); return std::move(this->__val()); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( this->__has_val(), "expected::operator* requires the expected to contain a value"); return std::move(this->__val()); @@ -826,9 +824,9 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); } - _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& value() const& { static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); if (!this->__has_val()) { std::__throw_bad_expected_access<_Err>(std::as_const(error())); @@ -836,7 +834,7 @@ public: return this->__val(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & { static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); if (!this->__has_val()) { std::__throw_bad_expected_access<_Err>(std::as_const(error())); @@ -844,7 +842,7 @@ public: return this->__val(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& value() const&& { static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>, "error_type has to be both copy constructible and constructible from decltype(std::move(error()))"); if (!this->__has_val()) { @@ -853,7 +851,7 @@ public: return std::move(this->__val()); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && { static_assert(is_copy_constructible_v<_Err> && is_constructible_v<_Err, decltype(std::move(error()))>, "error_type has to be both copy constructible and constructible from decltype(std::move(error()))"); if (!this->__has_val()) { @@ -862,46 +860,46 @@ public: return std::move(this->__val()); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return this->__unex(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return this->__unex(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return std::move(this->__unex()); } - _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return std::move(this->__unex()); } - template <class _Up> - _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { + template <class _Up = remove_cv_t<_Tp>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { static_assert(is_copy_constructible_v<_Tp>, "value_type has to be copy constructible"); static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); return this->__has_val() ? this->__val() : static_cast<_Tp>(std::forward<_Up>(__v)); } - template <class _Up> - _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { + template <class _Up = remove_cv_t<_Tp>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { static_assert(is_move_constructible_v<_Tp>, "value_type has to be move constructible"); static_assert(is_convertible_v<_Up, _Tp>, "argument has to be convertible to value_type"); return this->__has_val() ? std::move(this->__val()) : static_cast<_Tp>(std::forward<_Up>(__v)); } template <class _Up = _Err> - _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); if (has_value()) @@ -910,7 +908,7 @@ public: } template <class _Up = _Err> - _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); if (has_value()) @@ -921,7 +919,7 @@ public: // [expected.void.monadic], monadic template <class _Func> requires is_constructible_v<_Err, _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>; static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Up::error_type, _Err>, @@ -934,7 +932,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&>>; static_assert(__is_std_expected<_Up>::value, "The result of f(value()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Up::error_type, _Err>, @@ -947,7 +945,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&&>>; static_assert( __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected"); @@ -961,7 +959,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>; static_assert( __is_std_expected<_Up>::value, "The result of f(std::move(value())) must be a specialization of std::expected"); @@ -975,7 +973,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, _Tp&> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>; static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Gp::value_type, _Tp>, @@ -988,7 +986,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, const _Tp&> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>; static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Gp::value_type, _Tp>, @@ -1001,7 +999,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, _Tp&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>; static_assert( __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); @@ -1015,7 +1013,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, const _Tp&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>; static_assert( __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); @@ -1029,7 +1027,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, error()); @@ -1045,7 +1043,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, error()); @@ -1061,7 +1059,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, std::move(error())); @@ -1077,7 +1075,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, std::move(error())); @@ -1093,7 +1091,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, _Tp&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(error()) must be a valid template argument for unexpected"); @@ -1105,7 +1103,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, const _Tp&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(error()) must be a valid template argument for unexpected"); @@ -1117,7 +1115,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, _Tp&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(std::move(error())) must be a valid template argument for unexpected"); @@ -1130,7 +1128,7 @@ public: template <class _Func> requires is_constructible_v<_Tp, const _Tp&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(std::move(error())) must be a valid template argument for unexpected"); @@ -1597,7 +1595,7 @@ public: // [expected.void.obs], observers _LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return this->__has_val(); } - _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__has_val(); } _LIBCPP_HIDE_FROM_ABI constexpr void operator*() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( @@ -1618,32 +1616,32 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return this->__unex(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return this->__unex(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return std::move(this->__unex()); } - _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( !this->__has_val(), "expected::error requires the expected to contain an error"); return std::move(this->__unex()); } template <class _Up = _Err> - _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) const& { static_assert(is_copy_constructible_v<_Err>, "error_type has to be copy constructible"); static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); if (has_value()) { @@ -1653,7 +1651,7 @@ public: } template <class _Up = _Err> - _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err error_or(_Up&& __error) && { static_assert(is_move_constructible_v<_Err>, "error_type has to be move constructible"); static_assert(is_convertible_v<_Up, _Err>, "argument has to be convertible to error_type"); if (has_value()) { @@ -1665,7 +1663,7 @@ public: // [expected.void.monadic], monadic template <class _Func> requires is_constructible_v<_Err, _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { using _Up = remove_cvref_t<invoke_result_t<_Func>>; static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); static_assert( @@ -1678,7 +1676,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { using _Up = remove_cvref_t<invoke_result_t<_Func>>; static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); static_assert( @@ -1691,7 +1689,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { using _Up = remove_cvref_t<invoke_result_t<_Func>>; static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); static_assert( @@ -1704,7 +1702,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { using _Up = remove_cvref_t<invoke_result_t<_Func>>; static_assert(__is_std_expected<_Up>::value, "The result of f() must be a specialization of std::expected"); static_assert( @@ -1716,7 +1714,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) & { using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&>>; static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Gp::value_type, _Tp>, @@ -1728,7 +1726,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const& { using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&>>; static_assert(__is_std_expected<_Gp>::value, "The result of f(error()) must be a specialization of std::expected"); static_assert(is_same_v<typename _Gp::value_type, _Tp>, @@ -1740,7 +1738,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) && { using _Gp = remove_cvref_t<invoke_result_t<_Func, _Err&&>>; static_assert( __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); @@ -1753,7 +1751,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto or_else(_Func&& __f) const&& { using _Gp = remove_cvref_t<invoke_result_t<_Func, const _Err&&>>; static_assert( __is_std_expected<_Gp>::value, "The result of f(std::move(error())) must be a specialization of std::expected"); @@ -1767,7 +1765,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { using _Up = remove_cv_t<invoke_result_t<_Func>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, error()); @@ -1782,7 +1780,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { using _Up = remove_cv_t<invoke_result_t<_Func>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, error()); @@ -1797,7 +1795,7 @@ public: template <class _Func> requires is_constructible_v<_Err, _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { using _Up = remove_cv_t<invoke_result_t<_Func>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, std::move(error())); @@ -1812,7 +1810,7 @@ public: template <class _Func> requires is_constructible_v<_Err, const _Err&&> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { using _Up = remove_cv_t<invoke_result_t<_Func>>; if (!has_value()) { return expected<_Up, _Err>(unexpect, std::move(error())); @@ -1826,7 +1824,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) & { using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(error()) must be a valid template argument for unexpected"); @@ -1837,7 +1835,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const& { using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(error()) must be a valid template argument for unexpected"); @@ -1848,7 +1846,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) && { using _Gp = remove_cv_t<invoke_result_t<_Func, _Err&&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(std::move(error())) must be a valid template argument for unexpected"); @@ -1860,7 +1858,7 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform_error(_Func&& __f) const&& { using _Gp = remove_cv_t<invoke_result_t<_Func, const _Err&&>>; static_assert(__valid_std_unexpected<_Gp>::value, "The result of f(std::move(error())) must be a valid template argument for unexpected"); diff --git a/lib/libcxx/include/__expected/unexpected.h b/lib/libcxx/include/__expected/unexpected.h @@ -89,10 +89,10 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(const unexpected&) = default; _LIBCPP_HIDE_FROM_ABI constexpr unexpected& operator=(unexpected&&) = default; - _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; } - _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; } - _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); } - _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err& error() const& noexcept { return __unex_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err& error() & noexcept { return __unex_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Err&& error() const&& noexcept { return std::move(__unex_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Err&& error() && noexcept { return std::move(__unex_); } _LIBCPP_HIDE_FROM_ABI constexpr void swap(unexpected& __other) noexcept(is_nothrow_swappable_v<_Err>) { static_assert(is_swappable_v<_Err>, "unexpected::swap requires is_swappable_v<E> to be true"); diff --git a/lib/libcxx/include/__filesystem/copy_options.h b/lib/libcxx/include/__filesystem/copy_options.h @@ -34,19 +34,19 @@ enum class copy_options : unsigned short { __in_recursive_copy = 512, }; -_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator&(copy_options __lhs, copy_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator&(copy_options __lhs, copy_options __rhs) { return static_cast<copy_options>(static_cast<unsigned short>(__lhs) & static_cast<unsigned short>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator|(copy_options __lhs, copy_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator|(copy_options __lhs, copy_options __rhs) { return static_cast<copy_options>(static_cast<unsigned short>(__lhs) | static_cast<unsigned short>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator^(copy_options __lhs, copy_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator^(copy_options __lhs, copy_options __rhs) { return static_cast<copy_options>(static_cast<unsigned short>(__lhs) ^ static_cast<unsigned short>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator~(copy_options __lhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr copy_options operator~(copy_options __lhs) { return static_cast<copy_options>(~static_cast<unsigned short>(__lhs)); } diff --git a/lib/libcxx/include/__filesystem/directory_entry.h b/lib/libcxx/include/__filesystem/directory_entry.h @@ -40,8 +40,6 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - class directory_entry { typedef filesystem::path _Path; @@ -89,80 +87,88 @@ public: _LIBCPP_HIDE_FROM_ABI void refresh(error_code& __ec) noexcept { __refresh(&__ec); } - _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _Path const& path() const noexcept { return __p_; } _LIBCPP_HIDE_FROM_ABI operator const _Path&() const noexcept { return __p_; } - _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(file_status{__get_ft()}); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool exists() const { return filesystem::exists(file_status{__get_ft()}); } - _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool exists(error_code& __ec) const noexcept { return filesystem::exists(file_status{__get_ft(&__ec)}); } - _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_block_file() const { return __get_ft() == file_type::block; } - _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_block_file(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::block; } - _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_character_file() const { return __get_ft() == file_type::character; } - _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_character_file(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::character; } - _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_directory() const { return __get_ft() == file_type::directory; } - _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_directory(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::directory; } - _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_fifo() const { return __get_ft() == file_type::fifo; } - _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::fifo; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_fifo(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::fifo; + } - _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(file_status{__get_ft()}); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_other() const { return filesystem::is_other(file_status{__get_ft()}); } - _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_other(error_code& __ec) const noexcept { return filesystem::is_other(file_status{__get_ft(&__ec)}); } - _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_regular_file() const { return __get_ft() == file_type::regular; } - _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_regular_file(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::regular; } - _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_socket() const { return __get_ft() == file_type::socket; } - _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { return __get_ft(&__ec) == file_type::socket; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_socket(error_code& __ec) const noexcept { + return __get_ft(&__ec) == file_type::socket; + } - _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_symlink() const { return __get_sym_ft() == file_type::symlink; } - _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_symlink(error_code& __ec) const noexcept { return __get_sym_ft(&__ec) == file_type::symlink; } - _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI uintmax_t file_size() const { return __get_size(); } - _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(&__ec); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(error_code& __ec) const noexcept { return __get_size(&__ec); } - _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count() const { return __get_nlink(); } - _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { return __get_nlink(&__ec); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(error_code& __ec) const noexcept { + return __get_nlink(&__ec); + } - _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time() const { return __get_write_time(); } - _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(error_code& __ec) const noexcept { return __get_write_time(&__ec); } - _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_status status() const { return __get_status(); } - _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { return __get_status(&__ec); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_status status(error_code& __ec) const noexcept { + return __get_status(&__ec); + } - _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_status symlink_status() const { return __get_symlink_status(); } - _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_status symlink_status(error_code& __ec) const noexcept { return __get_symlink_status(&__ec); } @@ -459,8 +465,6 @@ private: directory_entry __elem_; }; -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP - _LIBCPP_END_NAMESPACE_FILESYSTEM #endif // _LIBCPP_STD_VER >= 17 && _LIBCPP_HAS_FILESYSTEM diff --git a/lib/libcxx/include/__filesystem/directory_iterator.h b/lib/libcxx/include/__filesystem/directory_iterator.h @@ -34,8 +34,6 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - class _LIBCPP_HIDDEN __dir_stream; class directory_iterator { public: @@ -73,7 +71,7 @@ public: _LIBCPP_HIDE_FROM_ABI ~directory_iterator() = default; - _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { // Note: this check duplicates a check in `__dereference()`. _LIBCPP_ASSERT_NON_NULL(__imp_, "The end iterator cannot be dereferenced"); return __dereference(); @@ -123,23 +121,23 @@ operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs) noe } // enable directory_iterator range-based for statements -inline _LIBCPP_HIDE_FROM_ABI directory_iterator begin(directory_iterator __iter) noexcept { return __iter; } - -inline _LIBCPP_HIDE_FROM_ABI directory_iterator end(directory_iterator) noexcept { return directory_iterator(); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI directory_iterator begin(directory_iterator __iter) noexcept { + return __iter; +} -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI directory_iterator end(directory_iterator) noexcept { + return directory_iterator(); +} _LIBCPP_END_NAMESPACE_FILESYSTEM # if _LIBCPP_STD_VER >= 20 template <> -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool - std::ranges::enable_borrowed_range<std::filesystem::directory_iterator> = true; +inline constexpr bool std::ranges::enable_borrowed_range<std::filesystem::directory_iterator> = true; template <> -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool - std::ranges::enable_view<std::filesystem::directory_iterator> = true; +inline constexpr bool std::ranges::enable_view<std::filesystem::directory_iterator> = true; # endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__filesystem/directory_options.h b/lib/libcxx/include/__filesystem/directory_options.h @@ -22,19 +22,22 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM enum class directory_options : unsigned char { none = 0, follow_directory_symlink = 1, skip_permission_denied = 2 }; -_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator&(directory_options __lhs, directory_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr directory_options +operator&(directory_options __lhs, directory_options __rhs) { return static_cast<directory_options>(static_cast<unsigned char>(__lhs) & static_cast<unsigned char>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator|(directory_options __lhs, directory_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr directory_options +operator|(directory_options __lhs, directory_options __rhs) { return static_cast<directory_options>(static_cast<unsigned char>(__lhs) | static_cast<unsigned char>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator^(directory_options __lhs, directory_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr directory_options +operator^(directory_options __lhs, directory_options __rhs) { return static_cast<directory_options>(static_cast<unsigned char>(__lhs) ^ static_cast<unsigned char>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator~(directory_options __lhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr directory_options operator~(directory_options __lhs) { return static_cast<directory_options>(~static_cast<unsigned char>(__lhs)); } diff --git a/lib/libcxx/include/__filesystem/file_status.h b/lib/libcxx/include/__filesystem/file_status.h @@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -class _LIBCPP_EXPORTED_FROM_ABI file_status { +class file_status { public: // constructors _LIBCPP_HIDE_FROM_ABI file_status() noexcept : file_status(file_type::none) {} @@ -38,9 +38,9 @@ public: _LIBCPP_HIDE_FROM_ABI file_status& operator=(file_status&&) noexcept = default; // observers - _LIBCPP_HIDE_FROM_ABI file_type type() const noexcept { return __ft_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI file_type type() const noexcept { return __ft_; } - _LIBCPP_HIDE_FROM_ABI perms permissions() const noexcept { return __prms_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI perms permissions() const noexcept { return __prms_; } // modifiers _LIBCPP_HIDE_FROM_ABI void type(file_type __ft) noexcept { __ft_ = __ft; } diff --git a/lib/libcxx/include/__filesystem/filesystem_error.h b/lib/libcxx/include/__filesystem/filesystem_error.h @@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -class _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_EXPORTED_FROM_ABI filesystem_error : public system_error { +class _LIBCPP_EXPORTED_FROM_ABI filesystem_error : public system_error { public: _LIBCPP_HIDE_FROM_ABI filesystem_error(const string& __what, error_code __ec) : system_error(__ec, __what), __storage_(make_shared<_Storage>(path(), path())) { @@ -44,15 +44,16 @@ public: __create_what(2); } - _LIBCPP_HIDE_FROM_ABI const path& path1() const noexcept { return __storage_->__p1_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const path& path1() const noexcept { return __storage_->__p1_; } - _LIBCPP_HIDE_FROM_ABI const path& path2() const noexcept { return __storage_->__p2_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const path& path2() const noexcept { return __storage_->__p2_; } - _LIBCPP_HIDE_FROM_ABI filesystem_error(const filesystem_error&) = default; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI filesystem_error(const filesystem_error&) = default; ~filesystem_error() override; // key function - _LIBCPP_HIDE_FROM_ABI_VIRTUAL - const char* what() const noexcept override { return __storage_->__what_.c_str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI_VIRTUAL const char* what() const noexcept override { + return __storage_->__what_.c_str(); + } void __create_what(int __num_paths); @@ -69,14 +70,12 @@ private: # if _LIBCPP_HAS_EXCEPTIONS template <class... _Args> -[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY void -__throw_filesystem_error(_Args&&... __args) { +[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_filesystem_error(_Args&&... __args) { throw filesystem_error(std::forward<_Args>(__args)...); } # else template <class... _Args> -[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY void -__throw_filesystem_error(_Args&&...) { +[[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_filesystem_error(_Args&&...) { _LIBCPP_VERBOSE_ABORT("filesystem_error was thrown in -fno-exceptions mode"); } # endif diff --git a/lib/libcxx/include/__filesystem/operations.h b/lib/libcxx/include/__filesystem/operations.h @@ -31,8 +31,6 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - _LIBCPP_EXPORTED_FROM_ABI path __absolute(const path&, error_code* __ec = nullptr); _LIBCPP_EXPORTED_FROM_ABI path __canonical(const path&, error_code* __ec = nullptr); _LIBCPP_EXPORTED_FROM_ABI bool @@ -70,10 +68,14 @@ _LIBCPP_EXPORTED_FROM_ABI bool __fs_is_empty(const path& __p, error_code* __ec = _LIBCPP_EXPORTED_FROM_ABI void __permissions(const path&, perms, perm_options, error_code* = nullptr); _LIBCPP_EXPORTED_FROM_ABI space_info __space(const path&, error_code* __ec = nullptr); -inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p) { return __absolute(__p); } -inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p, error_code& __ec) { return __absolute(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p) { return __canonical(__p); } -inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p, error_code& __ec) { return __canonical(__p, &__ec); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p) { return __absolute(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path absolute(const path& __p, error_code& __ec) { + return __absolute(__p, &__ec); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p) { return __canonical(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path canonical(const path& __p, error_code& __ec) { + return __canonical(__p, &__ec); +} inline _LIBCPP_HIDE_FROM_ABI bool copy_file(const path& __from, const path& __to) { return __copy_file(__from, __to, copy_options::none); } @@ -137,85 +139,112 @@ inline _LIBCPP_HIDE_FROM_ABI void create_symlink(const path& __target, const pat inline _LIBCPP_HIDE_FROM_ABI void create_symlink(const path& __target, const path& __link, error_code& __ec) noexcept { return __create_symlink(__target, __link, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI path current_path() { return __current_path(); } -inline _LIBCPP_HIDE_FROM_ABI path current_path(error_code& __ec) { return __current_path(&__ec); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path current_path() { return __current_path(); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path current_path(error_code& __ec) { return __current_path(&__ec); } inline _LIBCPP_HIDE_FROM_ABI void current_path(const path& __p) { __current_path(__p); } inline _LIBCPP_HIDE_FROM_ABI void current_path(const path& __p, error_code& __ec) noexcept { __current_path(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI bool equivalent(const path& __p1, const path& __p2) { return __equivalent(__p1, __p2); } -inline _LIBCPP_HIDE_FROM_ABI bool equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool equivalent(const path& __p1, const path& __p2) { + return __equivalent(__p1, __p2); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool +equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept { return __equivalent(__p1, __p2, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI bool status_known(file_status __s) noexcept { return __s.type() != file_type::none; } -inline _LIBCPP_HIDE_FROM_ABI bool exists(file_status __s) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool status_known(file_status __s) noexcept { + return __s.type() != file_type::none; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool exists(file_status __s) noexcept { return status_known(__s) && __s.type() != file_type::not_found; } -inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p) { return exists(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p) { return exists(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool exists(const path& __p, error_code& __ec) noexcept { auto __s = __status(__p, &__ec); if (status_known(__s)) __ec.clear(); return exists(__s); } -inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p) { return __file_size(__p); } -inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p) { return __file_size(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI uintmax_t file_size(const path& __p, error_code& __ec) noexcept { return __file_size(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p) { return __hard_link_count(__p); } -inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p) { return __hard_link_count(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept { return __hard_link_count(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(file_status __s) noexcept { return __s.type() == file_type::block; } -inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p) { return is_block_file(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(file_status __s) noexcept { + return __s.type() == file_type::block; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p) { return is_block_file(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_block_file(const path& __p, error_code& __ec) noexcept { return is_block_file(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(file_status __s) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(file_status __s) noexcept { return __s.type() == file_type::character; } -inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p) { return is_character_file(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p) { + return is_character_file(__status(__p)); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_character_file(const path& __p, error_code& __ec) noexcept { return is_character_file(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_directory(file_status __s) noexcept { return __s.type() == file_type::directory; } -inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p) { return is_directory(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_directory(file_status __s) noexcept { + return __s.type() == file_type::directory; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p) { return is_directory(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_directory(const path& __p, error_code& __ec) noexcept { return is_directory(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p) { return __fs_is_empty(__p); } -inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p, error_code& __ec) { return __fs_is_empty(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(file_status __s) noexcept { return __s.type() == file_type::fifo; } -inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p) { return is_fifo(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p) { return __fs_is_empty(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_empty(const path& __p, error_code& __ec) { + return __fs_is_empty(__p, &__ec); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(file_status __s) noexcept { + return __s.type() == file_type::fifo; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p) { return is_fifo(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_fifo(const path& __p, error_code& __ec) noexcept { return is_fifo(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(file_status __s) noexcept { return __s.type() == file_type::regular; } -inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p) { return is_regular_file(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(file_status __s) noexcept { + return __s.type() == file_type::regular; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p) { + return is_regular_file(__status(__p)); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_regular_file(const path& __p, error_code& __ec) noexcept { return is_regular_file(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(file_status __s) noexcept { return __s.type() == file_type::symlink; } -inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p) { return is_symlink(__symlink_status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(file_status __s) noexcept { + return __s.type() == file_type::symlink; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p) { + return is_symlink(__symlink_status(__p)); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_symlink(const path& __p, error_code& __ec) noexcept { return is_symlink(__symlink_status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_other(file_status __s) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_other(file_status __s) noexcept { return exists(__s) && !is_regular_file(__s) && !is_directory(__s) && !is_symlink(__s); } -inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p) { return is_other(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p) { return is_other(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_other(const path& __p, error_code& __ec) noexcept { return is_other(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_socket(file_status __s) noexcept { return __s.type() == file_type::socket; } -inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p) { return is_socket(__status(__p)); } -inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_socket(file_status __s) noexcept { + return __s.type() == file_type::socket; +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p) { return is_socket(__status(__p)); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool is_socket(const path& __p, error_code& __ec) noexcept { return is_socket(__status(__p, &__ec)); } -inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p) { return __last_write_time(__p); } -inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p) { + return __last_write_time(__p); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_time_type last_write_time(const path& __p, error_code& __ec) noexcept { return __last_write_time(__p, &__ec); } inline _LIBCPP_HIDE_FROM_ABI void last_write_time(const path& __p, file_time_type __t) { __last_write_time(__p, __t); } @@ -233,7 +262,7 @@ inline _LIBCPP_HIDE_FROM_ABI void permissions(const path& __p, perms __prms, per __permissions(__p, __prms, __opts, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base, error_code& __ec) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base, error_code& __ec) { path __tmp = __weakly_canonical(__p, &__ec); if (__ec) return {}; @@ -243,16 +272,18 @@ inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base, return __tmp.lexically_proximate(__tmp_base); } -inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, error_code& __ec) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, error_code& __ec) { return proximate(__p, current_path(), __ec); } -inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base = current_path()) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path proximate(const path& __p, const path& __base = current_path()) { return __weakly_canonical(__p).lexically_proximate(__weakly_canonical(__base)); } -inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p) { return __read_symlink(__p); } -inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p, error_code& __ec) { return __read_symlink(__p, &__ec); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p) { return __read_symlink(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path read_symlink(const path& __p, error_code& __ec) { + return __read_symlink(__p, &__ec); +} -inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base, error_code& __ec) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base, error_code& __ec) { path __tmp = __weakly_canonical(__p, &__ec); if (__ec) return path(); @@ -262,10 +293,10 @@ inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base, return __tmp.lexically_relative(__tmpbase); } -inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, error_code& __ec) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, error_code& __ec) { return relative(__p, current_path(), __ec); } -inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base = current_path()) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path relative(const path& __p, const path& __base = current_path()) { return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base)); } inline _LIBCPP_HIDE_FROM_ABI uintmax_t remove_all(const path& __p) { return __remove_all(__p); } @@ -282,27 +313,27 @@ inline _LIBCPP_HIDE_FROM_ABI void resize_file(const path& __p, uintmax_t __ns) { inline _LIBCPP_HIDE_FROM_ABI void resize_file(const path& __p, uintmax_t __ns, error_code& __ec) noexcept { return __resize_file(__p, __ns, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p) { return __space(__p); } -inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p) { return __space(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI space_info space(const path& __p, error_code& __ec) noexcept { return __space(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p) { return __status(__p); } -inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p) { return __status(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_status status(const path& __p, error_code& __ec) noexcept { return __status(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p) { return __symlink_status(__p); } -inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p, error_code& __ec) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p) { return __symlink_status(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI file_status symlink_status(const path& __p, error_code& __ec) noexcept { return __symlink_status(__p, &__ec); } -inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path() { return __temp_directory_path(); } -inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path(error_code& __ec) { return __temp_directory_path(&__ec); } -inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p) { return __weakly_canonical(__p); } -inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p, error_code& __ec) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path() { return __temp_directory_path(); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path temp_directory_path(error_code& __ec) { + return __temp_directory_path(&__ec); +} +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p) { return __weakly_canonical(__p); } +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI path weakly_canonical(path const& __p, error_code& __ec) { return __weakly_canonical(__p, &__ec); } -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP - _LIBCPP_END_NAMESPACE_FILESYSTEM #endif // _LIBCPP_STD_VER >= 17 && _LIBCPP_HAS_FILESYSTEM diff --git a/lib/libcxx/include/__filesystem/path.h b/lib/libcxx/include/__filesystem/path.h @@ -42,8 +42,6 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - template <class _Tp> struct __can_convert_char { static const bool value = false; @@ -326,6 +324,7 @@ struct _PathCVT<char> { } }; +# if _LIBCPP_HAS_LOCALIZATION template <class _ECharT> struct _PathExport { typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower; @@ -366,7 +365,7 @@ struct _PathExport<char16_t> { } }; -# if _LIBCPP_HAS_CHAR8_T +# if _LIBCPP_HAS_CHAR8_T template <> struct _PathExport<char8_t> { typedef __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__> _Narrower; @@ -376,8 +375,9 @@ struct _PathExport<char8_t> { _Narrower()(back_inserter(__dest), __src.data(), __src.data() + __src.size()); } }; -# endif // _LIBCPP_HAS_CHAR8_T -# endif /* _LIBCPP_WIN32API */ +# endif // _LIBCPP_HAS_CHAR8_T +# endif // _LIBCPP_HAS_LOCALIZATION +# endif // _LIBCPP_WIN32API class _LIBCPP_EXPORTED_FROM_ABI path { template <class _SourceOrIter, class _Tp = path&> @@ -667,16 +667,16 @@ public: _LIBCPP_HIDE_FROM_ABI void __reserve(size_t __s) { __pn_.reserve(__s); } // native format observers - _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const string_type& native() const noexcept { return __pn_; } - _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept { return __pn_.c_str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const value_type* c_str() const noexcept { return __pn_.c_str(); } _LIBCPP_HIDE_FROM_ABI operator string_type() const { return __pn_; } # if defined(_LIBCPP_WIN32API) - _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return __pn_; } - _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { std::wstring __s; __s.resize(__pn_.size()); std::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/'); @@ -685,6 +685,7 @@ public: # if _LIBCPP_HAS_LOCALIZATION template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> > + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const { using _Str = basic_string<_ECharT, _Traits, _Allocator>; _Str __s(__a); @@ -693,8 +694,8 @@ public: return __s; } - _LIBCPP_HIDE_FROM_ABI std::string string() const { return string<char>(); } - _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string string() const { return string<char>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __u8_string u8string() const { using _CVT = __narrow_to_utf8<sizeof(wchar_t) * __CHAR_BIT__>; __u8_string __s; __s.reserve(__pn_.size()); @@ -702,12 +703,12 @@ public: return __s; } - _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); } - _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); } // generic format observers template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> > - _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> generic_string(const _Allocator& __a = _Allocator()) const { using _Str = basic_string<_ECharT, _Traits, _Allocator>; _Str __s = string<_ECharT, _Traits, _Allocator>(__a); @@ -718,10 +719,10 @@ public: return __s; } - _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return generic_string<char>(); } - _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return generic_string<char16_t>(); } - _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return generic_string<char32_t>(); } - _LIBCPP_HIDE_FROM_ABI __u8_string generic_u8string() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return generic_string<char>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return generic_string<char16_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return generic_string<char32_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __u8_string generic_u8string() const { __u8_string __s = u8string(); std::replace(__s.begin(), __s.end(), '\\', '/'); return __s; @@ -729,15 +730,18 @@ public: # endif // _LIBCPP_HAS_LOCALIZATION # else /* _LIBCPP_WIN32API */ - _LIBCPP_HIDE_FROM_ABI std::string string() const { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string string() const { return __pn_; } # if _LIBCPP_HAS_CHAR8_T - _LIBCPP_HIDE_FROM_ABI std::u8string u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u8string u8string() const { + return std::u8string(__pn_.begin(), __pn_.end()); + } # else - _LIBCPP_HIDE_FROM_ABI std::string u8string() const { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string u8string() const { return __pn_; } # endif # if _LIBCPP_HAS_LOCALIZATION template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> > + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> string(const _Allocator& __a = _Allocator()) const { using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>; using _Str = basic_string<_ECharT, _Traits, _Allocator>; @@ -748,32 +752,34 @@ public: } # if _LIBCPP_HAS_WIDE_CHARACTERS - _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return string<wchar_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::wstring wstring() const { return string<wchar_t>(); } # endif - _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); } - _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u16string u16string() const { return string<char16_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u32string u32string() const { return string<char32_t>(); } # endif // _LIBCPP_HAS_LOCALIZATION // generic format observers - _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string generic_string() const { return __pn_; } # if _LIBCPP_HAS_CHAR8_T - _LIBCPP_HIDE_FROM_ABI std::u8string generic_u8string() const { return std::u8string(__pn_.begin(), __pn_.end()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u8string generic_u8string() const { + return std::u8string(__pn_.begin(), __pn_.end()); + } # else - _LIBCPP_HIDE_FROM_ABI std::string generic_u8string() const { return __pn_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::string generic_u8string() const { return __pn_; } # endif # if _LIBCPP_HAS_LOCALIZATION template <class _ECharT, class _Traits = char_traits<_ECharT>, class _Allocator = allocator<_ECharT> > - _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<_ECharT, _Traits, _Allocator> generic_string(const _Allocator& __a = _Allocator()) const { return string<_ECharT, _Traits, _Allocator>(__a); } # if _LIBCPP_HAS_WIDE_CHARACTERS - _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { return string<wchar_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::wstring generic_wstring() const { return string<wchar_t>(); } # endif - _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return string<char16_t>(); } - _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return string<char32_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u16string generic_u16string() const { return string<char16_t>(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::u32string generic_u32string() const { return string<char32_t>(); } # endif // _LIBCPP_HAS_LOCALIZATION # endif /* !_LIBCPP_WIN32API */ @@ -790,40 +796,40 @@ private: public: // compare - _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept { return __compare(__p.__pn_); } - _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return __compare(__s); } - _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const { return __compare(__s); } - _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return __compare(__s); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI int compare(const path& __p) const noexcept { return __compare(__p.__pn_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return __compare(__s); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI int compare(__string_view __s) const { return __compare(__s); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return __compare(__s); } // decomposition - _LIBCPP_HIDE_FROM_ABI path root_name() const { return string_type(__root_name()); } - _LIBCPP_HIDE_FROM_ABI path root_directory() const { return string_type(__root_directory()); } - _LIBCPP_HIDE_FROM_ABI path root_path() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path root_name() const { return string_type(__root_name()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path root_directory() const { return string_type(__root_directory()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path root_path() const { # if defined(_LIBCPP_WIN32API) return string_type(__root_path_raw()); # else return root_name().append(string_type(__root_directory())); # endif } - _LIBCPP_HIDE_FROM_ABI path relative_path() const { return string_type(__relative_path()); } - _LIBCPP_HIDE_FROM_ABI path parent_path() const { return string_type(__parent_path()); } - _LIBCPP_HIDE_FROM_ABI path filename() const { return string_type(__filename()); } - _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); } - _LIBCPP_HIDE_FROM_ABI path extension() const { return string_type(__extension()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path relative_path() const { return string_type(__relative_path()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path parent_path() const { return string_type(__parent_path()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path filename() const { return string_type(__filename()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path stem() const { return string_type(__stem()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path extension() const { return string_type(__extension()); } // query [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __pn_.empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_root_name() const { return !__root_name().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const { return !__root_directory().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_root_path() const { return !__root_path_raw().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const { return !__relative_path().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const { return !__parent_path().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_filename() const { return !__filename().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); } - _LIBCPP_HIDE_FROM_ABI bool has_extension() const { return !__extension().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_root_name() const { return !__root_name().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_root_directory() const { return !__root_directory().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_root_path() const { return !__root_path_raw().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_relative_path() const { return !__relative_path().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_parent_path() const { return !__parent_path().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_filename() const { return !__filename().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_stem() const { return !__stem().empty(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_extension() const { return !__extension().empty(); } - _LIBCPP_HIDE_FROM_ABI bool is_absolute() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_absolute() const { # if defined(_LIBCPP_WIN32API) __string_view __root_name_str = __root_name(); __string_view __root_dir = __root_directory(); @@ -847,13 +853,13 @@ public: return has_root_directory(); # endif } - _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_relative() const { return !is_absolute(); } // relative paths - path lexically_normal() const; - path lexically_relative(const path& __base) const; + [[nodiscard]] path lexically_normal() const; + [[nodiscard]] path lexically_relative(const path& __base) const; - _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI path lexically_proximate(const path& __base) const { path __result = this->lexically_relative(__base); if (__result.native().empty()) return *this; @@ -861,11 +867,11 @@ public: } // iterators - class _LIBCPP_EXPORTED_FROM_ABI iterator; + class iterator; typedef iterator const_iterator; - iterator begin() const; - iterator end() const; + [[nodiscard]] iterator begin() const; + [[nodiscard]] iterator end() const; # if _LIBCPP_HAS_LOCALIZATION template < @@ -908,17 +914,15 @@ private: inline _LIBCPP_HIDE_FROM_ABI void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } -_LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept; - -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP +[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI size_t hash_value(const path& __p) noexcept; _LIBCPP_END_NAMESPACE_FILESYSTEM _LIBCPP_BEGIN_NAMESPACE_STD template <> -struct _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY hash<filesystem::path> : __unary_function<filesystem::path, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(filesystem::path const& __p) const noexcept { +struct hash<filesystem::path> : __unary_function<filesystem::path, size_t> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(filesystem::path const& __p) const noexcept { return filesystem::hash_value(__p); } }; diff --git a/lib/libcxx/include/__filesystem/path_iterator.h b/lib/libcxx/include/__filesystem/path_iterator.h @@ -52,7 +52,7 @@ public: _LIBCPP_HIDE_FROM_ABI iterator& operator=(const iterator&) = default; - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __stashed_elem_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __stashed_elem_; } _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return &__stashed_elem_; } @@ -95,12 +95,10 @@ private: _ParserState __state_; }; -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline _LIBCPP_HIDE_FROM_ABI bool operator==(const path::iterator& __lhs, const path::iterator& __rhs) { return __lhs.__path_ptr_ == __rhs.__path_ptr_ && __lhs.__entry_.data() == __rhs.__entry_.data(); } -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const path::iterator& __lhs, const path::iterator& __rhs) { return !(__lhs == __rhs); } diff --git a/lib/libcxx/include/__filesystem/perm_options.h b/lib/libcxx/include/__filesystem/perm_options.h @@ -22,19 +22,19 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM enum class perm_options : unsigned char { replace = 1, add = 2, remove = 4, nofollow = 8 }; -_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator&(perm_options __lhs, perm_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator&(perm_options __lhs, perm_options __rhs) { return static_cast<perm_options>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator|(perm_options __lhs, perm_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator|(perm_options __lhs, perm_options __rhs) { return static_cast<perm_options>(static_cast<unsigned>(__lhs) | static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator^(perm_options __lhs, perm_options __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator^(perm_options __lhs, perm_options __rhs) { return static_cast<perm_options>(static_cast<unsigned>(__lhs) ^ static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator~(perm_options __lhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perm_options operator~(perm_options __lhs) { return static_cast<perm_options>(~static_cast<unsigned>(__lhs)); } diff --git a/lib/libcxx/include/__filesystem/perms.h b/lib/libcxx/include/__filesystem/perms.h @@ -51,19 +51,19 @@ enum class perms : unsigned { unknown = 0xFFFF, }; -_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator&(perms __lhs, perms __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perms operator&(perms __lhs, perms __rhs) { return static_cast<perms>(static_cast<unsigned>(__lhs) & static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator|(perms __lhs, perms __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perms operator|(perms __lhs, perms __rhs) { return static_cast<perms>(static_cast<unsigned>(__lhs) | static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator^(perms __lhs, perms __rhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perms operator^(perms __lhs, perms __rhs) { return static_cast<perms>(static_cast<unsigned>(__lhs) ^ static_cast<unsigned>(__rhs)); } -_LIBCPP_HIDE_FROM_ABI inline constexpr perms operator~(perms __lhs) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI inline constexpr perms operator~(perms __lhs) { return static_cast<perms>(~static_cast<unsigned>(__lhs)); } diff --git a/lib/libcxx/include/__filesystem/recursive_directory_iterator.h b/lib/libcxx/include/__filesystem/recursive_directory_iterator.h @@ -33,8 +33,6 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - class recursive_directory_iterator { public: using value_type = directory_entry; @@ -73,7 +71,7 @@ public: _LIBCPP_HIDE_FROM_ABI ~recursive_directory_iterator() = default; - _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { return __dereference(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { return __dereference(); } _LIBCPP_HIDE_FROM_ABI const directory_entry* operator->() const { return &__dereference(); } @@ -87,14 +85,14 @@ public: _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator& increment(error_code& __ec) { return __increment(&__ec); } - _LIBCPP_EXPORTED_FROM_ABI directory_options options() const; - _LIBCPP_EXPORTED_FROM_ABI int depth() const; + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI directory_options options() const; + [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI int depth() const; _LIBCPP_HIDE_FROM_ABI void pop() { __pop(); } _LIBCPP_HIDE_FROM_ABI void pop(error_code& __ec) { __pop(&__ec); } - _LIBCPP_HIDE_FROM_ABI bool recursion_pending() const { return __rec_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool recursion_pending() const { return __rec_; } _LIBCPP_HIDE_FROM_ABI void disable_recursion_pending() { __rec_ = false; } @@ -132,27 +130,24 @@ operator!=(const recursive_directory_iterator& __lhs, const recursive_directory_ return !(__lhs == __rhs); } // enable recursive_directory_iterator range-based for statements -inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator begin(recursive_directory_iterator __iter) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator +begin(recursive_directory_iterator __iter) noexcept { return __iter; } -inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator end(recursive_directory_iterator) noexcept { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI recursive_directory_iterator end(recursive_directory_iterator) noexcept { return recursive_directory_iterator(); } -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP - _LIBCPP_END_NAMESPACE_FILESYSTEM # if _LIBCPP_STD_VER >= 20 template <> -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool - std::ranges::enable_borrowed_range<std::filesystem::recursive_directory_iterator> = true; +inline constexpr bool std::ranges::enable_borrowed_range<std::filesystem::recursive_directory_iterator> = true; template <> -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY inline constexpr bool - std::ranges::enable_view<std::filesystem::recursive_directory_iterator> = true; +inline constexpr bool std::ranges::enable_view<std::filesystem::recursive_directory_iterator> = true; # endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__filesystem/space_info.h b/lib/libcxx/include/__filesystem/space_info.h @@ -21,7 +21,7 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -struct _LIBCPP_EXPORTED_FROM_ABI space_info { +struct space_info { uintmax_t capacity; uintmax_t free; uintmax_t available; diff --git a/lib/libcxx/include/__filesystem/u8path.h b/lib/libcxx/include/__filesystem/u8path.h @@ -24,32 +24,32 @@ _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_PUSH - +# if !defined(_LIBCPP_WIN32API) || _LIBCPP_HAS_LOCALIZATION template <class _InputIt, __enable_if_t<__is_pathable<_InputIt>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _InputIt __l) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _InputIt __l) { static_assert( -# if _LIBCPP_HAS_CHAR8_T +# if _LIBCPP_HAS_CHAR8_T is_same<typename __is_pathable<_InputIt>::__char_type, char8_t>::value || -# endif +# endif is_same<typename __is_pathable<_InputIt>::__char_type, char>::value, "u8path(Iter, Iter) requires Iter have a value_type of type 'char'" " or 'char8_t'"); -# if defined(_LIBCPP_WIN32API) +# if defined(_LIBCPP_WIN32API) string __tmp(__f, __l); using _CVT = __widen_from_utf8<sizeof(wchar_t) * __CHAR_BIT__>; std::wstring __w; __w.reserve(__tmp.size()); _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); return path(__w); -# else +# else return path(__f, __l); -# endif /* !_LIBCPP_WIN32API */ +# endif // defined(_LIBCPP_WIN32API) } +# endif // !defined(_LIBCPP_WIN32API) || _LIBCPP_HAS_LOCALIZATION -# if defined(_LIBCPP_WIN32API) +# if defined(_LIBCPP_WIN32API) && _LIBCPP_HAS_LOCALIZATION template <class _InputIt, __enable_if_t<__is_pathable<_InputIt>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _NullSentinel) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _NullSentinel) { static_assert( # if _LIBCPP_HAS_CHAR8_T is_same<typename __is_pathable<_InputIt>::__char_type, char8_t>::value || @@ -67,10 +67,10 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(_InputIt __f, _CVT()(back_inserter(__w), __tmp.data(), __tmp.data() + __tmp.size()); return path(__w); } -# endif /* _LIBCPP_WIN32API */ +# endif // defined(_LIBCPP_WIN32API) && _LIBCPP_HAS_LOCALIZATION template <class _Source, __enable_if_t<__is_pathable<_Source>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(const _Source& __s) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(const _Source& __s) { static_assert( # if _LIBCPP_HAS_CHAR8_T is_same<typename __is_pathable<_Source>::__char_type, char8_t>::value || @@ -86,8 +86,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_WITH_CHAR8_T path u8path(const _Source& # endif } -_LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY_POP - _LIBCPP_END_NAMESPACE_FILESYSTEM #endif // _LIBCPP_STD_VER >= 17 diff --git a/lib/libcxx/include/__flat_map/flat_map.h b/lib/libcxx/include/__flat_map/flat_map.h @@ -29,7 +29,6 @@ #include <__flat_map/key_value_iterator.h> #include <__flat_map/sorted_unique.h> #include <__flat_map/utils.h> -#include <__functional/invoke.h> #include <__functional/is_transparent.h> #include <__functional/operations.h> #include <__fwd/memory.h> @@ -48,7 +47,7 @@ #include <__ranges/container_compatible_range.h> #include <__ranges/drop_view.h> #include <__ranges/from_range.h> -#include <__ranges/ref_view.h> +#include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/subrange.h> #include <__ranges/zip_view.h> @@ -410,41 +409,45 @@ public: } // iterators - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { return iterator(__containers_.keys.begin(), __containers_.values.begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { return iterator(__containers_.keys.end(), __containers_.values.end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rend() 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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { + return begin(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { + return end(); + } + [[nodiscard]] _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } @@ -453,11 +456,11 @@ public: return __containers_.keys.empty(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { return __containers_.keys.size(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept { + [[nodiscard]] _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()); } @@ -481,7 +484,7 @@ public: return try_emplace(std::forward<_Kp>(__x)).first->second; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const key_type& __x) { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const key_type&): Key does not exist"); @@ -489,7 +492,7 @@ public: return __it->second; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const key_type& __x) const { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const key_type&) const: Key does not exist"); @@ -499,7 +502,7 @@ public: template <class _Kp> requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 mapped_type& at(const _Kp& __x) { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const K&): Key does not exist"); @@ -509,7 +512,7 @@ public: template <class _Kp> requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_type& at(const _Kp& __x) const { auto __it = find(__x); if (__it == end()) { std::__throw_out_of_range("flat_map::at(const K&) const: Key does not exist"); @@ -589,6 +592,15 @@ public: __append_sort_merge_unique</*WasSorted = */ false>(ranges::begin(__range), ranges::end(__range)); } + template <_ContainerCompatibleRange<value_type> _Range> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_unique_t, _Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); } @@ -597,7 +609,7 @@ public: insert(sorted_unique, __il.begin(), __il.end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 containers extract() && { + [[nodiscard]] _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; @@ -738,14 +750,17 @@ public: return iterator(std::move(__key_it), std::move(__mapped_it)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __y) noexcept { - // warning: The spec has unconditional noexcept, which means that - // if any of the following functions throw an exception, - // std::terminate will be called. - // This is discussed in P2767, which hasn't been voted on yet. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_map& __y) noexcept(is_nothrow_swappable_v<key_container_type> && + is_nothrow_swappable_v<mapped_container_type> && is_nothrow_swappable_v<key_compare>) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + clear() /* noexcept */; + __y.clear() /* noexcept */; + }); ranges::swap(__compare_, __y.__compare_); ranges::swap(__containers_.keys, __y.__containers_.keys); ranges::swap(__containers_.values, __y.__containers_.values); + __on_failure.__complete(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { @@ -754,116 +769,121 @@ public: } // observers - _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare value_comp() const { return value_compare(__compare_); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const key_container_type& keys() const noexcept { + [[nodiscard]] _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const mapped_container_type& + values() const noexcept { return __containers_.values; } // map operations - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const key_type& __x) { return __find_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const key_type& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template <class _Kp> requires __is_compare_transparent - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const { return find(__x) != end(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const key_type& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const key_type& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const key_type& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator> + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const _Kp& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator> + [[nodiscard]] _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); } @@ -878,7 +898,8 @@ public: __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } - friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_map& __x, flat_map& __y) noexcept { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_map& __x, flat_map& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } @@ -913,7 +934,7 @@ private: __compare_(std::forward<_CompArg>(__comp)...) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool __is_sorted_and_unique(auto&& __key_container) const { - auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) -> bool { return !__compare_(__x, __y); }; return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); } @@ -946,7 +967,7 @@ private: auto __zv = ranges::views::zip(__containers_.keys, __containers_.values); auto __append_start_offset = __containers_.keys.size() - __num_of_appended; auto __end = __zv.end(); - auto __compare_key = [this](const auto& __p1, const auto& __p2) { + auto __compare_key = [this](const auto& __p1, const auto& __p2) -> bool { return __compare_(std::get<0>(__p1), std::get<0>(__p2)); }; if constexpr (!_WasSorted) { @@ -1125,8 +1146,7 @@ private: }; template <class _KeyContainer, class _MappedContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -1139,7 +1159,7 @@ flat_map(_KeyContainer, _MappedContainer, _Compare = _Compare()) template <class _KeyContainer, class _MappedContainer, class _Allocator> requires(uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && - !__is_allocator<_KeyContainer>::value && !__is_allocator<_MappedContainer>::value) + !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer>) flat_map(_KeyContainer, _MappedContainer, _Allocator) -> flat_map<typename _KeyContainer::value_type, typename _MappedContainer::value_type, @@ -1148,9 +1168,8 @@ flat_map(_KeyContainer, _MappedContainer, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && uses_allocator_v<_KeyContainer, _Allocator> && - uses_allocator_v<_MappedContainer, _Allocator> && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && + uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -1162,8 +1181,7 @@ flat_map(_KeyContainer, _MappedContainer, _Compare, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -1176,7 +1194,7 @@ flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare = _Compare() template <class _KeyContainer, class _MappedContainer, class _Allocator> requires(uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && - !__is_allocator<_KeyContainer>::value && !__is_allocator<_MappedContainer>::value) + !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer>) flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Allocator) -> flat_map<typename _KeyContainer::value_type, typename _MappedContainer::value_type, @@ -1185,9 +1203,8 @@ flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && uses_allocator_v<_KeyContainer, _Allocator> && - uses_allocator_v<_MappedContainer, _Allocator> && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && + uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -1199,19 +1216,19 @@ flat_map(sorted_unique_t, _KeyContainer, _MappedContainer, _Compare, _Allocator) _MappedContainer>; template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_map(_InputIterator, _InputIterator, _Compare = _Compare()) -> flat_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare>; template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_map(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) -> flat_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare>; template <ranges::input_range _Range, class _Compare = less<__range_key_type<_Range>>, class _Allocator = allocator<byte>, - class = __enable_if_t<!__is_allocator<_Compare>::value && __is_allocator<_Allocator>::value>> + class = __enable_if_t<!__is_allocator_v<_Compare> && __is_allocator_v<_Allocator>>> flat_map(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_map< __range_key_type<_Range>, __range_mapped_type<_Range>, @@ -1219,7 +1236,7 @@ flat_map(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator( vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>, vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>; -template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator_v<_Allocator>>> flat_map(from_range_t, _Range&&, _Allocator) -> flat_map< __range_key_type<_Range>, __range_mapped_type<_Range>, @@ -1228,11 +1245,11 @@ flat_map(from_range_t, _Range&&, _Allocator) -> flat_map< vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>; template <class _Key, class _Tp, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_map(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare()) -> flat_map<_Key, _Tp, _Compare>; template <class _Key, class _Tp, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_map(sorted_unique_t, initializer_list<pair<_Key, _Tp>>, _Compare = _Compare()) -> flat_map<_Key, _Tp, _Compare>; template <class _Key, class _Tp, class _Compare, class _KeyContainer, class _MappedContainer, class _Allocator> diff --git a/lib/libcxx/include/__flat_map/flat_multimap.h b/lib/libcxx/include/__flat_map/flat_multimap.h @@ -22,7 +22,6 @@ #include <__algorithm/upper_bound.h> #include <__assert> #include <__compare/synth_three_way.h> -#include <__concepts/convertible_to.h> #include <__concepts/swappable.h> #include <__config> #include <__cstddef/byte.h> @@ -30,7 +29,6 @@ #include <__flat_map/key_value_iterator.h> #include <__flat_map/sorted_equivalent.h> #include <__flat_map/utils.h> -#include <__functional/invoke.h> #include <__functional/is_transparent.h> #include <__functional/operations.h> #include <__fwd/vector.h> @@ -47,7 +45,7 @@ #include <__ranges/container_compatible_range.h> #include <__ranges/drop_view.h> #include <__ranges/from_range.h> -#include <__ranges/ref_view.h> +#include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/subrange.h> #include <__ranges/zip_view.h> @@ -57,14 +55,12 @@ #include <__type_traits/is_allocator.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_same.h> -#include <__type_traits/maybe_const.h> #include <__utility/exception_guard.h> #include <__utility/move.h> #include <__utility/pair.h> #include <__utility/scope_guard.h> #include <__vector/vector.h> #include <initializer_list> -#include <stdexcept> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -114,11 +110,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 +134,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 +165,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 +175,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 +192,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 +202,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 +212,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 +236,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 +249,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 +285,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 +293,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 +394,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 +408,58 @@ public: } // iterators - _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + [[nodiscard]] _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()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { + return begin(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { + return end(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(end()); + } + [[nodiscard]] _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(); } + [[nodiscard]] _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 { + [[nodiscard]] _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,32 @@ 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()); } + template <_ContainerCompatibleRange<value_type> _Range> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_equivalent_t, _Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge</*WasSorted = */ true>(ranges::begin(__range), ranges::end(__range)); + } + + _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() && { + [[nodiscard]] _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 +609,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 +627,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,146 +642,178 @@ public: return iterator(std::move(__key_it), std::move(__mapped_it)); } - _LIBCPP_HIDE_FROM_ABI 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 + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept( + is_nothrow_swappable_v<key_container_type> && is_nothrow_swappable_v<mapped_container_type> && + is_nothrow_swappable_v<key_compare>) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + clear() /* noexcept */; + __y.clear() /* noexcept */; + }); ranges::swap(__compare_, __y.__compare_); ranges::swap(__containers_.keys, __y.__containers_.keys); ranges::swap(__containers_.values, __y.__containers_.values); + __on_failure.__complete(); } - _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_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; } + [[nodiscard]] _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; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const key_container_type& keys() const noexcept { + return __containers_.keys; + } + [[nodiscard]] _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); } + [[nodiscard]] _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); } + [[nodiscard]] _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) { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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(); } + [[nodiscard]] _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 { + [[nodiscard]] _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); } + [[nodiscard]] _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 { + [[nodiscard]] _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) { + [[nodiscard]] _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 { + [[nodiscard]] _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); } + [[nodiscard]] _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 { + [[nodiscard]] _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) { + [[nodiscard]] _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 { + [[nodiscard]] _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) { + [[nodiscard]] _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 { + [[nodiscard]] _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) { + [[nodiscard]] _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 { + [[nodiscard]] _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(noexcept(__x.swap(__y))) { + __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,36 +822,39 @@ 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) { auto __zv = ranges::views::zip(__containers_.keys, __containers_.values); auto __append_start_offset = __containers_.keys.size() - __num_appended; auto __end = __zv.end(); - auto __compare_key = [this](const auto& __p1, const auto& __p2) { + auto __compare_key = [this](const auto& __p1, const auto& __p2) -> bool { return __compare_(std::get<0>(__p1), std::get<0>(__p2)); }; if constexpr (!_WasSorted) { @@ -791,7 +870,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 +880,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 +890,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 +898,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 +916,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 +927,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 +936,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_; @@ -864,8 +946,7 @@ private: }; template <class _KeyContainer, class _MappedContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -878,7 +959,7 @@ flat_multimap(_KeyContainer, _MappedContainer, _Compare = _Compare()) template <class _KeyContainer, class _MappedContainer, class _Allocator> requires(uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && - !__is_allocator<_KeyContainer>::value && !__is_allocator<_MappedContainer>::value) + !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer>) flat_multimap(_KeyContainer, _MappedContainer, _Allocator) -> flat_multimap<typename _KeyContainer::value_type, typename _MappedContainer::value_type, @@ -887,9 +968,8 @@ flat_multimap(_KeyContainer, _MappedContainer, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && uses_allocator_v<_KeyContainer, _Allocator> && - uses_allocator_v<_MappedContainer, _Allocator> && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && + uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -901,8 +981,7 @@ flat_multimap(_KeyContainer, _MappedContainer, _Compare, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -915,7 +994,7 @@ flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare = _ template <class _KeyContainer, class _MappedContainer, class _Allocator> requires(uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && - !__is_allocator<_KeyContainer>::value && !__is_allocator<_MappedContainer>::value) + !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer>) flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Allocator) -> flat_multimap<typename _KeyContainer::value_type, typename _MappedContainer::value_type, @@ -924,9 +1003,8 @@ flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Allocator) _MappedContainer>; template <class _KeyContainer, class _MappedContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && - !__is_allocator<_MappedContainer>::value && uses_allocator_v<_KeyContainer, _Allocator> && - uses_allocator_v<_MappedContainer, _Allocator> && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && !__is_allocator_v<_MappedContainer> && + uses_allocator_v<_KeyContainer, _Allocator> && uses_allocator_v<_MappedContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -938,19 +1016,19 @@ flat_multimap(sorted_equivalent_t, _KeyContainer, _MappedContainer, _Compare, _A _MappedContainer>; template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_multimap(_InputIterator, _InputIterator, _Compare = _Compare()) -> flat_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare>; template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_multimap(sorted_equivalent_t, _InputIterator, _InputIterator, _Compare = _Compare()) -> flat_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare>; template <ranges::input_range _Range, class _Compare = less<__range_key_type<_Range>>, class _Allocator = allocator<byte>, - class = __enable_if_t<!__is_allocator<_Compare>::value && __is_allocator<_Allocator>::value>> + class = __enable_if_t<!__is_allocator_v<_Compare> && __is_allocator_v<_Allocator>>> flat_multimap(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_multimap< __range_key_type<_Range>, __range_mapped_type<_Range>, @@ -958,7 +1036,7 @@ flat_multimap(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Alloc vector<__range_key_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_key_type<_Range>>>, vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>; -template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator_v<_Allocator>>> flat_multimap(from_range_t, _Range&&, _Allocator) -> flat_multimap< __range_key_type<_Range>, __range_mapped_type<_Range>, @@ -967,11 +1045,11 @@ flat_multimap(from_range_t, _Range&&, _Allocator) -> flat_multimap< vector<__range_mapped_type<_Range>, __allocator_traits_rebind_t<_Allocator, __range_mapped_type<_Range>>>>; template <class _Key, class _Tp, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_multimap(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare()) -> flat_multimap<_Key, _Tp, _Compare>; template <class _Key, class _Tp, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_multimap(sorted_equivalent_t, initializer_list<pair<_Key, _Tp>>, _Compare = _Compare()) -> flat_multimap<_Key, _Tp, _Compare>; @@ -980,8 +1058,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/lib/libcxx/include/__flat_map/key_value_iterator.h b/lib/libcxx/include/__flat_map/key_value_iterator.h @@ -20,7 +20,6 @@ #include <__type_traits/conditional.h> #include <__utility/forward.h> #include <__utility/move.h> -#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/lib/libcxx/include/__flat_map/utils.h b/lib/libcxx/include/__flat_map/utils.h @@ -16,6 +16,7 @@ #include <__utility/exception_guard.h> #include <__utility/forward.h> #include <__utility/move.h> +#include <__vector/container_traits.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/lib/libcxx/include/__flat_set/flat_multiset.h b/lib/libcxx/include/__flat_set/flat_multiset.h @@ -13,54 +13,41 @@ #include <__algorithm/equal_range.h> #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/lower_bound.h> -#include <__algorithm/min.h> #include <__algorithm/ranges_equal.h> #include <__algorithm/ranges_inplace_merge.h> #include <__algorithm/ranges_is_sorted.h> #include <__algorithm/ranges_sort.h> -#include <__algorithm/ranges_unique.h> #include <__algorithm/remove_if.h> #include <__algorithm/upper_bound.h> #include <__assert> #include <__compare/synth_three_way.h> -#include <__concepts/convertible_to.h> #include <__concepts/swappable.h> #include <__config> -#include <__cstddef/byte.h> -#include <__cstddef/ptrdiff_t.h> -#include <__flat_map/key_value_iterator.h> #include <__flat_map/sorted_equivalent.h> #include <__flat_set/ra_iterator.h> #include <__flat_set/utils.h> -#include <__functional/invoke.h> #include <__functional/is_transparent.h> #include <__functional/operations.h> #include <__fwd/vector.h> #include <__iterator/concepts.h> -#include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/prev.h> -#include <__iterator/ranges_iterator_traits.h> #include <__iterator/reverse_iterator.h> #include <__memory/allocator_traits.h> #include <__memory/uses_allocator.h> #include <__memory/uses_allocator_construction.h> -#include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/container_compatible_range.h> #include <__ranges/drop_view.h> #include <__ranges/from_range.h> -#include <__ranges/ref_view.h> +#include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/subrange.h> -#include <__ranges/zip_view.h> -#include <__type_traits/conjunction.h> #include <__type_traits/container_traits.h> #include <__type_traits/invoke.h> #include <__type_traits/is_allocator.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_same.h> -#include <__type_traits/maybe_const.h> #include <__utility/as_const.h> #include <__utility/exception_guard.h> #include <__utility/move.h> @@ -108,16 +95,16 @@ public: public: // [flat.multiset.cons], constructors - _LIBCPP_HIDE_FROM_ABI flat_multiset() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && - is_nothrow_default_constructible_v<_Compare>) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset() noexcept( + is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>) : __keys_(), __compare_() {} - _LIBCPP_HIDE_FROM_ABI flat_multiset(const flat_multiset&) = default; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(const flat_multiset&) = 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_multiset(flat_multiset&& __other) noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(flat_multiset&& __other) noexcept( is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>) # if _LIBCPP_HAS_EXCEPTIONS try @@ -134,14 +121,16 @@ public: # endif // _LIBCPP_HAS_EXCEPTIONS } - _LIBCPP_HIDE_FROM_ABI explicit flat_multiset(const key_compare& __comp) : __keys_(), __compare_(__comp) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_multiset(const key_compare& __comp) + : __keys_(), __compare_(__comp) {} - _LIBCPP_HIDE_FROM_ABI explicit flat_multiset(container_type __keys, const key_compare& __comp = key_compare()) + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_multiset(container_type __keys, const key_compare& __comp = key_compare()) : __keys_(std::move(__keys)), __compare_(__comp) { ranges::sort(__keys_, __compare_); } - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(sorted_equivalent_t, container_type __keys, const key_compare& __comp = key_compare()) : __keys_(std::move(__keys)), __compare_(__comp) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); @@ -149,7 +138,7 @@ public: template <class _InputIterator> requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) : __keys_(), __compare_(__comp) { insert(__first, __last); @@ -157,48 +146,53 @@ public: template <class _InputIterator> requires __has_input_iterator_category<_InputIterator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset( sorted_equivalent_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare()) : __keys_(__first, __last), __compare_(__comp) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); } template <_ContainerCompatibleRange<value_type> _Range> - _LIBCPP_HIDE_FROM_ABI flat_multiset(from_range_t __fr, _Range&& __rg) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(from_range_t __fr, _Range&& __rg) : flat_multiset(__fr, std::forward<_Range>(__rg), key_compare()) {} template <_ContainerCompatibleRange<value_type> _Range> - _LIBCPP_HIDE_FROM_ABI flat_multiset(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_multiset(__comp) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(from_range_t, _Range&& __rg, const key_compare& __comp) + : flat_multiset(__comp) { insert_range(std::forward<_Range>(__rg)); } - _LIBCPP_HIDE_FROM_ABI flat_multiset(initializer_list<value_type> __il, const key_compare& __comp = key_compare()) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(initializer_list<value_type> __il, const key_compare& __comp = key_compare()) : flat_multiset(__il.begin(), __il.end(), __comp) {} - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(sorted_equivalent_t, initializer_list<value_type> __il, const key_compare& __comp = key_compare()) : flat_multiset(sorted_equivalent, __il.begin(), __il.end(), __comp) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI explicit flat_multiset(const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 explicit flat_multiset(const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_() {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(const key_compare& __comp, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(const key_compare& __comp, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_(__comp) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(const container_type& __keys, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(const container_type& __keys, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_() { ranges::sort(__keys_, __compare_); } template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_(__comp) { ranges::sort(__keys_, __compare_); @@ -206,14 +200,15 @@ public: template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(sorted_equivalent_t, const container_type& __keys, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(sorted_equivalent_t, const container_type& __keys, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_() { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); } template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(sorted_equivalent_t, const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_(__comp) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); @@ -221,13 +216,14 @@ public: template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(const flat_multiset& __other, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(const flat_multiset& __other, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __other.__keys_)), __compare_(__other.__compare_) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(flat_multiset&& __other, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(flat_multiset&& __other, const _Allocator& __alloc) # if _LIBCPP_HAS_EXCEPTIONS try # endif // _LIBCPP_HAS_EXCEPTIONS @@ -243,14 +239,15 @@ public: template <class _InputIterator, class _Allocator> requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value) - _LIBCPP_HIDE_FROM_ABI flat_multiset(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(_InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_() { insert(__first, __last); } template <class _InputIterator, class _Allocator> requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value) - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(_InputIterator __first, _InputIterator __last, const key_compare& __comp, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_(__comp) { insert(__first, __last); @@ -258,7 +255,7 @@ public: template <class _InputIterator, class _Allocator> requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value) - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(sorted_equivalent_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __first, __last)), __compare_() { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); @@ -266,53 +263,57 @@ public: template <class _InputIterator, class _Allocator> requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value) - _LIBCPP_HIDE_FROM_ABI - flat_multiset(sorted_equivalent_t, - _InputIterator __first, - _InputIterator __last, - const key_compare& __comp, - const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset( + sorted_equivalent_t, + _InputIterator __first, + _InputIterator __last, + const key_compare& __comp, + const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc, __first, __last)), __compare_(__comp) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys_, __compare_), "Key container is not sorted"); } template <_ContainerCompatibleRange<value_type> _Range, class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(from_range_t, _Range&& __rg, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(from_range_t, _Range&& __rg, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_() { insert_range(std::forward<_Range>(__rg)); } template <_ContainerCompatibleRange<value_type> _Range, class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(from_range_t, _Range&& __rg, const key_compare& __comp, const _Allocator& __alloc) : __keys_(std::make_obj_using_allocator<container_type>(__alloc)), __compare_(__comp) { insert_range(std::forward<_Range>(__rg)); } template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(initializer_list<value_type> __il, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(initializer_list<value_type> __il, const _Allocator& __alloc) : flat_multiset(__il.begin(), __il.end(), __alloc) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset(initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc) : flat_multiset(__il.begin(), __il.end(), __comp, __alloc) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset(sorted_equivalent_t, initializer_list<value_type> __il, const _Allocator& __alloc) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 + flat_multiset(sorted_equivalent_t, initializer_list<value_type> __il, const _Allocator& __alloc) : flat_multiset(sorted_equivalent, __il.begin(), __il.end(), __alloc) {} template <class _Allocator> requires uses_allocator<container_type, _Allocator>::value - _LIBCPP_HIDE_FROM_ABI flat_multiset( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset( sorted_equivalent_t, initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc) : flat_multiset(sorted_equivalent, __il.begin(), __il.end(), __comp, __alloc) {} - _LIBCPP_HIDE_FROM_ABI flat_multiset& operator=(initializer_list<value_type> __il) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset& operator=(initializer_list<value_type> __il) { clear(); insert(__il); return *this; @@ -321,9 +322,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_multiset& operator=(const flat_multiset&) = default; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset& operator=(const flat_multiset&) = default; - _LIBCPP_HIDE_FROM_ABI flat_multiset& operator=(flat_multiset&& __other) noexcept( + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 flat_multiset& operator=(flat_multiset&& __other) noexcept( is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) { auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; }); auto __clear_self_guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); @@ -334,30 +335,60 @@ public: } // iterators - _LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return iterator(std::as_const(__keys_).begin()); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const noexcept { return const_iterator(__keys_.begin()); } - _LIBCPP_HIDE_FROM_ABI iterator end() noexcept { return iterator(std::as_const(__keys_).end()); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const noexcept { return const_iterator(__keys_.end()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { + return iterator(std::as_const(__keys_).begin()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept { + return const_iterator(__keys_.begin()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { + return iterator(std::as_const(__keys_).end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept { + return const_iterator(__keys_.end()); + } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept { + return reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rend() noexcept { + return reverse_iterator(begin()); + } + [[nodiscard]] _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()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { + return begin(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { + return end(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(begin()); + } // capacity - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); } - _LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool empty() const noexcept { + return __keys_.empty(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { + return __keys_.size(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept { + return __keys_.max_size(); + } // [flat.multiset.modifiers], modifiers template <class... _Args> requires is_constructible_v<value_type, _Args...> - _LIBCPP_HIDE_FROM_ABI iterator emplace(_Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator emplace(_Args&&... __args) { if constexpr (sizeof...(__args) == 1 && (is_same_v<remove_cvref_t<_Args>, _Key> && ...)) { return __emplace(std::forward<_Args>(__args)...); } else { @@ -367,7 +398,7 @@ public: template <class... _Args> requires is_constructible_v<value_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) { if constexpr (sizeof...(__args) == 1 && (is_same_v<remove_cvref_t<_Args>, _Key> && ...)) { return __emplace_hint(std::move(__hint), std::forward<_Args>(__args)...); } else { @@ -375,21 +406,23 @@ public: } } - _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 _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); } @@ -398,7 +431,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); } @@ -407,7 +441,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)); } @@ -415,26 +449,38 @@ public: __append_sort_merge</*WasSorted = */ false>(std::forward<_Range>(__range)); } - _LIBCPP_HIDE_FROM_ABI void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); } + template <_ContainerCompatibleRange<value_type> _Range> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(sorted_equivalent_t, _Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } - _LIBCPP_HIDE_FROM_ABI void insert(sorted_equivalent_t, initializer_list<value_type> __il) { + __append_sort_merge</*WasSorted = */ true>(std::forward<_Range>(__range)); + } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) { + insert(__il.begin(), __il.end()); + } + + _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 container_type extract() && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 container_type extract() && { auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); auto __ret = std::move(__keys_); return __ret; } - _LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void replace(container_type&& __keys) { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(ranges::is_sorted(__keys, __compare_), "Key container is not sorted"); auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); __keys_ = std::move(__keys); __guard.__complete(); } - _LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator erase(iterator __position) { auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); auto __key_iter = __keys_.erase(__position.__base()); __on_failure.__complete(); @@ -444,7 +490,7 @@ public: // The following overload is the same as the iterator overload // iterator erase(const_iterator __position); - _LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) { + _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); @@ -454,149 +500,170 @@ public: template <class _Kp> requires(__is_transparent_v<_Compare> && !is_convertible_v<_Kp &&, iterator> && !is_convertible_v<_Kp &&, const_iterator>) - _LIBCPP_HIDE_FROM_ABI size_type erase(_Kp&& __x) { + _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 = __keys_.erase(__first.__base(), __last.__base()); __on_failure.__complete(); return iterator(std::move(__key_it)); } - _LIBCPP_HIDE_FROM_ABI void swap(flat_multiset& __y) noexcept { - // warning: The spec has unconditional noexcept, which means that - // if any of the following functions throw an exception, - // std::terminate will be called - // This is discussed in P3567, which hasn't been voted on yet. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_multiset& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + clear() /* noexcept */; + __y.clear() /* noexcept */; + }); ranges::swap(__compare_, __y.__compare_); ranges::swap(__keys_, __y.__keys_); + __on_failure.__complete(); } - _LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __keys_.clear(); } // observers - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare value_comp() const { + return __compare_; + } // map operations - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); } + [[nodiscard]] _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); } + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI iterator find(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Kp& __x) const { + [[nodiscard]] _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 { + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI size_type count(const _Kp& __x) const { + [[nodiscard]] _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(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const { + return find(__x) != end(); + } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const { + [[nodiscard]] _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) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) { const auto& __keys = __keys_; return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator + lower_bound(const key_type& __x) const { return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) { const auto& __keys = __keys_; return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const { return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) { const auto& __keys = __keys_; return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator + upper_bound(const key_type& __x) const { return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) { const auto& __keys = __keys_; return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const { return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __x) { + [[nodiscard]] _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 { + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _Kp& __x) { + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _Kp& __x) const { + [[nodiscard]] _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_multiset& __x, const flat_multiset& __y) { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool + operator==(const flat_multiset& __x, const flat_multiset& __y) { return ranges::equal(__x, __y); } - friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_multiset& __x, const flat_multiset& __y) { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 auto + operator<=>(const flat_multiset& __x, const flat_multiset& __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_multiset& __x, flat_multiset& __y) noexcept { __x.swap(__y); } + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_multiset& __x, flat_multiset& __y) noexcept(noexcept(__x.swap(__y))) { + __x.swap(__y); + } private: template <bool _WasSorted, class... _Args> - _LIBCPP_HIDE_FROM_ABI void __append_sort_merge(_Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void __append_sort_merge(_Args&&... __args) { auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; }); size_type __old_size = size(); __flat_set_utils::__append(*this, std::forward<_Args>(__args)...); @@ -604,20 +671,20 @@ private: ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_); } else { _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT( - ranges::is_sorted(__keys_ | ranges::views::drop(__old_size)), "Key container is not sorted"); + ranges::is_sorted(__keys_ | ranges::views::drop(__old_size), __compare_), "Key container is not sorted"); } ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_); __on_failure.__complete(); } template <class _Kp> - _LIBCPP_HIDE_FROM_ABI iterator __emplace(_Kp&& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator __emplace(_Kp&& __key) { auto __it = upper_bound(__key); return __flat_set_utils::__emplace_exact_pos(*this, __it, std::forward<_Kp>(__key)); } template <class _Kp> - _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator __emplace_hint(const_iterator __hint, _Kp&& __key) { auto __prev_larger = __hint != cbegin() && __compare_(__key, *std::prev(__hint)); auto __next_smaller = __hint != cend() && __compare_(*__hint, __key); @@ -649,7 +716,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)) { @@ -659,29 +726,30 @@ 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) { using __iter = _If<is_const_v<__libcpp_remove_reference_t<_Self>>, const_iterator, iterator>; auto [__key_first, __key_last] = std::equal_range(__self.__keys_.begin(), __self.__keys_.end(), __key, __self.__compare_); return std::make_pair(__iter(__key_first), __iter(__key_last)); } - _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) { __keys_.reserve(__size); } } template <class _Key2, class _Compare2, class _KeyContainer2, class _Predicate> - friend typename flat_multiset<_Key2, _Compare2, _KeyContainer2>::size_type + friend typename flat_multiset<_Key2, _Compare2, _KeyContainer2>::size_type _LIBCPP_CONSTEXPR_SINCE_CXX26 erase_if(flat_multiset<_Key2, _Compare2, _KeyContainer2>&, _Predicate); _KeyContainer __keys_; _LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_; struct __key_equiv { - _LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {} - _LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const { + _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_; @@ -689,7 +757,7 @@ private: }; template <class _KeyContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -697,12 +765,12 @@ flat_multiset(_KeyContainer, _Compare = _Compare()) -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Allocator> - requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator_v<_KeyContainer>) flat_multiset(_KeyContainer, _Allocator) -> flat_multiset<typename _KeyContainer::value_type, less<typename _KeyContainer::value_type>, _KeyContainer>; template <class _KeyContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && uses_allocator_v<_KeyContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, @@ -711,7 +779,7 @@ flat_multiset(_KeyContainer, _Compare, _Allocator) -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -719,12 +787,12 @@ flat_multiset(sorted_equivalent_t, _KeyContainer, _Compare = _Compare()) -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Allocator> - requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator_v<_KeyContainer>) flat_multiset(sorted_equivalent_t, _KeyContainer, _Allocator) -> flat_multiset<typename _KeyContainer::value_type, less<typename _KeyContainer::value_type>, _KeyContainer>; template <class _KeyContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && uses_allocator_v<_KeyContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, @@ -732,37 +800,37 @@ template <class _KeyContainer, class _Compare, class _Allocator> flat_multiset(sorted_equivalent_t, _KeyContainer, _Compare, _Allocator) -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>; -template <class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +template <class _InputIterator, class _Compare = less<__iterator_value_type<_InputIterator>>> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_multiset(_InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_multiset<__iter_value_type<_InputIterator>, _Compare>; + -> flat_multiset<__iterator_value_type<_InputIterator>, _Compare>; -template <class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +template <class _InputIterator, class _Compare = less<__iterator_value_type<_InputIterator>>> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_multiset(sorted_equivalent_t, _InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_multiset<__iter_value_type<_InputIterator>, _Compare>; + -> flat_multiset<__iterator_value_type<_InputIterator>, _Compare>; template <ranges::input_range _Range, class _Compare = less<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = __enable_if_t<!__is_allocator<_Compare>::value && __is_allocator<_Allocator>::value>> + class = __enable_if_t<!__is_allocator_v<_Compare> && __is_allocator_v<_Allocator>>> flat_multiset(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_multiset< ranges::range_value_t<_Range>, _Compare, vector<ranges::range_value_t<_Range>, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; -template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator_v<_Allocator>>> flat_multiset(from_range_t, _Range&&, _Allocator) -> flat_multiset< ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, vector<ranges::range_value_t<_Range>, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; template <class _Key, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_multiset(initializer_list<_Key>, _Compare = _Compare()) -> flat_multiset<_Key, _Compare>; template <class _Key, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_multiset(sorted_equivalent_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_multiset<_Key, _Compare>; template <class _Key, class _Compare, class _KeyContainer, class _Allocator> @@ -770,7 +838,7 @@ struct uses_allocator<flat_multiset<_Key, _Compare, _KeyContainer>, _Allocator> : bool_constant<uses_allocator_v<_KeyContainer, _Allocator> > {}; template <class _Key, class _Compare, class _KeyContainer, class _Predicate> -_LIBCPP_HIDE_FROM_ABI typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 typename flat_multiset<_Key, _Compare, _KeyContainer>::size_type erase_if(flat_multiset<_Key, _Compare, _KeyContainer>& __flat_multiset, _Predicate __pred) { auto __guard = std::__make_exception_guard([&] { __flat_multiset.clear(); }); auto __it = diff --git a/lib/libcxx/include/__flat_set/flat_set.h b/lib/libcxx/include/__flat_set/flat_set.h @@ -12,7 +12,6 @@ #include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/lower_bound.h> -#include <__algorithm/min.h> #include <__algorithm/ranges_adjacent_find.h> #include <__algorithm/ranges_equal.h> #include <__algorithm/ranges_inplace_merge.h> @@ -24,20 +23,16 @@ #include <__compare/synth_three_way.h> #include <__concepts/swappable.h> #include <__config> -#include <__cstddef/ptrdiff_t.h> #include <__flat_map/sorted_unique.h> #include <__flat_set/ra_iterator.h> #include <__flat_set/utils.h> -#include <__functional/invoke.h> #include <__functional/is_transparent.h> #include <__functional/operations.h> #include <__fwd/vector.h> #include <__iterator/concepts.h> -#include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> #include <__iterator/prev.h> -#include <__iterator/ranges_iterator_traits.h> #include <__iterator/reverse_iterator.h> #include <__memory/allocator_traits.h> #include <__memory/uses_allocator.h> @@ -47,10 +42,7 @@ #include <__ranges/container_compatible_range.h> #include <__ranges/drop_view.h> #include <__ranges/from_range.h> -#include <__ranges/ref_view.h> #include <__ranges/size.h> -#include <__ranges/subrange.h> -#include <__type_traits/conjunction.h> #include <__type_traits/container_traits.h> #include <__type_traits/invoke.h> #include <__type_traits/is_allocator.h> @@ -347,38 +339,42 @@ public: } // iterators - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator begin() noexcept { return iterator(std::as_const(__keys_).begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator begin() const noexcept { return const_iterator(__keys_.begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator end() noexcept { return iterator(std::as_const(__keys_).end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator end() const noexcept { return const_iterator(__keys_.end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 reverse_iterator rbegin() noexcept { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator rend() 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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cbegin() const noexcept { + return begin(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator cend() const noexcept { + return end(); + } + [[nodiscard]] _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 { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } @@ -387,9 +383,13 @@ public: return __keys_.empty(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { return __keys_.size(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type size() const noexcept { + return __keys_.size(); + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept { return __keys_.max_size(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type max_size() const noexcept { + return __keys_.max_size(); + } // [flat.set.modifiers], modifiers template <class... _Args> @@ -466,6 +466,15 @@ public: __append_sort_merge_unique</*WasSorted = */ false>(std::forward<_Range>(__range)); } + template <_ContainerCompatibleRange<value_type> _Range> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert_range(std::sorted_unique_t, _Range&& __range) { + if constexpr (ranges::sized_range<_Range>) { + __reserve(ranges::size(__range)); + } + + __append_sort_merge_unique</*WasSorted = */ true>(std::forward<_Range>(__range)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); } @@ -474,7 +483,7 @@ public: insert(sorted_unique, __il.begin(), __il.end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 container_type extract() && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 container_type extract() && { auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; }); auto __ret = std::move(__keys_); return __ret; @@ -524,123 +533,131 @@ public: return iterator(std::move(__key_it)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __y) noexcept { - // warning: The spec has unconditional noexcept, which means that - // if any of the following functions throw an exception, - // std::terminate will be called. - // This is discussed in P2767, which hasn't been voted on yet. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_set& __y) noexcept(is_nothrow_swappable_v<container_type> && is_nothrow_swappable_v<key_compare>) { + auto __on_failure = std::__make_exception_guard([&]() noexcept { + clear() /* noexcept */; + __y.clear() /* noexcept */; + }); ranges::swap(__compare_, __y.__compare_); ranges::swap(__keys_, __y.__keys_); + __on_failure.__complete(); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept { __keys_.clear(); } // observers - _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 __compare_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 key_compare key_comp() const { return __compare_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 value_compare value_comp() const { + return __compare_; + } // set operations - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const key_type& __x) { return __find_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const key_type& __x) const { + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator find(const _Kp& __x) { return __find_impl(*this, __x); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator find(const _Kp& __x) const { return __find_impl(*this, __x); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const key_type& __x) const { return contains(__x) ? 1 : 0; } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 size_type count(const _Kp& __x) const { return contains(__x) ? 1 : 0; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const key_type& __x) const { return find(__x) != end(); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool contains(const _Kp& __x) const { return find(__x) != end(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const key_type& __x) { const auto& __keys = __keys_; return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator + lower_bound(const key_type& __x) const { return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator lower_bound(const _Kp& __x) { const auto& __keys = __keys_; return iterator(std::lower_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator lower_bound(const _Kp& __x) const { return const_iterator(std::lower_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const key_type& __x) { const auto& __keys = __keys_; return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const key_type& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator + upper_bound(const key_type& __x) const { return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 iterator upper_bound(const _Kp& __x) { const auto& __keys = __keys_; return iterator(std::upper_bound(__keys.begin(), __keys.end(), __x, __compare_)); } template <class _Kp> requires __is_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 const_iterator upper_bound(const _Kp& __x) const { return const_iterator(std::upper_bound(__keys_.begin(), __keys_.end(), __x, __compare_)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const key_type& __x) { + [[nodiscard]] _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 _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator> + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<iterator, iterator> equal_range(const _Kp& __x) { + [[nodiscard]] _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_transparent_v<_Compare> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 pair<const_iterator, const_iterator> + [[nodiscard]] _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); } @@ -655,13 +672,14 @@ public: __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } - friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_set& __x, flat_set& __y) noexcept { + friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void + swap(flat_set& __x, flat_set& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 bool __is_sorted_and_unique(auto&& __key_container) const { - auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); }; + auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) -> bool { return !__compare_(__x, __y); }; return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container); } @@ -774,19 +792,19 @@ private: }; template <class _KeyContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) flat_set(_KeyContainer, _Compare = _Compare()) -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Allocator> - requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator_v<_KeyContainer>) flat_set(_KeyContainer, _Allocator) -> flat_set<typename _KeyContainer::value_type, less<typename _KeyContainer::value_type>, _KeyContainer>; template <class _KeyContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && uses_allocator_v<_KeyContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, @@ -794,7 +812,7 @@ template <class _KeyContainer, class _Compare, class _Allocator> flat_set(_KeyContainer, _Compare, _Allocator) -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Compare = less<typename _KeyContainer::value_type>> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, const typename _KeyContainer::value_type&>) @@ -802,12 +820,12 @@ flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare()) -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>; template <class _KeyContainer, class _Allocator> - requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value) + requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator_v<_KeyContainer>) flat_set(sorted_unique_t, _KeyContainer, _Allocator) -> flat_set<typename _KeyContainer::value_type, less<typename _KeyContainer::value_type>, _KeyContainer>; template <class _KeyContainer, class _Compare, class _Allocator> - requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value && + requires(!__is_allocator_v<_Compare> && !__is_allocator_v<_KeyContainer> && uses_allocator_v<_KeyContainer, _Allocator> && is_invocable_v<const _Compare&, const typename _KeyContainer::value_type&, @@ -815,37 +833,37 @@ template <class _KeyContainer, class _Compare, class _Allocator> flat_set(sorted_unique_t, _KeyContainer, _Compare, _Allocator) -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>; -template <class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +template <class _InputIterator, class _Compare = less<__iterator_value_type<_InputIterator>>> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_set(_InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + -> flat_set<__iterator_value_type<_InputIterator>, _Compare>; -template <class _InputIterator, class _Compare = less<__iter_value_type<_InputIterator>>> - requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator<_Compare>::value) +template <class _InputIterator, class _Compare = less<__iterator_value_type<_InputIterator>>> + requires(__has_input_iterator_category<_InputIterator>::value && !__is_allocator_v<_Compare>) flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare()) - -> flat_set<__iter_value_type<_InputIterator>, _Compare>; + -> flat_set<__iterator_value_type<_InputIterator>, _Compare>; template <ranges::input_range _Range, class _Compare = less<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = __enable_if_t<!__is_allocator<_Compare>::value && __is_allocator<_Allocator>::value>> + class = __enable_if_t<!__is_allocator_v<_Compare> && __is_allocator_v<_Allocator>>> flat_set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> flat_set< ranges::range_value_t<_Range>, _Compare, vector<ranges::range_value_t<_Range>, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; -template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = __enable_if_t<__is_allocator_v<_Allocator>>> flat_set(from_range_t, _Range&&, _Allocator) -> flat_set< ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, vector<ranges::range_value_t<_Range>, __allocator_traits_rebind_t<_Allocator, ranges::range_value_t<_Range>>>>; template <class _Key, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; template <class _Key, class _Compare = less<_Key>> - requires(!__is_allocator<_Compare>::value) + requires(!__is_allocator_v<_Compare>) flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>; template <class _Key, class _Compare, class _KeyContainer, class _Allocator> diff --git a/lib/libcxx/include/__format/concepts.h b/lib/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/lib/libcxx/include/__format/extended_grapheme_cluster_table.h b/lib/libcxx/include/__format/extended_grapheme_cluster_table.h @@ -61,7 +61,7 @@ #ifndef _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H #define _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H -#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/upper_bound.h> #include <__config> #include <__cstddef/ptrdiff_t.h> #include <__iterator/access.h> @@ -1647,7 +1647,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[1501] = { // size. Then the upper bound for code point 3 will return the entry after // 0x1810. After moving to the previous entry the algorithm arrives at the // correct entry. - ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries; + ptrdiff_t __i = + std::upper_bound(std::begin(__entries), std::end(__entries), (__code_point << 11) | 0x7ffu) - __entries; if (__i == 0) return __property::__none; diff --git a/lib/libcxx/include/__format/fmt_pair_like.h b/lib/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/lib/libcxx/include/__format/format_arg.h b/lib/libcxx/include/__format/format_arg.h @@ -149,7 +149,7 @@ _LIBCPP_HIDE_FROM_ABI decltype(auto) __visit_format_arg(_Visitor&& __vis, basic_ __libcpp_unreachable(); } -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# if _LIBCPP_STD_VER >= 26 template <class _Rp, class _Visitor, class _Context> _LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { @@ -200,7 +200,7 @@ _LIBCPP_HIDE_FROM_ABI _Rp __visit_format_arg(_Visitor&& __vis, basic_format_arg< __libcpp_unreachable(); } -# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif // _LIBCPP_STD_VER >= 26 /// Contains the values used in basic_format_arg. /// @@ -285,7 +285,7 @@ public: _LIBCPP_HIDE_FROM_ABI explicit operator bool() const noexcept { return __type_ != __format::__arg_t::__none; } -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# if _LIBCPP_STD_VER >= 26 // This function is user facing, so it must wrap the non-standard types of // the "variant" in a handle to stay conforming. See __arg_t for more details. @@ -329,7 +329,7 @@ public: } } -# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif // _LIBCPP_STD_VER >= 26 private: using char_type = typename _Context::char_type; @@ -371,11 +371,8 @@ private: // This function is user facing, so it must wrap the non-standard types of // the "variant" in a handle to stay conforming. See __arg_t for more details. template <class _Visitor, class _Context> -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER -_LIBCPP_DEPRECATED_IN_CXX26 -# endif - _LIBCPP_HIDE_FROM_ABI decltype(auto) - visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { +_LIBCPP_DEPRECATED_IN_CXX26 _LIBCPP_HIDE_FROM_ABI decltype(auto) +visit_format_arg(_Visitor&& __vis, basic_format_arg<_Context> __arg) { switch (__arg.__type_) { # if _LIBCPP_HAS_INT128 case __format::__arg_t::__i128: { @@ -387,7 +384,7 @@ _LIBCPP_DEPRECATED_IN_CXX26 typename __basic_format_arg_value<_Context>::__handle __h{__arg.__value_.__u128_}; return std::invoke(std::forward<_Visitor>(__vis), typename basic_format_arg<_Context>::handle{__h}); } -# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif // _LIBCPP_HAS_INT128 default: return std::__visit_format_arg(std::forward<_Visitor>(__vis), __arg); } diff --git a/lib/libcxx/include/__format/format_args.h b/lib/libcxx/include/__format/format_args.h @@ -40,7 +40,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> get(size_t __id) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> get(size_t __id) const noexcept { if (__id >= __size_) return basic_format_arg<_Context>{}; diff --git a/lib/libcxx/include/__format/format_context.h b/lib/libcxx/include/__format/format_context.h @@ -80,17 +80,17 @@ public: template <class _Tp> using formatter_type = formatter<_Tp, _CharT>; - _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_format_arg<basic_format_context> arg(size_t __id) const noexcept { return __args_.get(__id); } # if _LIBCPP_HAS_LOCALIZATION - _LIBCPP_HIDE_FROM_ABI std::locale locale() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI std::locale locale() { if (!__loc_) __loc_ = std::locale{}; return *__loc_; } # endif - _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator out() { return std::move(__out_it_); } _LIBCPP_HIDE_FROM_ABI void advance_to(iterator __it) { __out_it_ = std::move(__it); } private: @@ -175,13 +175,13 @@ public: __format::__determine_arg_t<basic_format_context, decltype(__arg)>(), __basic_format_arg_value<basic_format_context>(__arg)}; }; -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# if _LIBCPP_STD_VER >= 26 return static_cast<_Context*>(__c)->arg(__id).visit(std::move(__visitor)); # else _LIBCPP_SUPPRESS_DEPRECATED_PUSH return std::visit_format_arg(std::move(__visitor), static_cast<_Context*>(__c)->arg(__id)); _LIBCPP_SUPPRESS_DEPRECATED_POP -# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# endif // _LIBCPP_STD_VER >= 26 }) { } diff --git a/lib/libcxx/include/__format/format_parse_context.h b/lib/libcxx/include/__format/format_parse_context.h @@ -41,8 +41,8 @@ public: basic_format_parse_context(const basic_format_parse_context&) = delete; basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; - _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { return __begin_; } - _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { return __end_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { return __begin_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { return __end_; } _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(const_iterator __it) { __begin_ = __it; } _LIBCPP_HIDE_FROM_ABI constexpr size_t next_arg_id() { diff --git a/lib/libcxx/include/__format/formatter_output.h b/lib/libcxx/include/__format/formatter_output.h @@ -45,7 +45,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace __formatter { -struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result { +struct __padding_size_result { size_t __before_; size_t __after_; }; @@ -151,45 +151,41 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) } } -# if _LIBCPP_HAS_UNICODE template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> - requires(same_as<_CharT, char>) _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { - std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0])); - if (__bytes == 0) - return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); - - for (size_t __i = 0; __i < __n; ++__i) - __out_it = __formatter::__copy( - std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); - return __out_it; -} - +# if _LIBCPP_HAS_UNICODE + if constexpr (same_as<_CharT, char>) { + std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0])); + if (__bytes == 0) + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); + + for (size_t __i = 0; __i < __n; ++__i) + __out_it = __formatter::__copy( + std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); + return __out_it; # if _LIBCPP_HAS_WIDE_CHARACTERS -template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> - requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) -_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { - if (!__unicode::__is_high_surrogate(__value.__data[0])) - return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); - - for (size_t __i = 0; __i < __n; ++__i) - __out_it = __formatter::__copy( - std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); - return __out_it; -} - -template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> - requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) -_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { - return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); -} + } else if constexpr (same_as<_CharT, wchar_t>) { + if constexpr (sizeof(wchar_t) == 2) { + if (!__unicode::__is_high_surrogate(__value.__data[0])) + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); + + for (size_t __i = 0; __i < __n; ++__i) + __out_it = __formatter::__copy( + std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); + return __out_it; + } else if constexpr (sizeof(wchar_t) == 4) { + return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); + } else { + static_assert(false, "expected sizeof(wchar_t) to be 2 or 4"); + } # endif // _LIBCPP_HAS_WIDE_CHARACTERS -# else // _LIBCPP_HAS_UNICODE -template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> -_LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { + } else { + static_assert(false, "Unexpected CharT"); + } +# else // _LIBCPP_HAS_UNICODE return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); +# endif // _LIBCPP_HAS_UNICODE } -# endif // _LIBCPP_HAS_UNICODE /// Writes the input to the output with the required padding. /// diff --git a/lib/libcxx/include/__format/indic_conjunct_break_table.h b/lib/libcxx/include/__format/indic_conjunct_break_table.h @@ -61,7 +61,7 @@ #ifndef _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H #define _LIBCPP___FORMAT_INDIC_CONJUNCT_BREAK_TABLE_H -#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/upper_bound.h> #include <__config> #include <__cstddef/ptrdiff_t.h> #include <__iterator/access.h> @@ -531,7 +531,8 @@ _LIBCPP_HIDE_FROM_ABI inline constexpr uint32_t __entries[403] = { // size. Then the upper bound for code point 3 will return the entry after // 0x1810. After moving to the previous entry the algorithm arrives at the // correct entry. - ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 11) | 0x7ffu) - __entries; + ptrdiff_t __i = + std::upper_bound(std::begin(__entries), std::end(__entries), (__code_point << 11) | 0x7ffu) - __entries; if (__i == 0) return __property::__none; diff --git a/lib/libcxx/include/__format/range_default_formatter.h b/lib/libcxx/include/__format/range_default_formatter.h @@ -16,10 +16,11 @@ #include <__algorithm/ranges_copy.h> #include <__chrono/statically_widen.h> -#include <__concepts/same_as.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> #include <__iterator/back_insert_iterator.h> #include <__ranges/concepts.h> @@ -42,51 +43,11 @@ concept __const_formattable_range = template <class _Rp, class _CharT> using __fmt_maybe_const _LIBCPP_NODEBUG = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>; -_LIBCPP_DIAGNOSTIC_PUSH -_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") -_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") -// This shadows map, set, and string. -enum class range_format { disabled, map, set, sequence, string, debug_string }; -_LIBCPP_DIAGNOSTIC_POP - // There is no definition of this struct, it's purely intended to be used to // generate diagnostics. template <class _Rp> struct __instantiated_the_primary_template_of_format_kind; -template <class _Rp> -constexpr range_format format_kind = [] { - // [format.range.fmtkind]/1 - // A program that instantiates the primary template of format_kind is ill-formed. - static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); - return range_format::disabled; -}(); - -template <ranges::input_range _Rp> - requires same_as<_Rp, remove_cvref_t<_Rp>> -inline constexpr range_format format_kind<_Rp> = [] { - // [format.range.fmtkind]/2 - - // 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true, - // Otherwise format_kind<R> is range_format::disabled. - if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>) - return range_format::disabled; - // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type: - else if constexpr (requires { typename _Rp::key_type; }) { - // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ... - if constexpr (requires { typename _Rp::mapped_type; } && - // 2.2.1 ... If either U is a specialization of pair or U is a specialization - // of tuple and tuple_size_v<U> == 2 - __fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>) - return range_format::map; - else - // 2.2.2 Otherwise format_kind<R> is range_format::set. - return range_format::set; - } else - // 2.3 Otherwise, format_kind<R> is range_format::sequence. - return range_format::sequence; -}(); - template <range_format _Kp, ranges::input_range _Rp, class _CharT> struct __range_default_formatter; diff --git a/lib/libcxx/include/__format/range_format.h b/lib/libcxx/include/__format/range_format.h @@ -0,0 +1,71 @@ +// -*- 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_RANGE_FORMAT_H +#define _LIBCPP___FORMAT_RANGE_FORMAT_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__concepts/same_as.h> +#include <__config> +#include <__format/fmt_pair_like.h> +#include <__ranges/concepts.h> +#include <__type_traits/remove_cvref.h> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") +// This shadows map, set, and string. +enum class range_format { disabled, map, set, sequence, string, debug_string }; +_LIBCPP_DIAGNOSTIC_POP + +template <class _Rp> +constexpr range_format format_kind = [] { + // [format.range.fmtkind]/1 + // A program that instantiates the primary template of format_kind is ill-formed. + static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); + return range_format::disabled; +}(); + +template <ranges::input_range _Rp> + requires same_as<_Rp, remove_cvref_t<_Rp>> +inline constexpr range_format format_kind<_Rp> = [] { + // [format.range.fmtkind]/2 + + // 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true, + // Otherwise format_kind<R> is range_format::disabled. + if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>) + return range_format::disabled; + // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type: + else if constexpr (requires { typename _Rp::key_type; }) { + // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ... + if constexpr (requires { typename _Rp::mapped_type; } && + // 2.2.1 ... If either U is a specialization of pair or U is a specialization + // of tuple and tuple_size_v<U> == 2 + __fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>) + return range_format::map; + else + // 2.2.2 Otherwise format_kind<R> is range_format::set. + return range_format::set; + } else + // 2.3 Otherwise, format_kind<R> is range_format::sequence. + return range_format::sequence; +}(); + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +#endif diff --git a/lib/libcxx/include/__format/range_formatter.h b/lib/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/lib/libcxx/include/__format/width_estimation_table.h b/lib/libcxx/include/__format/width_estimation_table.h @@ -61,9 +61,10 @@ #ifndef _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H #define _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H -#include <__algorithm/ranges_upper_bound.h> +#include <__algorithm/upper_bound.h> #include <__config> #include <__cstddef/ptrdiff_t.h> +#include <__iterator/access.h> #include <cstdint> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -255,7 +256,8 @@ inline constexpr uint32_t __table_upper_bound = 0x0003fffd; if (__code_point < (__entries[0] >> 14)) return 1; - ptrdiff_t __i = std::ranges::upper_bound(__entries, (__code_point << 14) | 0x3fffu) - __entries; + ptrdiff_t __i = + std::upper_bound(std::begin(__entries), std::end(__entries), (__code_point << 14) | 0x3fffu) - __entries; if (__i == 0) return 1; diff --git a/lib/libcxx/include/__functional/bind.h b/lib/libcxx/include/__functional/bind.h @@ -81,17 +81,12 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __mu(reference_w return __t.get(); } -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...>) { - 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 [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> __invoke_result_t<_Ti&, _Uj...> { + return __ti(std::forward<_Uj>(std::get<_Indices>(__uj))...); + }(__index_sequence_for<_Uj...>{}); } template <bool _IsPh, class _Ti, class _Uj> @@ -191,7 +186,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 +200,6 @@ private: _Fd __f_; _Td __bound_args_; - typedef typename __make_tuple_indices<sizeof...(_BoundArgs)>::type __indices; - public: template < class _Gp, @@ -219,14 +212,16 @@ 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_, __index_sequence_for<_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_, __index_sequence_for<_BoundArgs...>(), tuple<_Args&&...>(std::forward<_Args>(__args)...)); } }; @@ -273,14 +268,14 @@ template <class _Rp, class _Fp, class... _BoundArgs> struct is_bind_expression<__bind_r<_Rp, _Fp, _BoundArgs...> > : public true_type {}; template <class _Fp, class... _BoundArgs> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind<_Fp, _BoundArgs...> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind<_Fp, _BoundArgs...> bind(_Fp&& __f, _BoundArgs&&... __bound_args) { typedef __bind<_Fp, _BoundArgs...> type; return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); } template <class _Rp, class _Fp, class... _BoundArgs> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind_r<_Rp, _Fp, _BoundArgs...> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bind_r<_Rp, _Fp, _BoundArgs...> bind(_Fp&& __f, _BoundArgs&&... __bound_args) { typedef __bind_r<_Rp, _Fp, _BoundArgs...> type; return type(std::forward<_Fp>(__f), std::forward<_BoundArgs>(__bound_args)...); diff --git a/lib/libcxx/include/__functional/bind_back.h b/lib/libcxx/include/__functional/bind_back.h @@ -64,7 +64,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) n # if _LIBCPP_STD_VER >= 23 template <class _Fn, class... _Args> -_LIBCPP_HIDE_FROM_ABI constexpr auto bind_back(_Fn&& __f, _Args&&... __args) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto bind_back(_Fn&& __f, _Args&&... __args) { static_assert(is_constructible_v<decay_t<_Fn>, _Fn>, "bind_back requires decay_t<F> to be constructible from F"); static_assert(is_move_constructible_v<decay_t<_Fn>>, "bind_back requires decay_t<F> to be move constructible"); static_assert((is_constructible_v<decay_t<_Args>, _Args> && ...), diff --git a/lib/libcxx/include/__functional/bind_front.h b/lib/libcxx/include/__functional/bind_front.h @@ -43,7 +43,7 @@ struct __bind_front_t : __perfect_forward<__bind_front_op, _Fn, _BoundArgs...> { template <class _Fn, class... _Args> requires is_constructible_v<decay_t<_Fn>, _Fn> && is_move_constructible_v<decay_t<_Fn>> && (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...) -_LIBCPP_HIDE_FROM_ABI constexpr auto bind_front(_Fn&& __f, _Args&&... __args) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto bind_front(_Fn&& __f, _Args&&... __args) { return __bind_front_t<decay_t<_Fn>, decay_t<_Args>...>(std::forward<_Fn>(__f), std::forward<_Args>(__args)...); } diff --git a/lib/libcxx/include/__functional/function.h b/lib/libcxx/include/__functional/function.h @@ -15,16 +15,14 @@ #include <__cstddef/nullptr_t.h> #include <__exception/exception.h> #include <__functional/binary_function.h> -#include <__functional/invoke.h> #include <__functional/unary_function.h> #include <__memory/addressof.h> #include <__type_traits/aligned_storage.h> #include <__type_traits/decay.h> -#include <__type_traits/is_core_convertible.h> +#include <__type_traits/invoke.h> #include <__type_traits/is_scalar.h> #include <__type_traits/is_trivially_constructible.h> #include <__type_traits/is_trivially_destructible.h> -#include <__type_traits/is_void.h> #include <__type_traits/strip_signature.h> #include <__utility/forward.h> #include <__utility/move.h> @@ -95,29 +93,29 @@ template <class _Rp, class _A1, class _A2> struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> : public __binary_function<_A1, _A2, _Rp> {}; template <class _Fp> -_LIBCPP_HIDE_FROM_ABI bool __not_null(_Fp const&) { - return true; +_LIBCPP_HIDE_FROM_ABI bool __is_null(_Fp const&) { + return false; } template <class _Fp> -_LIBCPP_HIDE_FROM_ABI bool __not_null(_Fp* __ptr) { - return __ptr; +_LIBCPP_HIDE_FROM_ABI bool __is_null(_Fp* __ptr) { + return !__ptr; } template <class _Ret, class _Class> -_LIBCPP_HIDE_FROM_ABI bool __not_null(_Ret _Class::*__ptr) { - return __ptr; +_LIBCPP_HIDE_FROM_ABI bool __is_null(_Ret _Class::* __ptr) { + return !__ptr; } template <class _Fp> -_LIBCPP_HIDE_FROM_ABI bool __not_null(function<_Fp> const& __f) { - return !!__f; +_LIBCPP_HIDE_FROM_ABI bool __is_null(function<_Fp> const& __f) { + return !__f; } # if __has_extension(blocks) template <class _Rp, class... _Args> -_LIBCPP_HIDE_FROM_ABI bool __not_null(_Rp (^__p)(_Args...)) { - return __p; +_LIBCPP_HIDE_FROM_ABI bool __is_null(_Rp (^__p)(_Args...)) { + return !__p; } # endif @@ -206,12 +204,13 @@ public: _LIBCPP_HIDE_FROM_ABI explicit __value_func(_Fp&& __f) : __f_(nullptr) { typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _Fun; - if (__function::__not_null(__f)) { - if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) { - __f_ = ::new (std::addressof(__buf_)) _Fun(std::move(__f)); - } else { - __f_ = new _Fun(std::move(__f)); - } + if (__function::__is_null(__f)) + return; + + if (sizeof(_Fun) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value) { + __f_ = ::new (std::addressof(__buf_)) _Fun(std::move(__f)); + } else { + __f_ = new _Fun(std::move(__f)); } } @@ -356,7 +355,31 @@ struct __policy { // type. template <typename _Fun> _LIBCPP_HIDE_FROM_ABI static const __policy* __create() { - return __choose_policy<_Fun>(__use_small_storage<_Fun>()); + if constexpr (__use_small_storage<_Fun>::value) { + static constexpr __policy __policy = { + nullptr, + nullptr, + false, +# if _LIBCPP_HAS_RTTI + &typeid(_Fun) +# else + nullptr +# endif + }; + return &__policy; + } else { + static constexpr __policy __policy = { + std::addressof(__large_clone<_Fun>), + std::addressof(__large_destroy<_Fun>), + false, +# if _LIBCPP_HAS_RTTI + &typeid(_Fun) +# else + nullptr +# endif + }; + return &__policy; + } } _LIBCPP_HIDE_FROM_ABI static const __policy* __create_empty() { @@ -384,36 +407,6 @@ private: _LIBCPP_HIDE_FROM_ABI static void __large_destroy(void* __s) { delete static_cast<_Fun*>(__s); } - - template <typename _Fun> - _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ false_type) { - static constexpr __policy __policy = { - std::addressof(__large_clone<_Fun>), - std::addressof(__large_destroy<_Fun>), - false, -# if _LIBCPP_HAS_RTTI - &typeid(_Fun) -# else - nullptr -# endif - }; - return &__policy; - } - - template <typename _Fun> - _LIBCPP_HIDE_FROM_ABI static const __policy* __choose_policy(/* is_small = */ true_type) { - static constexpr __policy __policy = { - nullptr, - nullptr, - false, -# if _LIBCPP_HAS_RTTI - &typeid(_Fun) -# else - nullptr -# endif - }; - return &__policy; - } }; // Used to choose between perfect forwarding or pass-by-value. Pass-by-value is @@ -455,14 +448,15 @@ public: template <class _Fp, __enable_if_t<!is_same<__decay_t<_Fp>, __policy_func>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI explicit __policy_func(_Fp&& __f) : __policy_(__policy::__create_empty()) { - if (__function::__not_null(__f)) { - __func_ = __call_func<_Fp>; - __policy_ = __policy::__create<_Fp>(); - if (__use_small_storage<_Fp>()) { - ::new ((void*)&__buf_.__small) _Fp(std::move(__f)); - } else { - __buf_.__large = ::new _Fp(std::move(__f)); - } + if (__function::__is_null(__f)) + return; + + __func_ = __call_func<_Fp>; + __policy_ = __policy::__create<_Fp>(); + if (__use_small_storage<_Fp>()) { + ::new ((void*)&__buf_.__small) _Fp(std::move(__f)); + } else { + __buf_.__large = ::new _Fp(std::move(__f)); } } @@ -615,21 +609,9 @@ class function<_Rp(_ArgTypes...)> __func __f_; - template <class _Fp, - bool = _And<_IsNotSame<__remove_cvref_t<_Fp>, function>, __is_invocable<_Fp, _ArgTypes...> >::value> - struct __callable; - template <class _Fp> - struct __callable<_Fp, true> { - static const bool value = - is_void<_Rp>::value || __is_core_convertible<__invoke_result_t<_Fp, _ArgTypes...>, _Rp>::value; - }; - template <class _Fp> - struct __callable<_Fp, false> { - static const bool value = false; - }; - template <class _Fp> - using _EnableIfLValueCallable _LIBCPP_NODEBUG = __enable_if_t<__callable<_Fp&>::value>; + using _EnableIfLValueCallable _LIBCPP_NODEBUG = __enable_if_t< + _And<_IsNotSame<__remove_cvref_t<_Fp>, function>, __is_invocable_r<_Rp, _Fp&, _ArgTypes...>>::value>; public: typedef _Rp result_type; @@ -690,11 +672,11 @@ public: # if _LIBCPP_HAS_RTTI // function target access: - _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const std::type_info& target_type() const _NOEXCEPT; template <typename _Tp> - _LIBCPP_HIDE_FROM_ABI _Tp* target() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Tp* target() _NOEXCEPT; template <typename _Tp> - _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const _Tp* target() const _NOEXCEPT; # endif // _LIBCPP_HAS_RTTI }; diff --git a/lib/libcxx/include/__functional/hash.h b/lib/libcxx/include/__functional/hash.h @@ -433,13 +433,10 @@ struct __hash_impl<long double> : __scalar_hash<long double> { template <class _Tp> struct hash : public __hash_impl<_Tp> {}; -#if _LIBCPP_STD_VER >= 17 - template <> struct hash<nullptr_t> : public __unary_function<nullptr_t, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(nullptr_t) const _NOEXCEPT { return 662607004ull; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(nullptr_t) const _NOEXCEPT { return 662607004ull; } }; -#endif #ifndef _LIBCPP_CXX03_LANG template <class _Key, class _Hash> @@ -452,18 +449,12 @@ template <class _Key, class _Hash = hash<_Key> > using __has_enabled_hash _LIBCPP_NODEBUG = integral_constant<bool, __check_hash_requirements<_Key, _Hash>::value && is_default_constructible<_Hash>::value >; -# if _LIBCPP_STD_VER >= 17 template <class _Type, class> using __enable_hash_helper_imp _LIBCPP_NODEBUG = _Type; template <class _Type, class... _Keys> using __enable_hash_helper _LIBCPP_NODEBUG = __enable_hash_helper_imp<_Type, __enable_if_t<__all<__has_enabled_hash<_Keys>::value...>::value> >; -# else -template <class _Type, class...> -using __enable_hash_helper _LIBCPP_NODEBUG = _Type; -# endif - #endif // !_LIBCPP_CXX03_LANG _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__functional/identity.h b/lib/libcxx/include/__functional/identity.h @@ -44,7 +44,7 @@ struct __is_identity<reference_wrapper<const __identity> > : true_type {}; struct identity { template <class _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator()(_Tp&& __t) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator()(_LIBCPP_LIFETIMEBOUND _Tp&& __t) const noexcept { return std::forward<_Tp>(__t); } diff --git a/lib/libcxx/include/__functional/is_transparent.h b/lib/libcxx/include/__functional/is_transparent.h @@ -29,6 +29,14 @@ inline const bool __is_transparent_v<_Tp, _Key, __void_t<typename _Tp::is_transp #endif +// Two types are considered transparently comparable if `comparator(key, arg)` is equivalent to `comparator(key, +// <implicit cast to KeyT>(arg))`. +// +// This is different from `__is_transparent_v`, which is only a property of the comparator and doesn't provide +// additional semantic guarantees. +template <class _Comparator, class _KeyT, class _Arg, class = void> +inline const bool __is_transparently_comparable_v = false; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___FUNCTIONAL_IS_TRANSPARENT diff --git a/lib/libcxx/include/__functional/mem_fn.h b/lib/libcxx/include/__functional/mem_fn.h @@ -43,7 +43,8 @@ public: }; template <class _Rp, class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __mem_fn<_Rp _Tp::*> mem_fn(_Rp _Tp::*__pm) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __mem_fn<_Rp _Tp::*> +mem_fn(_Rp _Tp::* __pm) _NOEXCEPT { return __mem_fn<_Rp _Tp::*>(__pm); } diff --git a/lib/libcxx/include/__functional/operations.h b/lib/libcxx/include/__functional/operations.h @@ -15,7 +15,9 @@ #include <__functional/unary_function.h> #include <__fwd/functional.h> #include <__type_traits/desugars_to.h> +#include <__type_traits/is_generic_transparent_comparator.h> #include <__type_traits/is_integral.h> +#include <__type_traits/make_transparent.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -377,6 +379,14 @@ struct less<void> { typedef void is_transparent; }; +template <class _Tp> +struct __make_transparent<_Tp, less<_Tp> > { + using type _LIBCPP_NODEBUG = less<>; +}; + +template <> +inline const bool __is_generic_transparent_comparator_v<less<>> = true; + template <class _Tp, class _Up> inline const bool __desugars_to_v<__less_tag, less<>, _Tp, _Up> = true; @@ -466,6 +476,14 @@ struct greater<void> { template <class _Tp, class _Up> inline const bool __desugars_to_v<__greater_tag, greater<>, _Tp, _Up> = true; + +template <class _Tp> +struct __make_transparent<_Tp, greater<_Tp>> { + using type _LIBCPP_NODEBUG = greater<>; +}; + +template <> +inline const bool __is_generic_transparent_comparator_v<greater<>> = true; #endif // Logical operations diff --git a/lib/libcxx/include/__functional/ranges_operations.h b/lib/libcxx/include/__functional/ranges_operations.h @@ -14,6 +14,7 @@ #include <__concepts/totally_ordered.h> #include <__config> #include <__type_traits/desugars_to.h> +#include <__type_traits/is_generic_transparent_comparator.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -108,6 +109,12 @@ inline const bool __desugars_to_v<__less_tag, ranges::less, _Tp, _Up> = true; template <class _Tp, class _Up> inline const bool __desugars_to_v<__greater_tag, ranges::greater, _Tp, _Up> = true; +template <> +inline const bool __is_generic_transparent_comparator_v<ranges::less> = true; + +template <> +inline const bool __is_generic_transparent_comparator_v<ranges::greater> = true; + #endif // _LIBCPP_STD_VER >= 20 _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__functional/reference_wrapper.h b/lib/libcxx/include/__functional/reference_wrapper.h @@ -58,7 +58,7 @@ public: // access _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator type&() const _NOEXCEPT { return *__f_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 type& get() const _NOEXCEPT { return *__f_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 type& get() const _NOEXCEPT { return *__f_; } // invoke template <class... _ArgTypes> @@ -128,23 +128,25 @@ reference_wrapper(_Tp&) -> reference_wrapper<_Tp>; #endif template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(_Tp& __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(_Tp& __t) _NOEXCEPT { return reference_wrapper<_Tp>(__t); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<_Tp> ref(reference_wrapper<_Tp> __t) _NOEXCEPT { return __t; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<const _Tp> cref(const _Tp& __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<const _Tp> +cref(const _Tp& __t) _NOEXCEPT { return reference_wrapper<const _Tp>(__t); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<const _Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference_wrapper<const _Tp> cref(reference_wrapper<_Tp> __t) _NOEXCEPT { return __t; } diff --git a/lib/libcxx/include/__functional/weak_result_type.h b/lib/libcxx/include/__functional/weak_result_type.h @@ -13,9 +13,9 @@ #include <__config> #include <__functional/binary_function.h> #include <__functional/unary_function.h> -#include <__type_traits/integral_constant.h> #include <__type_traits/invoke.h> #include <__type_traits/is_same.h> +#include <__type_traits/void_t.h> #include <__utility/declval.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -24,50 +24,36 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Tp> -struct __has_result_type { -private: - template <class _Up> - static false_type __test(...); - template <class _Up> - static true_type __test(typename _Up::result_type* = 0); +template <class _Tp, class = void> +inline const bool __has_result_type_v = false; -public: - static const bool value = decltype(__test<_Tp>(0))::value; -}; +template <class _Tp> +inline const bool __has_result_type_v<_Tp, __void_t<typename _Tp::result_type*> > = true; // __weak_result_type template <class _Tp> struct __derives_from_unary_function { private: - struct __two { - char __lx; - char __lxx; - }; - static __two __test(...); + static void __find_base(...); template <class _Ap, class _Rp> - static __unary_function<_Ap, _Rp> __test(const volatile __unary_function<_Ap, _Rp>*); + static __unary_function<_Ap, _Rp> __find_base(const volatile __unary_function<_Ap, _Rp>*); public: - static const bool value = !is_same<decltype(__test((_Tp*)0)), __two>::value; - typedef decltype(__test((_Tp*)0)) type; + using type = decltype(__find_base(static_cast<_Tp*>(nullptr))); + static const bool value = !is_same<type, void>::value; }; template <class _Tp> struct __derives_from_binary_function { private: - struct __two { - char __lx; - char __lxx; - }; - static __two __test(...); + static void __find_base(...); template <class _A1, class _A2, class _Rp> - static __binary_function<_A1, _A2, _Rp> __test(const volatile __binary_function<_A1, _A2, _Rp>*); + static __binary_function<_A1, _A2, _Rp> __find_base(const volatile __binary_function<_A1, _A2, _Rp>*); public: - static const bool value = !is_same<decltype(__test((_Tp*)0)), __two>::value; - typedef decltype(__test((_Tp*)0)) type; + using type = decltype(__find_base(static_cast<_Tp*>(nullptr))); + static const bool value = !is_same<type, void>::value; }; template <class _Tp, bool = __derives_from_unary_function<_Tp>::value> @@ -85,7 +71,7 @@ struct __maybe_derive_from_binary_function // bool is true template <class _Tp> struct __maybe_derive_from_binary_function<_Tp, false> {}; -template <class _Tp, bool = __has_result_type<_Tp>::value> +template <class _Tp, bool = __has_result_type_v<_Tp> > struct __weak_result_type_imp // bool is true : public __maybe_derive_from_unary_function<_Tp>, public __maybe_derive_from_binary_function<_Tp> { diff --git a/lib/libcxx/include/__fwd/ios.h b/lib/libcxx/include/__fwd/ios.h @@ -31,7 +31,7 @@ using wios = basic_ios<wchar_t>; template <class _CharT, class _Traits> class _LIBCPP_PREFERRED_NAME(ios) _LIBCPP_IF_WIDE_CHARACTERS(_LIBCPP_PREFERRED_NAME(wios)) basic_ios; -#if defined(_NEWLIB_VERSION) +#if _LIBCPP_LIBC_NEWLIB // On newlib, off_t is 'long int' using streamoff = long int; // for char_traits in <string> #else diff --git a/lib/libcxx/include/__fwd/tuple.h b/lib/libcxx/include/__fwd/tuple.h @@ -21,12 +21,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <size_t, class> struct tuple_element; +template <size_t _Np, class _Tp> +using __tuple_element_t _LIBCPP_NODEBUG = typename tuple_element<_Np, _Tp>::type; + #ifndef _LIBCPP_CXX03_LANG template <class...> class tuple; template <class> +inline const bool __is_tuple_v = false; + +template <class... _Tp> +inline const bool __is_tuple_v<tuple<_Tp...>> = true; + +template <size_t _Ip, class... _Tp> +struct tuple_element<_Ip, tuple<_Tp...> > { + using type _LIBCPP_NODEBUG = __type_pack_element<_Ip, _Tp...>; +}; + +template <class> struct tuple_size; template <size_t _Ip, class... _Tp> diff --git a/lib/libcxx/include/__hash_table b/lib/libcxx/include/__hash_table @@ -10,6 +10,7 @@ #ifndef _LIBCPP___HASH_TABLE #define _LIBCPP___HASH_TABLE +#include <__algorithm/fill_n.h> #include <__algorithm/max.h> #include <__algorithm/min.h> #include <__assert> @@ -28,7 +29,6 @@ #include <__memory/swap_allocator.h> #include <__memory/unique_ptr.h> #include <__new/launder.h> -#include <__type_traits/can_extract_key.h> #include <__type_traits/copy_cvref.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> @@ -44,7 +44,9 @@ #include <__utility/forward.h> #include <__utility/move.h> #include <__utility/pair.h> +#include <__utility/scope_guard.h> #include <__utility/swap.h> +#include <__utility/try_key_extraction.h> #include <limits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -81,18 +83,6 @@ struct __hash_node_base { typedef _NodePtr __node_pointer; typedef __node_base_pointer __next_pointer; -// TODO(LLVM 22): Remove this check -#ifndef _LIBCPP_ABI_FIX_UNORDERED_NODE_POINTER_UB - static_assert(sizeof(__node_base_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) == - _LIBCPP_ALIGNOF(__node_pointer), - "It looks like you are using std::__hash_table (an implementation detail for the unordered containers) " - "with a fancy pointer type that thas a different representation depending on whether it points to a " - "__hash_table base pointer or a __hash_table node pointer (both of which are implementation details of " - "the standard library). This means that your ABI is being broken between LLVM 19 and LLVM 20. If you " - "don't care about your ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to " - "silence this diagnostic."); -#endif - __next_pointer __next_; _LIBCPP_HIDE_FROM_ABI __next_pointer __ptr() _NOEXCEPT { @@ -122,6 +112,19 @@ struct __get_hash_node_value_type<__hash_value_type<_Key, _Tp> > { template <class _Tp> using __get_hash_node_value_type_t _LIBCPP_NODEBUG = typename __get_hash_node_value_type<_Tp>::type; +template <class _Tp> +struct __get_hash_node_key_type { + using type _LIBCPP_NODEBUG = _Tp; +}; + +template <class _Key, class _Tp> +struct __get_hash_node_key_type<__hash_value_type<_Key, _Tp> > { + using type _LIBCPP_NODEBUG = _Key; +}; + +template <class _Tp> +using __get_hash_node_key_type_t _LIBCPP_NODEBUG = typename __get_hash_node_key_type<_Tp>::type; + template <class _Tp, class _VoidPtr> struct __hash_node : public __hash_node_base< __rebind_pointer_t<_VoidPtr, __hash_node<_Tp, _VoidPtr> > > { using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>; @@ -152,7 +155,12 @@ public: } #endif - _LIBCPP_HIDE_FROM_ABI explicit __hash_node(__next_pointer __next, size_t __hash) : _Base(__next), __hash_(__hash) {} + template <class _Alloc, class... _Args> + _LIBCPP_HIDE_FROM_ABI explicit __hash_node(size_t __hash, _Alloc& __na, _Args&&... __args) + : _Base(nullptr), __hash_(__hash) { + allocator_traits<_Alloc>::construct(__na, std::addressof(__get_value()), std::forward<_Args>(__args)...); + } + _LIBCPP_HIDE_FROM_ABI ~__hash_node() {} }; @@ -182,85 +190,16 @@ class __hash_map_iterator; template <class _HashIterator> class __hash_map_const_iterator; -template <class _Tp> -struct __hash_key_value_types { - static_assert(!is_reference<_Tp>::value && !is_const<_Tp>::value, ""); - typedef _Tp key_type; - typedef _Tp __node_value_type; - typedef _Tp __container_value_type; - static const bool __is_map = false; - - _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(_Tp const& __v) { return __v; } - _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(__node_value_type const& __v) { return __v; } - _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__node_value_type& __n) { return std::addressof(__n); } - _LIBCPP_HIDE_FROM_ABI static __container_value_type&& __move(__node_value_type& __v) { return std::move(__v); } -}; - -template <class _Key, class _Tp> -struct __hash_key_value_types<__hash_value_type<_Key, _Tp> > { - typedef _Key key_type; - typedef _Tp mapped_type; - typedef __hash_value_type<_Key, _Tp> __node_value_type; - typedef pair<const _Key, _Tp> __container_value_type; - typedef __container_value_type __map_value_type; - static const bool __is_map = true; - - _LIBCPP_HIDE_FROM_ABI static key_type const& __get_key(__container_value_type const& __v) { return __v.first; } - - template <class _Up, __enable_if_t<is_same<__remove_cvref_t<_Up>, __node_value_type>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) { - return __t.__get_value(); - } - - template <class _Up, __enable_if_t<is_same<__remove_cvref_t<_Up>, __container_value_type>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI static __container_value_type const& __get_value(_Up& __t) { - return __t; - } - - _LIBCPP_HIDE_FROM_ABI static __container_value_type* __get_ptr(__container_value_type& __n) { - return std::addressof(__n); - } - _LIBCPP_HIDE_FROM_ABI static pair<key_type&&, mapped_type&&> __move(__node_value_type& __v) { return __v.__move(); } -}; - -template <class _Tp, class _AllocPtr, class _KVTypes = __hash_key_value_types<_Tp>, bool = _KVTypes::__is_map> -struct __hash_map_pointer_types {}; - -template <class _Tp, class _AllocPtr, class _KVTypes> -struct __hash_map_pointer_types<_Tp, _AllocPtr, _KVTypes, true> { - typedef typename _KVTypes::__map_value_type _Mv; - typedef __rebind_pointer_t<_AllocPtr, _Mv> __map_value_type_pointer; - typedef __rebind_pointer_t<_AllocPtr, const _Mv> __const_map_value_type_pointer; -}; - template <class _NodePtr, class _NodeT = typename pointer_traits<_NodePtr>::element_type> struct __hash_node_types; template <class _NodePtr, class _Tp, class _VoidPtr> -struct __hash_node_types<_NodePtr, __hash_node<_Tp, _VoidPtr> > - : public __hash_key_value_types<_Tp>, - __hash_map_pointer_types<_Tp, _VoidPtr> - -{ - typedef __hash_key_value_types<_Tp> __base; - -public: - typedef ptrdiff_t difference_type; - typedef size_t size_type; - - typedef __rebind_pointer_t<_NodePtr, void> __void_pointer; - +struct __hash_node_types<_NodePtr, __hash_node<_Tp, _VoidPtr> > { typedef typename pointer_traits<_NodePtr>::element_type __node_type; - typedef _NodePtr __node_pointer; - typedef __hash_node_base<__node_pointer> __node_base_type; - typedef __rebind_pointer_t<_NodePtr, __node_base_type> __node_base_pointer; - - typedef typename __node_base_type::__next_pointer __next_pointer; + typedef typename __hash_node_base<_NodePtr>::__next_pointer __next_pointer; using __node_value_type _LIBCPP_NODEBUG = __get_hash_node_value_type_t<_Tp>; - typedef __rebind_pointer_t<_VoidPtr, __node_value_type> __node_value_type_pointer; - typedef __rebind_pointer_t<_VoidPtr, const __node_value_type> __const_node_value_type_pointer; private: static_assert(!is_const<__node_type>::value, "_NodePtr should never be a pointer to const"); @@ -281,13 +220,6 @@ struct __hash_node_types_from_iterator<__hash_local_iterator<_NodePtr> > : __has template <class _NodePtr> struct __hash_node_types_from_iterator<__hash_const_local_iterator<_NodePtr> > : __hash_node_types<_NodePtr> {}; -template <class _NodeValueTp, class _VoidPtr> -struct __make_hash_node_types { - typedef __hash_node<_NodeValueTp, _VoidPtr> _NodeTp; - typedef __rebind_pointer_t<_VoidPtr, _NodeTp> _NodePtr; - typedef __hash_node_types<_NodePtr> type; -}; - template <class _NodePtr> class __hash_iterator { typedef __hash_node_types<_NodePtr> _NodeTypes; @@ -299,9 +231,9 @@ class __hash_iterator { public: typedef forward_iterator_tag iterator_category; typedef typename _NodeTypes::__node_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using difference_type = ptrdiff_t; typedef value_type& reference; - typedef typename _NodeTypes::__node_value_type_pointer pointer; + using pointer = __rebind_pointer_t<_NodePtr, value_type>; _LIBCPP_HIDE_FROM_ABI __hash_iterator() _NOEXCEPT : __node_(nullptr) {} @@ -366,9 +298,9 @@ public: typedef forward_iterator_tag iterator_category; typedef typename _NodeTypes::__node_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using difference_type = ptrdiff_t; typedef const value_type& reference; - typedef typename _NodeTypes::__const_node_value_type_pointer pointer; + using pointer = __rebind_pointer_t<_NodePtr, const value_type>; _LIBCPP_HIDE_FROM_ABI __hash_const_iterator() _NOEXCEPT : __node_(nullptr) {} @@ -431,9 +363,9 @@ class __hash_local_iterator { public: typedef forward_iterator_tag iterator_category; typedef typename _NodeTypes::__node_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using difference_type = ptrdiff_t; typedef value_type& reference; - typedef typename _NodeTypes::__node_value_type_pointer pointer; + using pointer = __rebind_pointer_t<_NodePtr, value_type>; _LIBCPP_HIDE_FROM_ABI __hash_local_iterator() _NOEXCEPT : __node_(nullptr) {} @@ -509,9 +441,9 @@ public: typedef forward_iterator_tag iterator_category; typedef typename _NodeTypes::__node_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using difference_type = ptrdiff_t; typedef const value_type& reference; - typedef typename _NodeTypes::__const_node_value_type_pointer pointer; + using pointer = __rebind_pointer_t<_ConstNodePtr, const value_type>; _LIBCPP_HIDE_FROM_ABI __hash_const_local_iterator() _NOEXCEPT : __node_(nullptr) {} @@ -617,8 +549,6 @@ public: typedef typename __alloc_traits::pointer pointer; private: - typedef __hash_node_types<pointer> _NodeTypes; - allocator_type& __na_; public: @@ -633,7 +563,7 @@ public: _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { if (__value_constructed) { - __alloc_traits::destroy(__na_, _NodeTypes::__get_ptr(__p->__get_value())); + __alloc_traits::destroy(__na_, std::addressof(__p->__get_value())); std::__destroy_at(std::addressof(*__p)); } if (__p) @@ -684,18 +614,16 @@ template <class _Tp, class _Hash, class _Equal, class _Alloc> class __hash_table { public: using value_type = __get_hash_node_value_type_t<_Tp>; + using key_type = __get_hash_node_key_type_t<_Tp>; + typedef _Hash hasher; typedef _Equal key_equal; typedef _Alloc allocator_type; private: typedef allocator_traits<allocator_type> __alloc_traits; - typedef typename __make_hash_node_types<_Tp, typename __alloc_traits::void_pointer>::type _NodeTypes; public: - typedef typename _NodeTypes::__node_value_type __node_value_type; - typedef typename _NodeTypes::__container_value_type __container_value_type; - typedef typename _NodeTypes::key_type key_type; typedef value_type& reference; typedef const value_type& const_reference; typedef typename __alloc_traits::pointer pointer; @@ -703,22 +631,23 @@ public: #ifndef _LIBCPP_ABI_FIX_UNORDERED_CONTAINER_SIZE_TYPE typedef typename __alloc_traits::size_type size_type; #else - typedef typename _NodeTypes::size_type size_type; + using size_type = size_t; #endif - typedef typename _NodeTypes::difference_type difference_type; + using difference_type = ptrdiff_t; public: // Create __node - typedef typename _NodeTypes::__node_type __node; - typedef __rebind_alloc<__alloc_traits, __node> __node_allocator; - typedef allocator_traits<__node_allocator> __node_traits; - typedef typename _NodeTypes::__void_pointer __void_pointer; - typedef typename _NodeTypes::__node_pointer __node_pointer; - typedef typename _NodeTypes::__node_pointer __node_const_pointer; - typedef typename _NodeTypes::__node_base_type __first_node; - typedef typename _NodeTypes::__node_base_pointer __node_base_pointer; - typedef typename _NodeTypes::__next_pointer __next_pointer; + using __void_pointer _LIBCPP_NODEBUG = typename __alloc_traits::void_pointer; + + using __node _LIBCPP_NODEBUG = __hash_node<_Tp, __void_pointer>; + using __node_allocator _LIBCPP_NODEBUG = __rebind_alloc<__alloc_traits, __node>; + using __node_traits _LIBCPP_NODEBUG = allocator_traits<__node_allocator>; + using __node_pointer _LIBCPP_NODEBUG = __rebind_pointer_t<__void_pointer, __node>; + + using __first_node _LIBCPP_NODEBUG = __hash_node_base<__node_pointer>; + using __node_base_pointer _LIBCPP_NODEBUG = __rebind_pointer_t<__void_pointer, __first_node>; + using __next_pointer _LIBCPP_NODEBUG = __node_base_pointer; private: // check for sane allocator pointer rebinding semantics. Rebinding the @@ -747,6 +676,38 @@ private: _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; } + _LIBCPP_HIDE_FROM_ABI void + __copy_construct(__next_pointer __other_iter, __next_pointer __own_iter, size_t __current_chash) { + auto __bucket_count = bucket_count(); + + for (; __other_iter; __other_iter = __other_iter->__next_) { + __node_holder __new_node = __construct_node_hash(__other_iter->__hash(), __other_iter->__upcast()->__get_value()); + + size_t __new_chash = std::__constrain_hash(__new_node->__hash(), __bucket_count); + if (__new_chash != __current_chash) { + __bucket_list_[__new_chash] = __own_iter; + __current_chash = __new_chash; + } + + __own_iter->__next_ = static_cast<__next_pointer>(__new_node.release()); + __own_iter = __own_iter->__next_; + } + } + + _LIBCPP_HIDE_FROM_ABI void __copy_construct(__next_pointer __other_iter) { + __next_pointer __own_iter = __first_node_.__ptr(); + { + __node_holder __new_node = __construct_node_hash(__other_iter->__hash(), __other_iter->__upcast()->__get_value()); + __own_iter->__next_ = static_cast<__next_pointer>(__new_node.release()); + } + + size_t __current_chash = std::__constrain_hash(__own_iter->__next_->__hash(), bucket_count()); + __bucket_list_[__current_chash] = __own_iter; + __other_iter = __other_iter->__next_; + __own_iter = __own_iter->__next_; + __copy_construct(__other_iter, __own_iter, __current_chash); + } + public: _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } @@ -811,40 +772,66 @@ public: _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd); _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd); - template <class _Key, class... _Args> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_key_args(_Key const& __k, _Args&&... __args); - - template <class... _Args> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_impl(_Args&&... __args); - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Pp&& __x) { - return __emplace_unique_extract_key(std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>()); - } - - template <class _First, - class _Second, - __enable_if_t<__can_extract_map_key<_First, key_type, __container_value_type>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_First&& __f, _Second&& __s) { - return __emplace_unique_key_args(__f, std::forward<_First>(__f), std::forward<_Second>(__s)); - } - template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Args&&... __args) { - return __emplace_unique_impl(std::forward<_Args>(__args)...); - } - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) { - return __emplace_unique_impl(std::forward<_Pp>(__x)); - } - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) { - return __emplace_unique_key_args(__x, std::forward<_Pp>(__x)); - } - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) { - return __emplace_unique_key_args(__x.first, std::forward<_Pp>(__x)); + return std::__try_key_extraction<key_type>( + [this](const key_type& __key, _Args&&... __args2) { + size_t __hash = hash_function()(__key); + size_type __bc = bucket_count(); + bool __inserted = false; + __next_pointer __nd; + size_t __chash; + if (__bc != 0) { + __chash = std::__constrain_hash(__hash, __bc); + __nd = __bucket_list_[__chash]; + if (__nd != nullptr) { + for (__nd = __nd->__next_; + __nd != nullptr && + (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash); + __nd = __nd->__next_) { + if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __key)) + goto __done; + } + } + } + { + __node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args2)...); + if (size() + 1 > __bc * max_load_factor()) { + __rehash_unique(std::max<size_type>(2 * __bc + !std::__is_hash_power2(__bc), + size_type(__math::ceil(float(size() + 1) / max_load_factor())))); + __bc = bucket_count(); + __chash = std::__constrain_hash(__hash, __bc); + } + // insert_after __bucket_list_[__chash], or __first_node if bucket is null + __next_pointer __pn = __bucket_list_[__chash]; + if (__pn == nullptr) { + __pn = __first_node_.__ptr(); + __h->__next_ = __pn->__next_; + __pn->__next_ = __h.get()->__ptr(); + // fix up __bucket_list_ + __bucket_list_[__chash] = __pn; + if (__h->__next_ != nullptr) + __bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr(); + } else { + __h->__next_ = __pn->__next_; + __pn->__next_ = static_cast<__next_pointer>(__h.get()); + } + __nd = static_cast<__next_pointer>(__h.release()); + // increment size + ++size(); + __inserted = true; + } + __done: + return pair<iterator, bool>(iterator(__nd), __inserted); + }, + [this](_Args&&... __args2) { + __node_holder __h = __construct_node(std::forward<_Args>(__args2)...); + pair<iterator, bool> __r = __node_insert_unique(__h.get()); + if (__r.second) + __h.release(); + return __r; + }, + std::forward<_Args>(__args)...); } template <class... _Args> @@ -854,9 +841,7 @@ public: template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(value_type&& __value) { - using __key_type = typename _NodeTypes::key_type; - - __node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second)); + __node_holder __h = __construct_node(const_cast<key_type&&>(__value.first), std::move(__value.second)); __node_insert_unique(__h.get()); __h.release(); } @@ -870,9 +855,7 @@ public: template <class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(value_type&& __value) { - using __key_type = typename _NodeTypes::key_type; - - __node_holder __h = __construct_node(const_cast<__key_type&&>(__value.first), std::move(__value.second)); + __node_holder __h = __construct_node(const_cast<key_type&&>(__value.first), std::move(__value.second)); __node_insert_multi(__h.get()); __h.release(); } @@ -1017,8 +1000,8 @@ private: template <class... _Args> _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args); - template <class _First, class... _Rest> - _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest); + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_hash(size_t __hash, _Args&&... __args); _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __hash_table& __u) { __copy_assign_alloc(__u, integral_constant<bool, __node_traits::propagate_on_container_copy_assignment::value>()); @@ -1042,17 +1025,29 @@ private: } _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__hash_table&, false_type) _NOEXCEPT {} - _LIBCPP_HIDE_FROM_ABI void __deallocate_node(__next_pointer __np) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI void __deallocate_node(__node_pointer __nd) _NOEXCEPT { + auto& __alloc = __node_alloc(); + __node_traits::destroy(__alloc, std::addressof(__nd->__get_value())); + std::__destroy_at(std::__to_address(__nd)); + __node_traits::deallocate(__alloc, __nd, 1); + } + + _LIBCPP_HIDE_FROM_ABI void __deallocate_node_list(__next_pointer __np) _NOEXCEPT { + while (__np != nullptr) { + __next_pointer __next = __np->__next_; + __deallocate_node(__np->__upcast()); + __np = __next; + } + } + _LIBCPP_HIDE_FROM_ABI __next_pointer __detach() _NOEXCEPT; template <class _From, class _ValueT = _Tp, __enable_if_t<__is_hash_value_type<_ValueT>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI void __assign_value(__get_hash_node_value_type_t<_Tp>& __lhs, _From&& __rhs) { - using __key_type = typename _NodeTypes::key_type; - // This is technically UB, since the object was constructed as `const`. // Clang doesn't optimize on this currently though. - const_cast<__key_type&>(__lhs.first) = const_cast<__copy_cvref_t<_From, __key_type>&&>(__rhs.first); - __lhs.second = std::forward<_From>(__rhs).second; + const_cast<key_type&>(__lhs.first) = const_cast<__copy_cvref_t<_From, key_type>&&>(__rhs.first); + __lhs.second = std::forward<_From>(__rhs).second; } template <class _From, class _ValueT = _Tp, __enable_if_t<!__is_hash_value_type<_ValueT>::value, int> = 0> @@ -1101,16 +1096,29 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const allocator_type& __a __max_load_factor_(1.0f) {} template <class _Tp, class _Hash, class _Equal, class _Alloc> -__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u) +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __other) : __bucket_list_(nullptr, - __bucket_list_deleter(allocator_traits<__pointer_allocator>::select_on_container_copy_construction( - __u.__bucket_list_.get_deleter().__alloc()), + __bucket_list_deleter(__pointer_alloc_traits::select_on_container_copy_construction( + __other.__bucket_list_.get_deleter().__alloc()), 0)), - __node_alloc_(allocator_traits<__node_allocator>::select_on_container_copy_construction(__u.__node_alloc())), + __node_alloc_(__node_traits::select_on_container_copy_construction(__other.__node_alloc())), __size_(0), - __hasher_(__u.hash_function()), - __max_load_factor_(__u.__max_load_factor_), - __key_eq_(__u.__key_eq_) {} + __hasher_(__other.hash_function()), + __max_load_factor_(__other.__max_load_factor_), + __key_eq_(__other.__key_eq_) { + if (__other.size() == 0) + return; + + auto& __bucket_list_del = __bucket_list_.get_deleter(); + auto __bucket_count = __other.bucket_count(); + __bucket_list_.reset(__pointer_alloc_traits::allocate(__bucket_list_del.__alloc(), __bucket_count)); + __bucket_list_del.size() = __bucket_count; + + std::fill_n(__bucket_list_.get(), __bucket_count, nullptr); + + __copy_construct(__other.__first_node_.__next_); + __size_ = __other.size(); +} template <class _Tp, class _Hash, class _Equal, class _Alloc> __hash_table<_Tp, _Hash, _Equal, _Alloc>::__hash_table(const __hash_table& __u, const allocator_type& __a) @@ -1169,7 +1177,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::~__hash_table() { static_assert(is_copy_constructible<hasher>::value, "Hasher must be copy-constructible."); #endif - __deallocate_node(__first_node_.__next_); + __deallocate_node_list(__first_node_.__next_); } template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1184,28 +1192,76 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__copy_assign_alloc(const __hash_ } template <class _Tp, class _Hash, class _Equal, class _Alloc> -__hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __u) { - if (this != std::addressof(__u)) { - __copy_assign_alloc(__u); - hash_function() = __u.hash_function(); - key_eq() = __u.key_eq(); - max_load_factor() = __u.max_load_factor(); - __assign_multi(__u.begin(), __u.end()); +__hash_table<_Tp, _Hash, _Equal, _Alloc>& +__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(const __hash_table& __other) { + if (this == std::addressof(__other)) + return *this; + + __copy_assign_alloc(__other); + hash_function() = __other.hash_function(); + key_eq() = __other.key_eq(); + max_load_factor() = __other.max_load_factor(); + + if (__other.size() == 0) { + clear(); + return *this; } - return *this; -} -template <class _Tp, class _Hash, class _Equal, class _Alloc> -void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__deallocate_node(__next_pointer __np) _NOEXCEPT { - __node_allocator& __na = __node_alloc(); - while (__np != nullptr) { - __next_pointer __next = __np->__next_; - __node_pointer __real_np = __np->__upcast(); - __node_traits::destroy(__na, _NodeTypes::__get_ptr(__real_np->__get_value())); - std::__destroy_at(std::addressof(*__real_np)); - __node_traits::deallocate(__na, __real_np, 1); - __np = __next; + auto __bucket_count = __other.bucket_count(); + if (__bucket_count != bucket_count()) { + auto& __bucket_list_del = __bucket_list_.get_deleter(); + __bucket_list_.reset(__pointer_alloc_traits::allocate(__bucket_list_del.__alloc(), __bucket_count)); + __bucket_list_del.size() = __bucket_count; + } + std::fill_n(__bucket_list_.get(), __bucket_count, nullptr); + + if (!__first_node_.__next_) { + __copy_construct(__other.__first_node_.__next_); + __size_ = __other.size(); + return *this; + } + + __next_pointer __other_iter = __other.__first_node_.__next_; + __next_pointer __own_iter = __first_node_.__ptr(); + { + __node_pointer __next = __own_iter->__next_->__upcast(); + __assign_value(__next->__get_value(), __other_iter->__upcast()->__get_value()); + __next->__hash_ = __other_iter->__hash(); + } + size_t __current_chash = std::__constrain_hash(__own_iter->__next_->__hash(), __bucket_count); + __bucket_list_[__current_chash] = __own_iter; + __other_iter = __other_iter->__next_; + __own_iter = __own_iter->__next_; + + // Go through the nodes of the incoming hash table and copy then into the destination hash table, reusing as many + // existing nodes as posssible in the destination. + while (__other_iter && __own_iter->__next_) { + __node_pointer __next = __own_iter->__next_->__upcast(); + __assign_value(__next->__get_value(), __other_iter->__upcast()->__get_value()); + __next->__hash_ = __other_iter->__hash(); + + size_t __new_chash = std::__constrain_hash(__next->__hash_, __bucket_count); + if (__new_chash != __current_chash) { + __bucket_list_[__new_chash] = __own_iter; + __current_chash = __new_chash; + } + + __other_iter = __other_iter->__next_; + __own_iter = __own_iter->__next_; } + + // At this point we either have consumed the whole incoming hash table, or we don't have any more nodes to reuse in + // the destination. Either continue with constructing new nodes, or deallocate the left over nodes. + if (__own_iter->__next_) { + __deallocate_node_list(__own_iter->__next_); + __own_iter->__next_ = nullptr; + } else { + __copy_construct(__other_iter, __own_iter, __current_chash); + } + + __size_ = __other.size(); + + return *this; } template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1251,23 +1307,14 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, max_load_factor() = __u.max_load_factor(); if (bucket_count() != 0) { __next_pointer __cache = __detach(); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - const_iterator __i = __u.begin(); - while (__cache != nullptr && __u.size() != 0) { - __assign_value(__cache->__upcast()->__get_value(), std::move(__u.remove(__i++)->__get_value())); - __next_pointer __next = __cache->__next_; - __node_insert_multi(__cache->__upcast()); - __cache = __next; - } -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __deallocate_node(__cache); - throw; + auto __guard = std::__make_scope_guard([&] { __deallocate_node_list(__cache); }); + const_iterator __i = __u.begin(); + while (__cache != nullptr && __u.size() != 0) { + __assign_value(__cache->__upcast()->__get_value(), std::move(__u.remove(__i++)->__get_value())); + __next_pointer __next = __cache->__next_; + __node_insert_multi(__cache->__upcast()); + __cache = __next; } -#endif // _LIBCPP_HAS_EXCEPTIONS - __deallocate_node(__cache); } const_iterator __i = __u.begin(); while (__u.size() != 0) @@ -1290,27 +1337,18 @@ template <class _InputIterator> void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_unique(_InputIterator __first, _InputIterator __last) { typedef iterator_traits<_InputIterator> _ITraits; typedef typename _ITraits::value_type _ItValueType; - static_assert(is_same<_ItValueType, __container_value_type>::value, - "__assign_unique may only be called with the containers value type"); + static_assert( + is_same<_ItValueType, value_type>::value, "__assign_unique may only be called with the containers value type"); if (bucket_count() != 0) { __next_pointer __cache = __detach(); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - for (; __cache != nullptr && __first != __last; ++__first) { - __assign_value(__cache->__upcast()->__get_value(), *__first); - __next_pointer __next = __cache->__next_; - __node_insert_unique(__cache->__upcast()); - __cache = __next; - } -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __deallocate_node(__cache); - throw; + auto __guard = std::__make_scope_guard([&] { __deallocate_node_list(__cache); }); + for (; __cache != nullptr && __first != __last; ++__first) { + __assign_value(__cache->__upcast()->__get_value(), *__first); + __next_pointer __next = __cache->__next_; + __node_insert_unique(__cache->__upcast()); + __cache = __next; } -#endif // _LIBCPP_HAS_EXCEPTIONS - __deallocate_node(__cache); } for (; __first != __last; ++__first) __emplace_unique(*__first); @@ -1321,31 +1359,20 @@ template <class _InputIterator> void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__assign_multi(_InputIterator __first, _InputIterator __last) { typedef iterator_traits<_InputIterator> _ITraits; typedef typename _ITraits::value_type _ItValueType; - static_assert( - (is_same<_ItValueType, __container_value_type>::value || is_same<_ItValueType, __node_value_type>::value), - "__assign_multi may only be called with the containers value type" - " or the nodes value type"); + static_assert(is_same<_ItValueType, value_type>::value, + "__assign_multi may only be called with the containers value type or the nodes value type"); if (bucket_count() != 0) { __next_pointer __cache = __detach(); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - for (; __cache != nullptr && __first != __last; ++__first) { - __assign_value(__cache->__upcast()->__get_value(), *__first); - __next_pointer __next = __cache->__next_; - __node_insert_multi(__cache->__upcast()); - __cache = __next; - } -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __deallocate_node(__cache); - throw; + auto __guard = std::__make_scope_guard([&] { __deallocate_node_list(__cache); }); + for (; __cache != nullptr && __first != __last; ++__first) { + __assign_value(__cache->__upcast()->__get_value(), *__first); + __next_pointer __next = __cache->__next_; + __node_insert_multi(__cache->__upcast()); + __cache = __next; } -#endif // _LIBCPP_HAS_EXCEPTIONS - __deallocate_node(__cache); } for (; __first != __last; ++__first) - __emplace_multi(_NodeTypes::__get_value(*__first)); + __emplace_multi(*__first); } template <class _Tp, class _Hash, class _Equal, class _Alloc> @@ -1375,7 +1402,7 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::end() const _NOEXCEPT { template <class _Tp, class _Hash, class _Equal, class _Alloc> void __hash_table<_Tp, _Hash, _Equal, _Alloc>::clear() _NOEXCEPT { if (size() > 0) { - __deallocate_node(__first_node_.__next_); + __deallocate_node_list(__first_node_.__next_); __first_node_.__next_ = nullptr; size_type __bc = bucket_count(); for (size_type __i = 0; __i < __bc; ++__i) @@ -1562,69 +1589,6 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_insert_multi(const_iterator __p } template <class _Tp, class _Hash, class _Equal, class _Alloc> -template <class _Key, class... _Args> -pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool> -__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args) { - size_t __hash = hash_function()(__k); - size_type __bc = bucket_count(); - bool __inserted = false; - __next_pointer __nd; - size_t __chash; - if (__bc != 0) { - __chash = std::__constrain_hash(__hash, __bc); - __nd = __bucket_list_[__chash]; - if (__nd != nullptr) { - for (__nd = __nd->__next_; - __nd != nullptr && (__nd->__hash() == __hash || std::__constrain_hash(__nd->__hash(), __bc) == __chash); - __nd = __nd->__next_) { - if ((__nd->__hash() == __hash) && key_eq()(__nd->__upcast()->__get_value(), __k)) - goto __done; - } - } - } - { - __node_holder __h = __construct_node_hash(__hash, std::forward<_Args>(__args)...); - if (size() + 1 > __bc * max_load_factor() || __bc == 0) { - __rehash_unique(std::max<size_type>( - 2 * __bc + !std::__is_hash_power2(__bc), size_type(__math::ceil(float(size() + 1) / max_load_factor())))); - __bc = bucket_count(); - __chash = std::__constrain_hash(__hash, __bc); - } - // insert_after __bucket_list_[__chash], or __first_node if bucket is null - __next_pointer __pn = __bucket_list_[__chash]; - if (__pn == nullptr) { - __pn = __first_node_.__ptr(); - __h->__next_ = __pn->__next_; - __pn->__next_ = __h.get()->__ptr(); - // fix up __bucket_list_ - __bucket_list_[__chash] = __pn; - if (__h->__next_ != nullptr) - __bucket_list_[std::__constrain_hash(__h->__next_->__hash(), __bc)] = __h.get()->__ptr(); - } else { - __h->__next_ = __pn->__next_; - __pn->__next_ = static_cast<__next_pointer>(__h.get()); - } - __nd = static_cast<__next_pointer>(__h.release()); - // increment size - ++size(); - __inserted = true; - } -__done: - return pair<iterator, bool>(iterator(__nd), __inserted); -} - -template <class _Tp, class _Hash, class _Equal, class _Alloc> -template <class... _Args> -pair<typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator, bool> -__hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_unique_impl(_Args&&... __args) { - __node_holder __h = __construct_node(std::forward<_Args>(__args)...); - pair<iterator, bool> __r = __node_insert_unique(__h.get()); - if (__r.second) - __h.release(); - return __r; -} - -template <class _Tp, class _Hash, class _Equal, class _Alloc> template <class... _Args> typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator __hash_table<_Tp, _Hash, _Equal, _Alloc>::__emplace_multi(_Args&&... __args) { @@ -1764,41 +1728,45 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__rehash(size_type __n) _LIBCPP_D template <class _Tp, class _Hash, class _Equal, class _Alloc> template <bool _UniqueKeys> -void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __nbc) { - __pointer_allocator& __npa = __bucket_list_.get_deleter().__alloc(); - __bucket_list_.reset(__nbc > 0 ? __pointer_alloc_traits::allocate(__npa, __nbc) : nullptr); - __bucket_list_.get_deleter().size() = __nbc; - if (__nbc > 0) { - for (size_type __i = 0; __i < __nbc; ++__i) - __bucket_list_[__i] = nullptr; - __next_pointer __pp = __first_node_.__ptr(); - __next_pointer __cp = __pp->__next_; - if (__cp != nullptr) { - size_type __chash = std::__constrain_hash(__cp->__hash(), __nbc); - __bucket_list_[__chash] = __pp; - size_type __phash = __chash; - for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) { - __chash = std::__constrain_hash(__cp->__hash(), __nbc); - if (__chash == __phash) - __pp = __cp; - else { - if (__bucket_list_[__chash] == nullptr) { - __bucket_list_[__chash] = __pp; - __pp = __cp; - __phash = __chash; - } else { - __next_pointer __np = __cp; - if _LIBCPP_CONSTEXPR_SINCE_CXX17 (!_UniqueKeys) { - for (; __np->__next_ != nullptr && - key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value()); - __np = __np->__next_) - ; - } - __pp->__next_ = __np->__next_; - __np->__next_ = __bucket_list_[__chash]->__next_; - __bucket_list_[__chash]->__next_ = __cp; - } +void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__do_rehash(size_type __bucket_count) { + __pointer_allocator& __ptr_alloc = __bucket_list_.get_deleter().__alloc(); + __bucket_list_.reset(__bucket_count > 0 ? __pointer_alloc_traits::allocate(__ptr_alloc, __bucket_count) : nullptr); + __bucket_list_.get_deleter().size() = __bucket_count; + + if (__bucket_count == 0) + return; + + for (size_type __i = 0; __i < __bucket_count; ++__i) + __bucket_list_[__i] = nullptr; + __next_pointer __pp = __first_node_.__ptr(); + __next_pointer __cp = __pp->__next_; + + if (!__cp) + return; + + size_type __chash = std::__constrain_hash(__cp->__hash(), __bucket_count); + __bucket_list_[__chash] = __pp; + size_type __phash = __chash; + for (__pp = __cp, void(), __cp = __cp->__next_; __cp != nullptr; __cp = __pp->__next_) { + __chash = std::__constrain_hash(__cp->__hash(), __bucket_count); + if (__chash == __phash) + __pp = __cp; + else { + if (__bucket_list_[__chash] == nullptr) { + __bucket_list_[__chash] = __pp; + __pp = __cp; + __phash = __chash; + } else { + __next_pointer __np = __cp; + if _LIBCPP_CONSTEXPR (!_UniqueKeys) { + for (; __np->__next_ != nullptr && + key_eq()(__cp->__upcast()->__get_value(), __np->__next_->__upcast()->__get_value()); + __np = __np->__next_) + ; } + __pp->__next_ = __np->__next_; + __np->__next_ = __bucket_list_[__chash]->__next_; + __bucket_list_[__chash]->__next_ = __cp; } } } @@ -1854,16 +1822,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) { __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - // Begin the lifetime of the node itself. Note that this doesn't begin the lifetime of the value - // held inside the node, since we need to use the allocator's construct() method for that. + // Begin the lifetime of the node itself and the value_type contained within. // // We don't use the allocator's construct() method to construct the node itself since the // Cpp17FooInsertable named requirements don't require the allocator's construct() method // to work on anything other than the value_type. - std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ 0); + std::__construct_at(std::addressof(*__h), /* hash = */ 0, __na, std::forward<_Args>(__args)...); - // Now construct the value_type using the allocator's construct() method. - __node_traits::construct(__na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; __h->__hash_ = hash_function()(__h->__get_value()); @@ -1871,15 +1836,13 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node(_Args&&... __args) { } template <class _Tp, class _Hash, class _Equal, class _Alloc> -template <class _First, class... _Rest> +template <class... _Args> typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::__node_holder -__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _First&& __f, _Rest&&... __rest) { - static_assert(!__is_hash_value_type<_First, _Rest...>::value, "Construct cannot be called with a hash value type"); +__hash_table<_Tp, _Hash, _Equal, _Alloc>::__construct_node_hash(size_t __hash, _Args&&... __args) { + static_assert(!__is_hash_value_type<_Args...>::value, "Construct cannot be called with a hash value type"); __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - std::__construct_at(std::addressof(*__h), /* next = */ nullptr, /* hash = */ __hash); - __node_traits::construct( - __na, _NodeTypes::__get_ptr(__h->__get_value()), std::forward<_First>(__f), std::forward<_Rest>(__rest)...); + std::__construct_at(std::addressof(*__h), /* hash = */ __hash, __na, std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; return __h; } @@ -1899,12 +1862,63 @@ __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __p) { template <class _Tp, class _Hash, class _Equal, class _Alloc> typename __hash_table<_Tp, _Hash, _Equal, _Alloc>::iterator __hash_table<_Tp, _Hash, _Equal, _Alloc>::erase(const_iterator __first, const_iterator __last) { - for (const_iterator __p = __first; __first != __last; __p = __first) { - ++__first; - erase(__p); + if (__first == __last) + return iterator(__last.__node_); + + // current node + __next_pointer __current = __first.__node_; + size_type __bucket_count = bucket_count(); + size_t __chash = std::__constrain_hash(__current->__hash(), __bucket_count); + // find previous node + __next_pointer __before_first = __bucket_list_[__chash]; + for (; __before_first->__next_ != __current; __before_first = __before_first->__next_) + ; + + __next_pointer __last_node = __last.__node_; + + // If __before_first is in the same bucket (i.e. the first element we erase is not the first in the bucket), clear + // this bucket first without re-linking it + if (__before_first != __first_node_.__ptr() && + std::__constrain_hash(__before_first->__hash(), __bucket_count) == __chash) { + while (__current != __last_node) { + auto __next = __current->__next_; + __deallocate_node(__current->__upcast()); + __current = __next; + --__size_; + + if (__next) { + if (auto __next_chash = std::__constrain_hash(__next->__hash(), __bucket_count); __next_chash != __chash) { + __bucket_list_[__next_chash] = __before_first; + __chash = __next_chash; + break; + } + } + } } - __next_pointer __np = __last.__node_; - return iterator(__np); + + while (__current != __last_node) { + auto __next = __current->__next_; + __deallocate_node(__current->__upcast()); + __current = __next; + --__size_; + + // When switching buckets, set the old bucket to be empty and update the next bucket to have __before_first as its + // before-first element + if (__next) { + if (auto __next_chash = std::__constrain_hash(__next->__hash(), __bucket_count); __next_chash != __chash) { + __bucket_list_[__chash] = nullptr; + __bucket_list_[__next_chash] = __before_first; + __chash = __next_chash; + } + } else { // When __next is a nullptr we've fully erased the last bucket. Update the bucket list accordingly. + __bucket_list_[__chash] = nullptr; + } + } + + // re-link __before_first with __last + __before_first->__next_ = __current; + + return iterator(__last.__node_); } template <class _Tp, class _Hash, class _Equal, class _Alloc> diff --git a/lib/libcxx/include/__ios/fpos.h b/lib/libcxx/include/__ios/fpos.h @@ -30,7 +30,7 @@ public: _LIBCPP_HIDE_FROM_ABI operator streamoff() const { return __off_; } - _LIBCPP_HIDE_FROM_ABI _StateT state() const { return __st_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _StateT state() const { return __st_; } _LIBCPP_HIDE_FROM_ABI void state(_StateT __st) { __st_ = __st; } _LIBCPP_HIDE_FROM_ABI fpos& operator+=(streamoff __off) { @@ -38,7 +38,7 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI fpos operator+(streamoff __off) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI fpos operator+(streamoff __off) const { fpos __t(*this); __t += __off; return __t; @@ -49,7 +49,7 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI fpos operator-(streamoff __off) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI fpos operator-(streamoff __off) const { fpos __t(*this); __t -= __off; return __t; @@ -57,7 +57,7 @@ public: }; template <class _StateT> -inline _LIBCPP_HIDE_FROM_ABI streamoff operator-(const fpos<_StateT>& __x, const fpos<_StateT>& __y) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI streamoff operator-(const fpos<_StateT>& __x, const fpos<_StateT>& __y) { return streamoff(__x) - streamoff(__y); } diff --git a/lib/libcxx/include/__iterator/back_insert_iterator.h b/lib/libcxx/include/__iterator/back_insert_iterator.h @@ -26,15 +26,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Container> class back_insert_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<back_insert_iterator<_Container>, output_iterator_tag, void, void, void, void> { protected: _Container* container; diff --git a/lib/libcxx/include/__iterator/bounded_iter.h b/lib/libcxx/include/__iterator/bounded_iter.h @@ -74,12 +74,12 @@ struct __bounded_iter { _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter const&) = default; _LIBCPP_HIDE_FROM_ABI __bounded_iter(__bounded_iter&&) = default; - template < class _OtherIterator, - __enable_if_t< - _And< is_convertible<const _OtherIterator&, _Iterator>, - _Or<is_same<reference, __iter_reference<_OtherIterator> >, - is_same<reference, __make_const_lvalue_ref<__iter_reference<_OtherIterator> > > > >::value, - int> = 0> + template <class _OtherIterator, + __enable_if_t< + _And<is_convertible<const _OtherIterator&, _Iterator>, + _Or<is_same<reference, __iterator_reference<_OtherIterator> >, + is_same<reference, __make_const_lvalue_ref<__iterator_reference<_OtherIterator> > > > >::value, + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __bounded_iter(__bounded_iter<_OtherIterator> const& __other) _NOEXCEPT : __current_(__other.__current_), __begin_(__other.__begin_), @@ -116,8 +116,7 @@ public: // These operations check that the iterator is dereferenceable. Since the class invariant is // that the iterator is always within `[begin, end]`, we only need to check it's not pointing to // `end`. This is easier for the optimizer because it aligns with the `iter != container.end()` - // checks that typical callers already use (see - // https://github.com/llvm/llvm-project/issues/78829). + // checks that typical callers already use (see https://llvm.org/PR78829). _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __current_ != __end_, "__bounded_iter::operator*: Attempt to dereference an iterator at the end"); diff --git a/lib/libcxx/include/__iterator/concepts.h b/lib/libcxx/include/__iterator/concepts.h @@ -117,15 +117,12 @@ template <class _Tp> concept __signed_integer_like = signed_integral<_Tp>; template <class _Ip> -concept weakly_incrementable = - // TODO: remove this once the clang bug is fixed (bugs.llvm.org/PR48173). - !same_as<_Ip, bool> && // Currently, clang does not handle bool correctly. - movable<_Ip> && requires(_Ip __i) { - typename iter_difference_t<_Ip>; - requires __signed_integer_like<iter_difference_t<_Ip>>; - { ++__i } -> same_as<_Ip&>; // not required to be equality-preserving - __i++; // not required to be equality-preserving - }; +concept weakly_incrementable = movable<_Ip> && requires(_Ip __i) { + typename iter_difference_t<_Ip>; + requires __signed_integer_like<iter_difference_t<_Ip>>; + { ++__i } -> same_as<_Ip&>; // not required to be equality-preserving + __i++; // not required to be equality-preserving +}; // [iterator.concept.inc] template <class _Ip> diff --git a/lib/libcxx/include/__iterator/cpp17_iterator_concepts.h b/lib/libcxx/include/__iterator/cpp17_iterator_concepts.h @@ -68,7 +68,8 @@ concept __cpp17_default_constructible = is_default_constructible_v<_Tp>; template <class _Iter> concept __cpp17_iterator = __cpp17_copy_constructible<_Iter> && __cpp17_copy_assignable<_Iter> && __cpp17_destructible<_Iter> && - (is_signed_v<__iter_diff_t<_Iter>> || is_void_v<__iter_diff_t<_Iter>>) && requires(_Iter __iter) { + (is_signed_v<__iterator_difference_type<_Iter>> || is_void_v<__iterator_difference_type<_Iter>>) && + requires(_Iter __iter) { { *__iter }; { ++__iter } -> same_as<_Iter&>; }; @@ -81,8 +82,8 @@ concept __cpp17_input_iterator = { __lhs != std::as_const(__rhs) } -> __boolean_testable; { std::as_const(__lhs) != std::as_const(__rhs) } -> __boolean_testable; - { *__lhs } -> same_as<__iter_reference<_Iter>>; - { *std::as_const(__lhs) } -> same_as<__iter_reference<_Iter>>; + { *__lhs } -> same_as<__iterator_reference<_Iter>>; + { *std::as_const(__lhs) } -> same_as<__iterator_reference<_Iter>>; { ++__lhs } -> same_as<_Iter&>; { (void)__lhs++ }; @@ -101,19 +102,19 @@ template <class _Iter> concept __cpp17_forward_iterator = __cpp17_input_iterator<_Iter> && __cpp17_default_constructible<_Iter> && requires(_Iter __iter) { { __iter++ } -> convertible_to<const _Iter&>; - { *__iter++ } -> same_as<__iter_reference<_Iter>>; + { *__iter++ } -> same_as<__iterator_reference<_Iter>>; }; template <class _Iter> concept __cpp17_bidirectional_iterator = __cpp17_forward_iterator<_Iter> && requires(_Iter __iter) { { --__iter } -> same_as<_Iter&>; { __iter-- } -> convertible_to<const _Iter&>; - { *__iter-- } -> same_as<__iter_reference<_Iter>>; + { *__iter-- } -> same_as<__iterator_reference<_Iter>>; }; template <class _Iter> concept __cpp17_random_access_iterator = - __cpp17_bidirectional_iterator<_Iter> && requires(_Iter __iter, __iter_diff_t<_Iter> __n) { + __cpp17_bidirectional_iterator<_Iter> && requires(_Iter __iter, __iterator_difference_type<_Iter> __n) { { __iter += __n } -> same_as<_Iter&>; { __iter + __n } -> same_as<_Iter>; @@ -125,13 +126,13 @@ concept __cpp17_random_access_iterator = { __iter - __n } -> same_as<_Iter>; { std::as_const(__iter) - __n } -> same_as<_Iter>; - { __iter - __iter } -> same_as<__iter_diff_t<_Iter>>; - { std::as_const(__iter) - __iter } -> same_as<__iter_diff_t<_Iter>>; - { __iter - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; - { std::as_const(__iter) - std::as_const(__iter) } -> same_as<__iter_diff_t<_Iter>>; + { __iter - __iter } -> same_as<__iterator_difference_type<_Iter>>; + { std::as_const(__iter) - __iter } -> same_as<__iterator_difference_type<_Iter>>; + { __iter - std::as_const(__iter) } -> same_as<__iterator_difference_type<_Iter>>; + { std::as_const(__iter) - std::as_const(__iter) } -> same_as<__iterator_difference_type<_Iter>>; - { __iter[__n] } -> convertible_to<__iter_reference<_Iter>>; - { std::as_const(__iter)[__n] } -> convertible_to<__iter_reference<_Iter>>; + { __iter[__n] } -> convertible_to<__iterator_reference<_Iter>>; + { std::as_const(__iter)[__n] } -> convertible_to<__iterator_reference<_Iter>>; { __iter < __iter } -> __boolean_testable; { std::as_const(__iter) < __iter } -> __boolean_testable; diff --git a/lib/libcxx/include/__iterator/distance.h b/lib/libcxx/include/__iterator/distance.h @@ -10,41 +10,66 @@ #ifndef _LIBCPP___ITERATOR_DISTANCE_H #define _LIBCPP___ITERATOR_DISTANCE_H +#include <__algorithm/for_each_segment.h> +#include <__concepts/same_as.h> #include <__config> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> +#include <__iterator/segmented_iterator.h> #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/size.h> #include <__type_traits/decay.h> +#include <__type_traits/enable_if.h> #include <__type_traits/remove_cvref.h> +#include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD -template <class _InputIter> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type -__distance(_InputIter __first, _InputIter __last, input_iterator_tag) { - typename iterator_traits<_InputIter>::difference_type __r(0); - for (; __first != __last; ++__first) - ++__r; - return __r; -} +#if _LIBCPP_STD_VER >= 20 +template <class _Iter> +using __iter_distance_t _LIBCPP_NODEBUG = std::iter_difference_t<_Iter>; +#else +template <class _Iter> +using __iter_distance_t _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type; +#endif -template <class _RandIter> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_RandIter>::difference_type -__distance(_RandIter __first, _RandIter __last, random_access_iterator_tag) { +template <class _RandIter, __enable_if_t<__has_random_access_iterator_category<_RandIter>::value, int> = 0> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_RandIter> +__distance(_RandIter __first, _RandIter __last) { return __last - __first; } +template <class _InputIter, class _Sent> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 __iter_distance_t<_InputIter> +__distance(_InputIter __first, _Sent __last) { + __iter_distance_t<_InputIter> __r(0); +#if _LIBCPP_STD_VER >= 20 + if constexpr (same_as<_InputIter, _Sent> && __is_segmented_iterator_v<_InputIter>) { + std::__for_each_segment(__first, __last, [&__r](auto __lfirst, auto __llast) { + __r += std::__distance(__lfirst, __llast); + }); + } else +#endif + { + for (; __first != __last; ++__first) + ++__r; + } + return __r; +} + template <class _InputIter> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 typename iterator_traits<_InputIter>::difference_type distance(_InputIter __first, _InputIter __last) { - return std::__distance(__first, __last, typename iterator_traits<_InputIter>::iterator_category()); + return std::__distance(__first, __last); } #if _LIBCPP_STD_VER >= 20 @@ -56,12 +81,7 @@ struct __distance { template <class _Ip, sentinel_for<_Ip> _Sp> requires(!sized_sentinel_for<_Sp, _Ip>) _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip __first, _Sp __last) const { - iter_difference_t<_Ip> __n = 0; - while (__first != __last) { - ++__first; - ++__n; - } - return __n; + return std::__distance(std::move(__first), std::move(__last)); } template <class _Ip, sized_sentinel_for<decay_t<_Ip>> _Sp> @@ -92,4 +112,6 @@ inline constexpr auto distance = __distance{}; _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___ITERATOR_DISTANCE_H diff --git a/lib/libcxx/include/__iterator/front_insert_iterator.h b/lib/libcxx/include/__iterator/front_insert_iterator.h @@ -26,15 +26,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Container> class front_insert_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<front_insert_iterator<_Container>, output_iterator_tag, void, void, void, void> { protected: _Container* container; diff --git a/lib/libcxx/include/__iterator/insert_iterator.h b/lib/libcxx/include/__iterator/insert_iterator.h @@ -35,15 +35,9 @@ template <class _Container> using __insert_iterator_iter_t _LIBCPP_NODEBUG = typename _Container::iterator; #endif -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Container> class insert_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<insert_iterator<_Container>, output_iterator_tag, void, void, void, void> { protected: _Container* container; __insert_iterator_iter_t<_Container> iter; diff --git a/lib/libcxx/include/__iterator/istream_iterator.h b/lib/libcxx/include/__iterator/istream_iterator.h @@ -25,15 +25,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Tp, class _CharT = char, class _Traits = char_traits<_CharT>, class _Distance = ptrdiff_t> class istream_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<input_iterator_tag, _Tp, _Distance, const _Tp*, const _Tp&> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<istream_iterator<_Tp, _CharT, _Traits, _Distance>, + input_iterator_tag, + _Tp, + _Distance, + const _Tp*, + const _Tp&> { public: typedef input_iterator_tag iterator_category; typedef _Tp value_type; diff --git a/lib/libcxx/include/__iterator/istreambuf_iterator.h b/lib/libcxx/include/__iterator/istreambuf_iterator.h @@ -25,15 +25,14 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _CharT, class _Traits> class istreambuf_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type, _CharT*, _CharT> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<istreambuf_iterator<_CharT, _Traits>, + input_iterator_tag, + _CharT, + typename _Traits::off_type, + _CharT*, + _CharT> { public: typedef input_iterator_tag iterator_category; typedef _CharT value_type; diff --git a/lib/libcxx/include/__iterator/iter_move.h b/lib/libcxx/include/__iterator/iter_move.h @@ -40,7 +40,7 @@ void iter_move() = delete; template <class _Tp> concept __unqualified_iter_move = __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) { - // NOLINTNEXTLINE(libcpp-robust-against-adl) iter_swap ADL calls should only be made through ranges::iter_swap + // NOLINTNEXTLINE(libcpp-robust-against-adl) iter_move ADL calls should only be made through ranges::iter_move iter_move(std::forward<_Tp>(__t)); }; diff --git a/lib/libcxx/include/__iterator/iterator.h b/lib/libcxx/include/__iterator/iterator.h @@ -28,6 +28,19 @@ struct _LIBCPP_DEPRECATED_IN_CXX17 iterator { typedef _Category iterator_category; }; +_LIBCPP_SUPPRESS_DEPRECATED_PUSH +#ifdef _LIBCPP_ABI_NO_ITERATOR_BASES +template <class _Derived> +struct __no_iterator_base {}; + +template <class _Derived, class _Category, class _Tp, class _Distance, class _Pointer, class _Reference> +using __iterator_base _LIBCPP_NODEBUG = __no_iterator_base<_Derived>; +#else +template <class _Derived, class _Category, class _Tp, class _Distance, class _Pointer, class _Reference> +using __iterator_base _LIBCPP_NODEBUG = iterator<_Category, _Tp, _Distance, _Pointer, _Reference>; +#endif +_LIBCPP_SUPPRESS_DEPRECATED_POP + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ITERATOR_ITERATOR_H diff --git a/lib/libcxx/include/__iterator/iterator_traits.h b/lib/libcxx/include/__iterator/iterator_traits.h @@ -420,44 +420,43 @@ using __has_exactly_bidirectional_iterator_category _LIBCPP_NODEBUG = !__has_iterator_category_convertible_to<_Tp, random_access_iterator_tag>::value>; template <class _InputIterator> -using __iter_value_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type; +using __iterator_value_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type; #if _LIBCPP_STD_VER >= 23 template <class _InputIterator> -using __iter_key_type _LIBCPP_NODEBUG = remove_const_t<tuple_element_t<0, __iter_value_type<_InputIterator>>>; +using __iter_key_type _LIBCPP_NODEBUG = remove_const_t<tuple_element_t<0, __iterator_value_type<_InputIterator>>>; template <class _InputIterator> -using __iter_mapped_type _LIBCPP_NODEBUG = tuple_element_t<1, __iter_value_type<_InputIterator>>; +using __iter_mapped_type _LIBCPP_NODEBUG = tuple_element_t<1, __iterator_value_type<_InputIterator>>; template <class _InputIterator> using __iter_to_alloc_type _LIBCPP_NODEBUG = - pair<const tuple_element_t<0, __iter_value_type<_InputIterator>>, - tuple_element_t<1, __iter_value_type<_InputIterator>>>; + pair<const tuple_element_t<0, __iterator_value_type<_InputIterator>>, + tuple_element_t<1, __iterator_value_type<_InputIterator>>>; #else template <class _InputIterator> -using __iter_key_type _LIBCPP_NODEBUG = - __remove_const_t<typename iterator_traits<_InputIterator>::value_type::first_type>; +using __iter_key_type _LIBCPP_NODEBUG = __remove_const_t<typename __iterator_value_type<_InputIterator>::first_type>; template <class _InputIterator> -using __iter_mapped_type _LIBCPP_NODEBUG = typename iterator_traits<_InputIterator>::value_type::second_type; +using __iter_mapped_type _LIBCPP_NODEBUG = typename __iterator_value_type<_InputIterator>::second_type; template <class _InputIterator> using __iter_to_alloc_type _LIBCPP_NODEBUG = - pair<const typename iterator_traits<_InputIterator>::value_type::first_type, - typename iterator_traits<_InputIterator>::value_type::second_type>; + pair<const typename __iterator_value_type<_InputIterator>::first_type, + typename __iterator_value_type<_InputIterator>::second_type>; #endif // _LIBCPP_STD_VER >= 23 template <class _Iter> -using __iterator_category_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category; +using __iterator_iterator_category _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::iterator_category; template <class _Iter> -using __iterator_pointer_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::pointer; +using __iterator_pointer _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::pointer; template <class _Iter> -using __iter_diff_t _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type; +using __iterator_difference_type _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::difference_type; template <class _Iter> -using __iter_reference _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::reference; +using __iterator_reference _LIBCPP_NODEBUG = typename iterator_traits<_Iter>::reference; #if _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/__iterator/ostream_iterator.h b/lib/libcxx/include/__iterator/ostream_iterator.h @@ -24,15 +24,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Tp, class _CharT = char, class _Traits = char_traits<_CharT> > class ostream_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<ostream_iterator<_Tp, _CharT, _Traits>, output_iterator_tag, void, void, void, void> { public: typedef output_iterator_tag iterator_category; typedef void value_type; diff --git a/lib/libcxx/include/__iterator/ostreambuf_iterator.h b/lib/libcxx/include/__iterator/ostreambuf_iterator.h @@ -25,15 +25,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _CharT, class _Traits> class ostreambuf_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<ostreambuf_iterator<_CharT, _Traits>, output_iterator_tag, void, void, void, void> { public: typedef output_iterator_tag iterator_category; typedef void value_type; diff --git a/lib/libcxx/include/__iterator/reverse_iterator.h b/lib/libcxx/include/__iterator/reverse_iterator.h @@ -46,21 +46,16 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _Iter> class reverse_iterator -#if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<typename iterator_traits<_Iter>::iterator_category, - typename iterator_traits<_Iter>::value_type, - typename iterator_traits<_Iter>::difference_type, - typename iterator_traits<_Iter>::pointer, - typename iterator_traits<_Iter>::reference> -#endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<reverse_iterator<_Iter>, + typename iterator_traits<_Iter>::iterator_category, + typename iterator_traits<_Iter>::value_type, + typename iterator_traits<_Iter>::difference_type, + typename iterator_traits<_Iter>::pointer, + typename iterator_traits<_Iter>::reference> { private: -#ifndef _LIBCPP_ABI_NO_ITERATOR_BASES +#ifndef _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER _Iter __t_; // no longer used as of LWG #2360, not removed due to ABI break #endif @@ -91,7 +86,7 @@ public: using reference = typename iterator_traits<_Iter>::reference; #endif -#ifndef _LIBCPP_ABI_NO_ITERATOR_BASES +#ifndef _LIBCPP_ABI_NO_REVERSE_ITERATOR_SECOND_MEMBER _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator() : __t_(), current() {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 explicit reverse_iterator(_Iter __x) : __t_(__x), current(__x) {} diff --git a/lib/libcxx/include/__iterator/segmented_iterator.h b/lib/libcxx/include/__iterator/segmented_iterator.h @@ -67,18 +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> >; - -template <class _SegmentedIterator> -struct __has_random_access_local_iterator - : __has_random_access_iterator_category< - typename __segmented_iterator_traits< _SegmentedIterator >::__local_iterator > {}; +inline const bool __is_segmented_iterator_v = __has_specialization_v<__segmented_iterator_traits<_Iterator> >; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__iterator/static_bounded_iter.h b/lib/libcxx/include/__iterator/static_bounded_iter.h @@ -99,9 +99,9 @@ struct __static_bounded_iter { template <class _OtherIterator, __enable_if_t< - _And< is_convertible<const _OtherIterator&, _Iterator>, - _Or<is_same<reference, __iter_reference<_OtherIterator> >, - is_same<reference, __make_const_lvalue_ref<__iter_reference<_OtherIterator> > > > >::value, + _And<is_convertible<const _OtherIterator&, _Iterator>, + _Or<is_same<reference, __iterator_reference<_OtherIterator> >, + is_same<reference, __make_const_lvalue_ref<__iterator_reference<_OtherIterator> > > > >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __static_bounded_iter(__static_bounded_iter<_OtherIterator, _Size> const& __other) _NOEXCEPT diff --git a/lib/libcxx/include/__iterator/wrap_iter.h b/lib/libcxx/include/__iterator/wrap_iter.h @@ -49,12 +49,12 @@ private: public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter() _NOEXCEPT : __i_() {} - template < - class _OtherIter, - __enable_if_t< _And< is_convertible<const _OtherIter&, _Iter>, - _Or<is_same<reference, __iter_reference<_OtherIter> >, - is_same<reference, __make_const_lvalue_ref<__iter_reference<_OtherIter> > > > >::value, - int> = 0> + template <class _OtherIter, + __enable_if_t< + _And<is_convertible<const _OtherIter&, _Iter>, + _Or<is_same<reference, __iterator_reference<_OtherIter> >, + is_same<reference, __make_const_lvalue_ref<__iterator_reference<_OtherIter> > > > >::value, + int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_OtherIter>& __u) _NOEXCEPT : __i_(__u.__i_) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { return *__i_; } @@ -117,6 +117,8 @@ private: friend class span; template <class _Tp, size_t _Size> friend struct array; + template <class _Tp, class> + friend struct __optional_iterator; }; template <class _Iter1> diff --git a/lib/libcxx/include/__locale b/lib/libcxx/include/__locale @@ -57,9 +57,8 @@ _LIBCPP_HIDE_FROM_ABI const _Facet& use_facet(const locale&); class _LIBCPP_EXPORTED_FROM_ABI locale { public: // locale is essentially a shared_ptr that doesn't support weak_ptrs and never got a move constructor, - // so it is trivially relocatable. Like shared_ptr, it is also replaceable. + // so it is trivially relocatable. using __trivially_relocatable _LIBCPP_NODEBUG = locale; - using __replaceable _LIBCPP_NODEBUG = locale; // types: class _LIBCPP_EXPORTED_FROM_ABI facet; @@ -389,7 +388,7 @@ public: static const mask xdigit = _ISXDIGIT; static const mask blank = _ISBLANK; static const mask __regex_word = 0x8000; -# elif defined(_NEWLIB_VERSION) +# elif _LIBCPP_LIBC_NEWLIB // Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h. typedef char mask; // In case char is signed, static_cast is needed to avoid warning on @@ -585,7 +584,7 @@ public: # ifdef _CACHED_RUNES static const size_t table_size = _CACHED_RUNES; # else - static const size_t table_size = 256; // FIXME: Don't hardcode this. + static const size_t table_size = 256; # endif _LIBCPP_HIDE_FROM_ABI const mask* table() const _NOEXCEPT { return __tab_; } static const mask* classic_table() _NOEXCEPT; @@ -1478,9 +1477,6 @@ public: protected: ~numpunct_byname() override; - -private: - void __init(const char*); }; # if _LIBCPP_HAS_WIDE_CHARACTERS @@ -1495,9 +1491,6 @@ public: protected: ~numpunct_byname() override; - -private: - void __init(const char*); }; # endif // _LIBCPP_HAS_WIDE_CHARACTERS diff --git a/lib/libcxx/include/__locale_dir/locale_base_api.h b/lib/libcxx/include/__locale_dir/locale_base_api.h @@ -57,15 +57,11 @@ // float __strtof(const char*, char**, __locale_t); // double __strtod(const char*, char**, __locale_t); // long double __strtold(const char*, char**, __locale_t); -// long long __strtoll(const char*, char**, __locale_t); -// unsigned long long __strtoull(const char*, char**, __locale_t); // } // // Character manipulation functions // -------------------------------- // namespace __locale { -// int __isdigit(int, __locale_t); // required by the headers -// int __isxdigit(int, __locale_t); // required by the headers // int __toupper(int, __locale_t); // int __tolower(int, __locale_t); // int __strcoll(const char*, const char*, __locale_t); @@ -106,7 +102,6 @@ // // int __snprintf(char*, size_t, __locale_t, const char*, ...); // required by the headers // int __asprintf(char**, __locale_t, const char*, ...); // required by the headers -// int __sscanf(const char*, __locale_t, const char*, ...); // required by the headers // } #if _LIBCPP_HAS_LOCALIZATION @@ -115,7 +110,6 @@ # include <__locale_dir/support/apple.h> # elif defined(__FreeBSD__) # include <__locale_dir/support/freebsd.h> -/* zig patch: https://github.com/llvm/llvm-project/pull/143055 */ # elif defined(__NetBSD__) # include <__locale_dir/support/netbsd.h> # elif defined(_LIBCPP_MSVCRT_LIKE) @@ -124,20 +118,20 @@ # include <__locale_dir/support/fuchsia.h> # elif defined(__linux__) # include <__locale_dir/support/linux.h> +# elif _LIBCPP_LIBC_NEWLIB +# include <__locale_dir/support/newlib.h> +# elif defined(_AIX) +# include <__locale_dir/support/aix.h> # else // TODO: This is a temporary definition to bridge between the old way we defined the locale base API // (by providing global non-reserved names) and the new API. As we move individual platforms // towards the new way of defining the locale base API, this should disappear since each platform // will define those directly. -# if defined(_AIX) || defined(__MVS__) +# if defined(__MVS__) # include <__locale_dir/locale_base_api/ibm.h> -# elif defined(__ANDROID__) -# include <__locale_dir/locale_base_api/android.h> # elif defined(__OpenBSD__) # include <__locale_dir/locale_base_api/openbsd.h> -# elif defined(__wasi__) || _LIBCPP_HAS_MUSL_LIBC -# include <__locale_dir/locale_base_api/musl.h> # endif # include <__locale_dir/locale_base_api/bsd_locale_fallbacks.h> @@ -197,21 +191,9 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __ return strtold_l(__nptr, __endptr, __loc); } -inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return strtoll_l(__nptr, __endptr, __base, __loc); -} - -inline _LIBCPP_HIDE_FROM_ABI unsigned long long -__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return strtoull_l(__nptr, __endptr, __base, __loc); -} - // // Character manipulation functions // -inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __ch, __locale_t __loc) { return isdigit_l(__ch, __loc); } -inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __ch, __locale_t __loc) { return isxdigit_l(__ch, __loc); } - # if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __strcoll(const char* __s1, const char* __s2, __locale_t __loc) { return strcoll_l(__s1, __s2, __loc); @@ -307,11 +289,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __ char** __s, __locale_t __loc, const char* __format, _Args&&... __args) { return std::__libcpp_asprintf_l(__s, __loc, __format, std::forward<_Args>(__args)...); } -template <class... _Args> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf( - const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) { - return std::__libcpp_sscanf_l(__s, __loc, __format, std::forward<_Args>(__args)...); -} _LIBCPP_DIAGNOSTIC_POP # undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT diff --git a/lib/libcxx/include/__locale_dir/locale_base_api/bsd_locale_fallbacks.h b/lib/libcxx/include/__locale_dir/locale_base_api/bsd_locale_fallbacks.h @@ -125,16 +125,6 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __libcpp_asprintf_l( return __res; } -inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __libcpp_sscanf_l( - const char* __s, locale_t __l, const char* __format, ...) { - va_list __va; - va_start(__va, __format); - __locale_guard __current(__l); - int __res = vsscanf(__s, __format, __va); - va_end(__va); - return __res; -} - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_BSD_LOCALE_FALLBACKS_H diff --git a/lib/libcxx/include/__locale_dir/messages.h b/lib/libcxx/include/__locale_dir/messages.h @@ -22,7 +22,7 @@ # if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // Most unix variants have catopen. These are the specific ones that don't. -# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) +# if !defined(__BIONIC__) && !_LIBCPP_LIBC_NEWLIB && !defined(__EMSCRIPTEN__) # define _LIBCPP_HAS_CATOPEN 1 # include <nl_types.h> # else diff --git a/lib/libcxx/include/__locale_dir/money.h b/lib/libcxx/include/__locale_dir/money.h @@ -433,7 +433,7 @@ bool money_get<_CharT, _InputIterator>::__do_get( __err |= ios_base::failbit; return false; } - for (++__b; __fd > 0; --__fd, ++__b) { + for (++__b; __fd > 0; --__fd, (void)++__b) { if (__b == __e || !__ct.is(ctype_base::digit, *__b)) { __err |= ios_base::failbit; return false; @@ -451,7 +451,7 @@ bool money_get<_CharT, _InputIterator>::__do_get( } } if (__trailing_sign) { - for (unsigned __i = 1; __i < __trailing_sign->size(); ++__i, ++__b) { + for (unsigned __i = 1; __i < __trailing_sign->size(); ++__i, (void)++__b) { if (__b == __e || *__b != (*__trailing_sign)[__i]) { __err |= ios_base::failbit; return false; diff --git a/lib/libcxx/include/__locale_dir/num.h b/lib/libcxx/include/__locale_dir/num.h @@ -9,8 +9,10 @@ #ifndef _LIBCPP___LOCALE_DIR_NUM_H #define _LIBCPP___LOCALE_DIR_NUM_H +#include <__algorithm/copy.h> #include <__algorithm/find.h> #include <__algorithm/reverse.h> +#include <__algorithm/simd_utils.h> #include <__charconv/to_chars_integral.h> #include <__charconv/traits.h> #include <__config> @@ -22,6 +24,7 @@ #include <__locale_dir/scan_keyword.h> #include <__memory/unique_ptr.h> #include <__system_error/errc.h> +#include <__type_traits/is_signed.h> #include <cerrno> #include <ios> #include <streambuf> @@ -46,9 +49,9 @@ struct _LIBCPP_EXPORTED_FROM_ABI __num_get_base { static int __get_base(ios_base&); static const char __src[33]; // "0123456789abcdefABCDEFxX+-pPiInN" // count of leading characters in __src used for parsing integers ("012..X+-") - static const size_t __int_chr_cnt = 26; + static inline const size_t __int_chr_cnt = 26; // count of leading characters in __src used for parsing floating-point values ("012..-pP") - static const size_t __fp_chr_cnt = 28; + static inline const size_t __fp_chr_cnt = 28; }; template <class _CharT> @@ -71,7 +74,8 @@ struct __num_get : protected __num_get_base { [[__deprecated__("This exists only for ABI compatibility")]] static string __stage2_int_prep(ios_base& __iob, _CharT* __atoms, _CharT& __thousands_sep); - static int __stage2_int_loop( + + [[__deprecated__("This exists only for ABI compatibility")]] static int __stage2_int_loop( _CharT __ct, int __base, char* __a, @@ -83,11 +87,24 @@ struct __num_get : protected __num_get_base { unsigned*& __g_end, _CharT* __atoms); - _LIBCPP_HIDE_FROM_ABI static string __stage2_int_prep(ios_base& __iob, _CharT& __thousands_sep) { - locale __loc = __iob.getloc(); - const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc); - __thousands_sep = __np.thousands_sep(); - return __np.grouping(); + _LIBCPP_HIDE_FROM_ABI static ptrdiff_t __atoms_offset(const _CharT* __atoms, _CharT __val) { + // TODO: Remove the manual vectorization once https://llvm.org/PR168551 is resolved +# if _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS + if constexpr (is_same<_CharT, char>::value) { + // TODO(LLVM 24): This can be removed, since -Wpsabi doesn't warn on [[gnu::always_inline]] functions anymore. + _LIBCPP_DIAGNOSTIC_PUSH + _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") + using __vec = __simd_vector<char, 32>; + __vec __chars = std::__broadcast<__vec>(__val); + __vec __cmp = std::__partial_load<__vec, __int_chr_cnt>(__atoms); + auto __res = __chars == __cmp; + if (std::__none_of(__res)) + return __int_chr_cnt; + return std::min(__int_chr_cnt, std::__find_first_set(__res)); + _LIBCPP_DIAGNOSTIC_POP + } +# endif + return std::find(__atoms, __atoms + __int_chr_cnt, __val) - __atoms; } _LIBCPP_HIDE_FROM_ABI const _CharT* __do_widen(ios_base& __iob, _CharT* __atoms) const { @@ -121,54 +138,6 @@ string __num_get<_CharT>::__stage2_float_prep( } template <class _CharT> -int __num_get<_CharT>::__stage2_int_loop( - _CharT __ct, - int __base, - char* __a, - char*& __a_end, - unsigned& __dc, - _CharT __thousands_sep, - const string& __grouping, - unsigned* __g, - unsigned*& __g_end, - _CharT* __atoms) { - if (__a_end == __a && (__ct == __atoms[24] || __ct == __atoms[25])) { - *__a_end++ = __ct == __atoms[24] ? '+' : '-'; - __dc = 0; - return 0; - } - if (__grouping.size() != 0 && __ct == __thousands_sep) { - if (__g_end - __g < __num_get_buf_sz) { - *__g_end++ = __dc; - __dc = 0; - } - return 0; - } - ptrdiff_t __f = std::find(__atoms, __atoms + __int_chr_cnt, __ct) - __atoms; - if (__f >= 24) - return -1; - switch (__base) { - case 8: - case 10: - if (__f >= __base) - return -1; - break; - case 16: - if (__f < 22) - break; - if (__a_end != __a && __a_end - __a <= 2 && __a_end[-1] == '0') { - __dc = 0; - *__a_end++ = __src[__f]; - return 0; - } - return -1; - } - *__a_end++ = __src[__f]; - ++__dc; - return 0; -} - -template <class _CharT> int __num_get<_CharT>::__stage2_float_loop( _CharT __ct, bool& __in_units, @@ -272,65 +241,6 @@ _LIBCPP_HIDE_FROM_ABI _Tp __num_get_float(const char* __a, const char* __a_end, return 0; } -template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp -__num_get_signed_integral(const char* __a, const char* __a_end, ios_base::iostate& __err, int __base) { - if (__a != __a_end) { - __libcpp_remove_reference_t<decltype(errno)> __save_errno = errno; - errno = 0; - char* __p2; - long long __ll = __locale::__strtoll(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE); - __libcpp_remove_reference_t<decltype(errno)> __current_errno = errno; - if (__current_errno == 0) - errno = __save_errno; - if (__p2 != __a_end) { - __err = ios_base::failbit; - return 0; - } else if (__current_errno == ERANGE || __ll < numeric_limits<_Tp>::min() || numeric_limits<_Tp>::max() < __ll) { - __err = ios_base::failbit; - if (__ll > 0) - return numeric_limits<_Tp>::max(); - else - return numeric_limits<_Tp>::min(); - } - return static_cast<_Tp>(__ll); - } - __err = ios_base::failbit; - return 0; -} - -template <class _Tp> -_LIBCPP_HIDE_FROM_ABI _Tp -__num_get_unsigned_integral(const char* __a, const char* __a_end, ios_base::iostate& __err, int __base) { - if (__a != __a_end) { - const bool __negate = *__a == '-'; - if (__negate && ++__a == __a_end) { - __err = ios_base::failbit; - return 0; - } - __libcpp_remove_reference_t<decltype(errno)> __save_errno = errno; - errno = 0; - char* __p2; - unsigned long long __ll = __locale::__strtoull(__a, &__p2, __base, _LIBCPP_GET_C_LOCALE); - __libcpp_remove_reference_t<decltype(errno)> __current_errno = errno; - if (__current_errno == 0) - errno = __save_errno; - if (__p2 != __a_end) { - __err = ios_base::failbit; - return 0; - } else if (__current_errno == ERANGE || numeric_limits<_Tp>::max() < __ll) { - __err = ios_base::failbit; - return numeric_limits<_Tp>::max(); - } - _Tp __res = static_cast<_Tp>(__ll); - if (__negate) - __res = -__res; - return __res; - } - __err = ios_base::failbit; - return 0; -} - template <class _CharT, class _InputIterator = istreambuf_iterator<_CharT> > class num_get : public locale::facet, private __num_get<_CharT> { public: @@ -468,137 +378,196 @@ protected: return __b; } - template <class _Signed> - _LIBCPP_HIDE_FROM_ABI iter_type - __do_get_signed(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Signed& __v) const { + template <class _MaybeSigned> + iter_type __do_get_integral( + iter_type __first, iter_type __last, ios_base& __iob, ios_base::iostate& __err, _MaybeSigned& __v) const { + using _Unsigned = __make_unsigned_t<_MaybeSigned>; + // Stage 1 int __base = this->__get_base(__iob); - // Stage 2 - char_type __thousands_sep; - const int __atoms_size = __num_get_base::__int_chr_cnt; - char_type __atoms1[__atoms_size]; - const char_type* __atoms = this->__do_widen(__iob, __atoms1); - string __grouping = this->__stage2_int_prep(__iob, __thousands_sep); - string __buf; - __buf.resize(__buf.capacity()); - char* __a = &__buf[0]; - char* __a_end = __a; + + // Stages 2 & 3 + // These are combined into a single step where we parse the characters and calculate the value in one go instead of + // storing the relevant characters first (in an allocated buffer) and parse the characters after we extracted them. + // This makes the whole process significantly faster, since we avoid potential allocations and copies. + + const auto& __numpunct = use_facet<numpunct<_CharT> >(__iob.getloc()); + char_type __thousands_sep = __numpunct.thousands_sep(); + string __grouping = __numpunct.grouping(); + + char_type __atoms_buffer[__num_get_base::__int_chr_cnt]; + const char_type* __atoms = this->__do_widen(__iob, __atoms_buffer); unsigned __g[__num_get_base::__num_get_buf_sz]; unsigned* __g_end = __g; unsigned __dc = 0; - for (; __b != __e; ++__b) { - if (__a_end == __a + __buf.size()) { - size_t __tmp = __buf.size(); - __buf.resize(2 * __buf.size()); - __buf.resize(__buf.capacity()); - __a = &__buf[0]; - __a_end = __a + __tmp; + + if (__first == __last) { + __err |= ios_base::eofbit | ios_base::failbit; + __v = 0; + return __first; + } + + while (!__grouping.empty() && *__first == __thousands_sep) { + ++__first; + if (__g_end - __g < this->__num_get_buf_sz) + *__g_end++ = 0; + } + + bool __negate = false; + // __c == '+' || __c == '-' + if (auto __c = *__first; __c == __atoms[24] || __c == __atoms[25]) { + __negate = __c == __atoms[25]; + ++__first; + } + + if (__first == __last) { + __err |= ios_base::eofbit | ios_base::failbit; + __v = 0; + return __first; + } + + bool __parsed_num = false; + + // If we don't have a pre-set base, figure it out and swallow any prefix + if (__base == 0) { + auto __c = *__first; + // __c == '0' + if (__c == __atoms[0]) { + ++__first; + if (__first == __last) { + __err |= ios_base::eofbit; + __v = 0; + return __first; + } + // __c2 == 'x' || __c2 == 'X' + if (auto __c2 = *__first; __c2 == __atoms[22] || __c2 == __atoms[23]) { + __base = 16; + ++__first; + } else { + __base = 8; + __parsed_num = true; // We only swallowed '0', so we've started to parse a number + } + } else { + __base = 10; + } + + // If the base has been specified explicitly, try to swallow the appropriate prefix. We only need to do something + // special for hex, since decimal has no prefix and octal's prefix is '0', which doesn't change the value that + // we'll parse if we don't swallow it. + } else if (__base == 16) { + // Try to swallow '0x' + + // *__first == '0' + if (*__first == __atoms[0]) { + ++__first; + if (__first == __last) { + __err |= ios_base::eofbit; + __v = 0; + return __first; + } + // __c == 'x' || __c == 'X' + if (auto __c = *__first; __c == __atoms[22] || __c == __atoms[23]) + ++__first; + else + __parsed_num = true; // We only swallowed '0', so we've started to parse a number } - if (this->__stage2_int_loop( - *__b, - __base, - __a, - __a_end, - __dc, - __thousands_sep, - __grouping, - __g, - __g_end, - const_cast<char_type*>(__atoms))) - break; } - if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz) - *__g_end++ = __dc; - // Stage 3 - __v = std::__num_get_signed_integral<_Signed>(__a, __a_end, __err, __base); - // Digit grouping checked - __check_grouping(__grouping, __g, __g_end, __err); - // EOF checked - if (__b == __e) - __err |= ios_base::eofbit; - return __b; - } - template <class _Unsigned> - _LIBCPP_HIDE_FROM_ABI iter_type - __do_get_unsigned(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, _Unsigned& __v) const { - // Stage 1 - int __base = this->__get_base(__iob); - // Stage 2 - char_type __thousands_sep; - const int __atoms_size = __num_get_base::__int_chr_cnt; - char_type __atoms1[__atoms_size]; - const char_type* __atoms = this->__do_widen(__iob, __atoms1); - string __grouping = this->__stage2_int_prep(__iob, __thousands_sep); - string __buf; - __buf.resize(__buf.capacity()); - char* __a = &__buf[0]; - char* __a_end = __a; - unsigned __g[__num_get_base::__num_get_buf_sz]; - unsigned* __g_end = __g; - unsigned __dc = 0; - for (; __b != __e; ++__b) { - if (__a_end == __a + __buf.size()) { - size_t __tmp = __buf.size(); - __buf.resize(2 * __buf.size()); - __buf.resize(__buf.capacity()); - __a = &__buf[0]; - __a_end = __a + __tmp; + // Calculate the actual number + _Unsigned __val = 0; + bool __overflowed = false; + for (; __first != __last; ++__first) { + auto __c = *__first; + if (!__grouping.empty() && __c == __thousands_sep) { + if (__g_end - __g < this->__num_get_buf_sz) { + *__g_end++ = __dc; + __dc = 0; + } + continue; } - if (this->__stage2_int_loop( - *__b, - __base, - __a, - __a_end, - __dc, - __thousands_sep, - __grouping, - __g, - __g_end, - const_cast<char_type*>(__atoms))) + auto __offset = this->__atoms_offset(__atoms, __c); + if (__offset >= 22) // Not a valid integer character + break; + + if (__base == 16 && __offset >= 16) + __offset -= 6; + if (__offset >= __base) break; + // __val = (__val * __base) + __offset + __overflowed |= __builtin_mul_overflow(__val, __base, std::addressof(__val)) || + __builtin_add_overflow(__val, __offset, std::addressof(__val)); + __parsed_num = true; + ++__dc; + } + + if (!__parsed_num) { + __err |= ios_base::failbit; + __v = 0; + } else if (__overflowed) { + __err |= ios_base::failbit; + __v = is_signed<_MaybeSigned>::value && __negate + ? numeric_limits<_MaybeSigned>::min() + : numeric_limits<_MaybeSigned>::max(); + } else if (!__negate) { + if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max())) { + __err |= ios_base::failbit; + __v = numeric_limits<_MaybeSigned>::max(); + } else { + __v = __val; + } + } else if (is_signed<_MaybeSigned>::value) { + if (__val > static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) { + __err |= ios_base::failbit; + __v = numeric_limits<_MaybeSigned>::min(); + } else if (__val == static_cast<_Unsigned>(numeric_limits<_MaybeSigned>::max()) + 1) { + __v = numeric_limits<_MaybeSigned>::min(); + } else { + __v = -__val; + } + } else { + __v = -__val; } + if (__grouping.size() != 0 && __g_end - __g < __num_get_base::__num_get_buf_sz) *__g_end++ = __dc; - // Stage 3 - __v = std::__num_get_unsigned_integral<_Unsigned>(__a, __a_end, __err, __base); + // Digit grouping checked __check_grouping(__grouping, __g, __g_end, __err); // EOF checked - if (__b == __e) + if (__first == __last) __err |= ios_base::eofbit; - return __b; + return __first; } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, bool& __v) const; virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long& __v) const { - return this->__do_get_signed(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, long long& __v) const { - return this->__do_get_signed(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned short& __v) const { - return this->__do_get_unsigned(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned int& __v) const { - return this->__do_get_unsigned(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long& __v) const { - return this->__do_get_unsigned(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, unsigned long long& __v) const { - return this->__do_get_unsigned(__b, __e, __iob, __err, __v); + return this->__do_get_integral(__b, __e, __iob, __err, __v); } virtual iter_type do_get(iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, float& __v) const { @@ -652,40 +621,13 @@ _InputIterator num_get<_CharT, _InputIterator>::do_get( template <class _CharT, class _InputIterator> _InputIterator num_get<_CharT, _InputIterator>::do_get( iter_type __b, iter_type __e, ios_base& __iob, ios_base::iostate& __err, void*& __v) const { - // Stage 1 - int __base = 16; - // Stage 2 - char_type __atoms[__num_get_base::__int_chr_cnt]; - char_type __thousands_sep = char_type(); - string __grouping; - std::use_facet<ctype<_CharT> >(__iob.getloc()) - .widen(__num_get_base::__src, __num_get_base::__src + __num_get_base::__int_chr_cnt, __atoms); - string __buf; - __buf.resize(__buf.capacity()); - char* __a = &__buf[0]; - char* __a_end = __a; - unsigned __g[__num_get_base::__num_get_buf_sz]; - unsigned* __g_end = __g; - unsigned __dc = 0; - for (; __b != __e; ++__b) { - if (__a_end == __a + __buf.size()) { - size_t __tmp = __buf.size(); - __buf.resize(2 * __buf.size()); - __buf.resize(__buf.capacity()); - __a = &__buf[0]; - __a_end = __a + __tmp; - } - if (this->__stage2_int_loop(*__b, __base, __a, __a_end, __dc, __thousands_sep, __grouping, __g, __g_end, __atoms)) - break; - } - // Stage 3 - __buf.resize(__a_end - __a); - if (__locale::__sscanf(__buf.c_str(), _LIBCPP_GET_C_LOCALE, "%p", &__v) != 1) - __err = ios_base::failbit; - // EOF checked - if (__b == __e) - __err |= ios_base::eofbit; - return __b; + auto __flags = __iob.flags(); + __iob.flags((__flags & ~ios_base::basefield & ~ios_base::uppercase) | ios_base::hex); + uintptr_t __ptr; + auto __res = __do_get_integral(__b, __e, __iob, __err, __ptr); + __iob.flags(__flags); + __v = reinterpret_cast<void*>(__ptr); + return __res; } extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS num_get<char>; @@ -748,6 +690,13 @@ void __num_put<_CharT>::__widen_and_group_int( __op = __ob + (__np - __nb); } +_LIBCPP_HIDE_FROM_ABI inline bool __isdigit(char __c) { return __c >= '0' && __c <= '9'; } + +_LIBCPP_HIDE_FROM_ABI inline bool __isxdigit(char __c) { + auto __lower = __c | 0x20; + return std::__isdigit(__c) || (__lower >= 'a' && __lower <= 'f'); +} + template <class _CharT> void __num_put<_CharT>::__widen_and_group_float( char* __nb, char* __np, char* __ne, _CharT* __ob, _CharT*& __op, _CharT*& __oe, const locale& __loc) { @@ -763,11 +712,11 @@ void __num_put<_CharT>::__widen_and_group_float( *__oe++ = __ct.widen(*__nf++); *__oe++ = __ct.widen(*__nf++); for (__ns = __nf; __ns < __ne; ++__ns) - if (!__locale::__isxdigit(*__ns, _LIBCPP_GET_C_LOCALE)) + if (!std::__isxdigit(*__ns)) break; } else { for (__ns = __nf; __ns < __ne; ++__ns) - if (!__locale::__isdigit(*__ns, _LIBCPP_GET_C_LOCALE)) + if (!std::__isdigit(*__ns)) break; } if (__grouping.empty()) { @@ -885,9 +834,7 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob, char_ty const numpunct<char_type>& __np = std::use_facet<numpunct<char_type> >(__iob.getloc()); typedef typename numpunct<char_type>::string_type string_type; string_type __nm = __v ? __np.truename() : __np.falsename(); - for (typename string_type::iterator __i = __nm.begin(); __i != __nm.end(); ++__i, ++__s) - *__s = *__i; - return __s; + return std::copy(__nm.begin(), __nm.end(), __s); } template <class _CharT, class _OutputIterator> diff --git a/lib/libcxx/include/__locale_dir/pad_and_output.h b/lib/libcxx/include/__locale_dir/pad_and_output.h @@ -13,6 +13,8 @@ #if _LIBCPP_HAS_LOCALIZATION +# include <__algorithm/copy.h> +# include <__algorithm/fill_n.h> # include <ios> # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -30,12 +32,9 @@ _LIBCPP_HIDE_FROM_ABI _OutputIterator __pad_and_output( __ns -= __sz; else __ns = 0; - for (; __ob < __op; ++__ob, ++__s) - *__s = *__ob; - for (; __ns; --__ns, ++__s) - *__s = __fl; - for (; __ob < __oe; ++__ob, ++__s) - *__s = *__ob; + __s = std::copy(__ob, __op, __s); + __s = std::fill_n(__s, __ns, __fl); + __s = std::copy(__op, __oe, __s); __iob.width(0); return __s; } diff --git a/lib/libcxx/include/__locale_dir/support/bsd_like.h b/lib/libcxx/include/__locale_dir/support/bsd_like.h @@ -24,7 +24,6 @@ # include <wctype.h> #endif -/* zig patch: https://github.com/llvm/llvm-project/pull/143055 */ #if __has_include(<xlocale.h>) # include <xlocale.h> #endif @@ -80,22 +79,9 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __ return ::strtold_l(__nptr, __endptr, __loc); } -inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return ::strtoll_l(__nptr, __endptr, __base, __loc); -} - -inline _LIBCPP_HIDE_FROM_ABI unsigned long long -__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return ::strtoull_l(__nptr, __endptr, __base, __loc); -} - // // Character manipulation functions // -inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return ::isdigit_l(__c, __loc); } - -inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return ::isxdigit_l(__c, __loc); } - #if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return ::toupper_l(__c, __loc); } @@ -216,12 +202,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __ char** __s, __locale_t __loc, const char* __format, _Args&&... __args) { return ::asprintf_l(__s, __loc, __format, std::forward<_Args>(__args)...); // non-standard } - -template <class... _Args> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf( - const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) { - return ::sscanf_l(__s, __loc, __format, std::forward<_Args>(__args)...); -} _LIBCPP_DIAGNOSTIC_POP #undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT diff --git a/lib/libcxx/include/__locale_dir/support/fuchsia.h b/lib/libcxx/include/__locale_dir/support/fuchsia.h @@ -141,13 +141,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __ __locale_guard __current(__loc); return ::asprintf(__s, __format, std::forward<_Args>(__args)...); // non-standard } -template <class... _Args> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf( - const char* __s, __locale_t __loc, const char* __format, _Args&&... __args) { - __locale_guard __current(__loc); - return std::sscanf(__s, __format, std::forward<_Args>(__args)...); -} - _LIBCPP_DIAGNOSTIC_POP #undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT diff --git a/lib/libcxx/include/__locale_dir/support/linux.h b/lib/libcxx/include/__locale_dir/support/linux.h @@ -94,32 +94,9 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __ return ::strtold_l(__nptr, __endptr, __loc); } -inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { -#if !_LIBCPP_HAS_MUSL_LIBC - return ::strtoll_l(__nptr, __endptr, __base, __loc); -#else - (void)__loc; - return ::strtoll(__nptr, __endptr, __base); -#endif -} - -inline _LIBCPP_HIDE_FROM_ABI unsigned long long -__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { -#if !_LIBCPP_HAS_MUSL_LIBC - return ::strtoull_l(__nptr, __endptr, __base, __loc); -#else - (void)__loc; - return ::strtoull(__nptr, __endptr, __base); -#endif -} - // // Character manipulation functions // -inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return isdigit_l(__c, __loc); } - -inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return isxdigit_l(__c, __loc); } - #if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return toupper_l(__c, __loc); } @@ -261,20 +238,6 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf( va_end(__va); return __res; } - -#ifndef _LIBCPP_COMPILER_GCC // GCC complains that this can't be always_inline due to C-style varargs -_LIBCPP_HIDE_FROM_ABI -#endif -inline _LIBCPP_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf( - const char* __s, __locale_t __loc, const char* __format, ...) { - va_list __va; - va_start(__va, __format); - __locale_guard __current(__loc); - int __res = std::vsscanf(__s, __format, __va); - va_end(__va); - return __res; -} - } // namespace __locale _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__locale_dir/support/netbsd.h b/lib/libcxx/include/__locale_dir/support/netbsd.h @@ -6,8 +6,6 @@ // //===----------------------------------------------------------------------===// -/* zig patch: https://github.com/llvm/llvm-project/pull/143055 */ - #ifndef _LIBCPP___LOCALE_DIR_SUPPORT_NETBSD_H #define _LIBCPP___LOCALE_DIR_SUPPORT_NETBSD_H diff --git a/lib/libcxx/include/__locale_dir/support/newlib.h b/lib/libcxx/include/__locale_dir/support/newlib.h @@ -0,0 +1,243 @@ +//===-----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___LOCALE_DIR_SUPPORT_NEWLIB_H +#define _LIBCPP___LOCALE_DIR_SUPPORT_NEWLIB_H + +#include <__config> +#include <__cstddef/size_t.h> +#include <__std_mbstate_t.h> +#include <clocale> // std::lconv +#include <cstdio> +#include <cstdlib> +#include <ctype.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#if _LIBCPP_HAS_WIDE_CHARACTERS +# include <cwchar> +# include <wctype.h> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD +namespace __locale { + +struct __locale_guard { + _LIBCPP_HIDE_FROM_ABI __locale_guard(locale_t& __loc) : __old_loc_(::uselocale(__loc)) {} + + _LIBCPP_HIDE_FROM_ABI ~__locale_guard() { + if (__old_loc_) + ::uselocale(__old_loc_); + } + + locale_t __old_loc_; + + __locale_guard(__locale_guard const&) = delete; + __locale_guard& operator=(__locale_guard const&) = delete; +}; + +// +// Locale management +// +#define _LIBCPP_COLLATE_MASK LC_COLLATE_MASK +#define _LIBCPP_CTYPE_MASK LC_CTYPE_MASK +#define _LIBCPP_MONETARY_MASK LC_MONETARY_MASK +#define _LIBCPP_NUMERIC_MASK LC_NUMERIC_MASK +#define _LIBCPP_TIME_MASK LC_TIME_MASK +#define _LIBCPP_MESSAGES_MASK LC_MESSAGES_MASK +#define _LIBCPP_ALL_MASK LC_ALL_MASK +#define _LIBCPP_LC_ALL LC_ALL + +using __locale_t _LIBCPP_NODEBUG = ::locale_t; + +#if defined(_LIBCPP_BUILDING_LIBRARY) +using __lconv_t _LIBCPP_NODEBUG = std::lconv; + +inline _LIBCPP_HIDE_FROM_ABI __locale_t __newlocale(int __category_mask, const char* __locale, __locale_t __base) { + return ::newlocale(__category_mask, __locale, __base); +} + +inline _LIBCPP_HIDE_FROM_ABI void __freelocale(__locale_t __loc) { ::freelocale(__loc); } + +inline _LIBCPP_HIDE_FROM_ABI char* __setlocale(int __category, char const* __locale) { + return ::setlocale(__category, __locale); +} + +inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) { + __locale_guard __current(__loc); + return std::localeconv(); +} +#endif // _LIBCPP_BUILDING_LIBRARY + +// +// Strtonum functions +// +inline _LIBCPP_HIDE_FROM_ABI float __strtof(const char* __nptr, char** __endptr, __locale_t __loc) { + return ::strtof_l(__nptr, __endptr, __loc); +} + +inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr, __locale_t __loc) { + return ::strtod_l(__nptr, __endptr, __loc); +} + +inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __endptr, __locale_t __loc) { + return ::strtold_l(__nptr, __endptr, __loc); +} + +// +// Character manipulation functions +// +#if defined(_LIBCPP_BUILDING_LIBRARY) +inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return toupper_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __tolower(int __c, __locale_t __loc) { return tolower_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __strcoll(const char* __s1, const char* __s2, __locale_t __loc) { + return strcoll_l(__s1, __s2, __loc); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __strxfrm(char* __dest, const char* __src, size_t __n, __locale_t __loc) { + return strxfrm_l(__dest, __src, __n, __loc); +} + +# if _LIBCPP_HAS_WIDE_CHARACTERS +inline _LIBCPP_HIDE_FROM_ABI int __iswctype(wint_t __c, wctype_t __type, __locale_t __loc) { + return iswctype_l(__c, __type, __loc); +} + +inline _LIBCPP_HIDE_FROM_ABI int __iswspace(wint_t __c, __locale_t __loc) { return iswspace_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswprint(wint_t __c, __locale_t __loc) { return iswprint_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswcntrl(wint_t __c, __locale_t __loc) { return iswcntrl_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswupper(wint_t __c, __locale_t __loc) { return iswupper_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswlower(wint_t __c, __locale_t __loc) { return iswlower_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswalpha(wint_t __c, __locale_t __loc) { return iswalpha_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswblank(wint_t __c, __locale_t __loc) { return iswblank_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswdigit(wint_t __c, __locale_t __loc) { return iswdigit_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswpunct(wint_t __c, __locale_t __loc) { return iswpunct_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __iswxdigit(wint_t __c, __locale_t __loc) { return iswxdigit_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI wint_t __towupper(wint_t __c, __locale_t __loc) { return towupper_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI wint_t __towlower(wint_t __c, __locale_t __loc) { return towlower_l(__c, __loc); } + +inline _LIBCPP_HIDE_FROM_ABI int __wcscoll(const wchar_t* __ws1, const wchar_t* __ws2, __locale_t __loc) { + return wcscoll_l(__ws1, __ws2, __loc); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __wcsxfrm(wchar_t* __dest, const wchar_t* __src, size_t __n, __locale_t __loc) { + return wcsxfrm_l(__dest, __src, __n, __loc); +} +# endif // _LIBCPP_HAS_WIDE_CHARACTERS + +inline _LIBCPP_HIDE_FROM_ABI +size_t __strftime(char* __s, size_t __max, const char* __format, const struct tm* __tm, __locale_t __loc) { + return strftime_l(__s, __max, __format, __tm, __loc); +} + +// +// Other functions +// +inline _LIBCPP_HIDE_FROM_ABI decltype(MB_CUR_MAX) __mb_len_max(__locale_t __loc) { + __locale_guard __current(__loc); + return MB_CUR_MAX; +} + +# if _LIBCPP_HAS_WIDE_CHARACTERS +inline _LIBCPP_HIDE_FROM_ABI wint_t __btowc(int __c, __locale_t __loc) { + __locale_guard __current(__loc); + return std::btowc(__c); +} + +inline _LIBCPP_HIDE_FROM_ABI int __wctob(wint_t __c, __locale_t __loc) { + __locale_guard __current(__loc); + return std::wctob(__c); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__wcsnrtombs(char* __dest, const wchar_t** __src, size_t __nwc, size_t __len, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return ::wcsnrtombs(__dest, __src, __nwc, __len, __ps); // non-standard +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __wcrtomb(char* __s, wchar_t __wc, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return std::wcrtomb(__s, __wc, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__mbsnrtowcs(wchar_t* __dest, const char** __src, size_t __nms, size_t __len, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return ::mbsnrtowcs(__dest, __src, __nms, __len, __ps); // non-standard +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__mbrtowc(wchar_t* __pwc, const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return std::mbrtowc(__pwc, __s, __n, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI int __mbtowc(wchar_t* __pwc, const char* __pmb, size_t __max, __locale_t __loc) { + __locale_guard __current(__loc); + return std::mbtowc(__pwc, __pmb, __max); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t __mbrlen(const char* __s, size_t __n, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return std::mbrlen(__s, __n, __ps); +} + +inline _LIBCPP_HIDE_FROM_ABI size_t +__mbsrtowcs(wchar_t* __dest, const char** __src, size_t __len, mbstate_t* __ps, __locale_t __loc) { + __locale_guard __current(__loc); + return std::mbsrtowcs(__dest, __src, __len, __ps); +} +# endif // _LIBCPP_HAS_WIDE_CHARACTERS +#endif // _LIBCPP_BUILDING_LIBRARY + +#ifndef _LIBCPP_COMPILER_GCC // GCC complains that this can't be always_inline due to C-style varargs +_LIBCPP_HIDE_FROM_ABI +#endif +inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __snprintf( + char* __s, size_t __n, __locale_t __loc, const char* __format, ...) { + va_list __va; + va_start(__va, __format); + __locale_guard __current(__loc); + int __res = std::vsnprintf(__s, __n, __format, __va); + va_end(__va); + return __res; +} + +#ifndef _LIBCPP_COMPILER_GCC // GCC complains that this can't be always_inline due to C-style varargs +_LIBCPP_HIDE_FROM_ABI +#endif +inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf( + char** __s, __locale_t __loc, const char* __format, ...) { + va_list __va; + va_start(__va, __format); + __locale_guard __current(__loc); + int __res = ::vasprintf(__s, __format, __va); // non-standard + va_end(__va); + return __res; +} +} // namespace __locale +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___LOCALE_DIR_SUPPORT_NEWLIB_H diff --git a/lib/libcxx/include/__locale_dir/support/no_locale/characters.h b/lib/libcxx/include/__locale_dir/support/no_locale/characters.h @@ -29,10 +29,6 @@ namespace __locale { // // Character manipulation functions // -inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t) { return std::isdigit(__c); } - -inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t) { return std::isxdigit(__c); } - #if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t) { return std::toupper(__c); } diff --git a/lib/libcxx/include/__locale_dir/support/no_locale/strtonum.h b/lib/libcxx/include/__locale_dir/support/no_locale/strtonum.h @@ -34,15 +34,6 @@ inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __ return std::strtold(__nptr, __endptr); } -inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t) { - return std::strtoll(__nptr, __endptr, __base); -} - -inline _LIBCPP_HIDE_FROM_ABI unsigned long long -__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t) { - return std::strtoull(__nptr, __endptr, __base); -} - } // namespace __locale _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__locale_dir/support/windows.h b/lib/libcxx/include/__locale_dir/support/windows.h @@ -186,21 +186,9 @@ inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr return ::_strtod_l(__nptr, __endptr, __loc); } -inline _LIBCPP_HIDE_FROM_ABI long long __strtoll(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return ::_strtoi64_l(__nptr, __endptr, __base, __loc); -} -inline _LIBCPP_HIDE_FROM_ABI unsigned long long -__strtoull(const char* __nptr, char** __endptr, int __base, __locale_t __loc) { - return ::_strtoui64_l(__nptr, __endptr, __base, __loc); -} - // // Character manipulation functions // -inline _LIBCPP_HIDE_FROM_ABI int __isdigit(int __c, __locale_t __loc) { return _isdigit_l(__c, __loc); } - -inline _LIBCPP_HIDE_FROM_ABI int __isxdigit(int __c, __locale_t __loc) { return _isxdigit_l(__c, __loc); } - #if defined(_LIBCPP_BUILDING_LIBRARY) inline _LIBCPP_HIDE_FROM_ABI int __toupper(int __c, __locale_t __loc) { return ::_toupper_l(__c, __loc); } @@ -280,23 +268,6 @@ _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 4, 5) int __snpri _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(char** __ret, __locale_t __loc, const char* __format, ...); -_LIBCPP_DIAGNOSTIC_PUSH -_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wgcc-compat") -_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wformat-nonliteral") // GCC doesn't support [[gnu::format]] on variadic templates -#ifdef _LIBCPP_COMPILER_CLANG_BASED -# define _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(...) _LIBCPP_ATTRIBUTE_FORMAT(__VA_ARGS__) -#else -# define _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(...) /* nothing */ -#endif - -template <class... _Args> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT(__scanf__, 3, 4) int __sscanf( - const char* __dest, __locale_t __loc, const char* __format, _Args&&... __args) { - return ::_sscanf_l(__dest, __format, __loc, std::forward<_Args>(__args)...); -} -_LIBCPP_DIAGNOSTIC_POP -#undef _LIBCPP_VARIADIC_ATTRIBUTE_FORMAT - #if defined(_LIBCPP_BUILDING_LIBRARY) struct __locale_guard { _LIBCPP_HIDE_FROM_ABI __locale_guard(__locale_t __l) : __status(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)) { diff --git a/lib/libcxx/include/__locale_dir/time.h b/lib/libcxx/include/__locale_dir/time.h @@ -601,17 +601,13 @@ private: template <> \ _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::__time_get_storage(const string&); \ template <> \ - _LIBCPP_EXPORTED_FROM_ABI void __time_get_storage<_CharT>::init(const ctype<_CharT>&); \ + void __time_get_storage<_CharT>::init(const ctype<_CharT>&); \ template <> \ - _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::string_type __time_get_storage<_CharT>::__analyze( \ - char, const ctype<_CharT>&); \ + __time_get_storage<_CharT>::string_type __time_get_storage<_CharT>::__analyze(char, const ctype<_CharT>&); \ extern template _LIBCPP_EXPORTED_FROM_ABI time_base::dateorder __time_get_storage<_CharT>::__do_date_order() \ const; \ extern template _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::__time_get_storage(const char*); \ - extern template _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::__time_get_storage(const string&); \ - extern template _LIBCPP_EXPORTED_FROM_ABI void __time_get_storage<_CharT>::init(const ctype<_CharT>&); \ - extern template _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::string_type \ - __time_get_storage<_CharT>::__analyze(char, const ctype<_CharT>&); + extern template _LIBCPP_EXPORTED_FROM_ABI __time_get_storage<_CharT>::__time_get_storage(const string&); _LIBCPP_TIME_GET_STORAGE_EXPLICIT_INSTANTIATION(char) # if _LIBCPP_HAS_WIDE_CHARACTERS diff --git a/lib/libcxx/include/__math/hypot.h b/lib/libcxx/include/__math/hypot.h @@ -53,7 +53,7 @@ inline _LIBCPP_HIDE_FROM_ABI __promote_t<_A1, _A2> hypot(_A1 __x, _A2 __y) _NOEX // Computes the three-dimensional hypotenuse: `std::hypot(x,y,z)`. // The naive implementation might over-/underflow which is why this implementation is more involved: // If the square of an argument might run into issues, we scale the arguments appropriately. -// See https://github.com/llvm/llvm-project/issues/92782 for a detailed discussion and summary. +// See https://llvm.org/PR92782 for a detailed discussion and summary. template <class _Real> _LIBCPP_HIDE_FROM_ABI _Real __hypot(_Real __x, _Real __y, _Real __z) { // Factors needed to determine if over-/underflow might happen diff --git a/lib/libcxx/include/__math/logarithms.h b/lib/libcxx/include/__math/logarithms.h @@ -58,7 +58,7 @@ inline _LIBCPP_HIDE_FROM_ABI double log10(_A1 __x) _NOEXCEPT { inline _LIBCPP_HIDE_FROM_ABI int ilogb(float __x) _NOEXCEPT { return __builtin_ilogbf(__x); } template <class = int> -_LIBCPP_HIDE_FROM_ABI double ilogb(double __x) _NOEXCEPT { +_LIBCPP_HIDE_FROM_ABI int ilogb(double __x) _NOEXCEPT { return __builtin_ilogb(__x); } diff --git a/lib/libcxx/include/__math/traits.h b/lib/libcxx/include/__math/traits.h @@ -25,33 +25,26 @@ namespace __math { // signbit -// TODO(LLVM 22): Remove conditional once support for Clang 19 is dropped. -#if defined(_LIBCPP_COMPILER_GCC) || __has_constexpr_builtin(__builtin_signbit) -# define _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_CONSTEXPR_SINCE_CXX23 -#else -# define _LIBCPP_SIGNBIT_CONSTEXPR -#endif - // The universal C runtime (UCRT) in the WinSDK provides floating point overloads // for std::signbit(). By defining our overloads as templates, we can work around // this issue as templates are less preferred than non-template functions. template <class = void> -[[__nodiscard__]] inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(float __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(float __x) _NOEXCEPT { return __builtin_signbit(__x); } template <class = void> -[[__nodiscard__]] inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(double __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(double __x) _NOEXCEPT { return __builtin_signbit(__x); } template <class = void> -[[__nodiscard__]] inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(long double __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(long double __x) _NOEXCEPT { return __builtin_signbit(__x); } template <class _A1, __enable_if_t<is_integral<_A1>::value, int> = 0> -[[__nodiscard__]] inline _LIBCPP_SIGNBIT_CONSTEXPR _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool signbit(_A1 __x) _NOEXCEPT { return __x < 0; } @@ -189,6 +182,82 @@ template <class _A1, class _A2, __enable_if_t<is_arithmetic<_A1>::value && is_ar return __builtin_isunordered((type)__x, (type)__y); } +// MS UCRT incorrectly defines some functions in a way not working with integer types. Until C++20, this was worked +// around by -fdelayed-template-parsing. Since C++20, we can use standard feature "requires" instead. + +// TODO: Remove the workaround once UCRT fixes these functions. Note that this doesn't seem planned as of 2025-07 per +// https://developercommunity.visualstudio.com/t/10294165. + +#if defined(_LIBCPP_MSVCRT) && _LIBCPP_STD_VER >= 20 +namespace __ucrt { +template <class _A1> + requires is_integral_v<_A1> +[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isfinite(_A1) noexcept { + return true; +} + +template <class _A1> + requires is_integral_v<_A1> +[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isinf(_A1) noexcept { + return false; +} + +template <class _A1> + requires is_integral_v<_A1> +[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnan(_A1) noexcept { + return false; +} + +template <class _A1> + requires is_integral_v<_A1> +[[nodiscard]] inline _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI bool isnormal(_A1 __x) noexcept { + return __x != 0; +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isgreater(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_isgreater((type)__x, (type)__y); +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isgreaterequal(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_isgreaterequal((type)__x, (type)__y); +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isless(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_isless((type)__x, (type)__y); +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool islessequal(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_islessequal((type)__x, (type)__y); +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool islessgreater(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_islessgreater((type)__x, (type)__y); +} + +template <class _A1, class _A2> + requires is_arithmetic_v<_A1> && is_arithmetic_v<_A2> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool isunordered(_A1 __x, _A2 __y) noexcept { + using type = __promote_t<_A1, _A2>; + return __builtin_isunordered((type)__x, (type)__y); +} +} // namespace __ucrt +#endif + } // namespace __math _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__mdspan/extents.h b/lib/libcxx/include/__mdspan/extents.h @@ -25,6 +25,7 @@ #include <__type_traits/integer_traits.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_signed.h> #include <__type_traits/make_unsigned.h> #include <__utility/integer_sequence.h> #include <__utility/unreachable.h> @@ -298,11 +299,13 @@ private: public: // [mdspan.extents.obs], observers of multidimensional index space - _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; } - _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return __rank_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return __rank_dynamic_; } - _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __vals_.__value(__r); } - _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + return __vals_.__value(__r); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { return _Values::__static_value(__r); } diff --git a/lib/libcxx/include/__mdspan/layout_stride.h b/lib/libcxx/include/__mdspan/layout_stride.h @@ -272,11 +272,10 @@ public: return [&]<size_t... _Pos>(index_sequence<_Pos...>) { if ((__extents_.extent(_Pos) * ... * 1) == 0) return static_cast<index_type>(0); - else - return static_cast<index_type>( - static_cast<index_type>(1) + - (((__extents_.extent(_Pos) - static_cast<index_type>(1)) * __strides_[_Pos]) + ... + - static_cast<index_type>(0))); + + return static_cast<index_type>( + static_cast<index_type>(1) + (((__extents_.extent(_Pos) - static_cast<index_type>(1)) * __strides_[_Pos]) + + ... + static_cast<index_type>(0))); }(make_index_sequence<__rank_>()); } } diff --git a/lib/libcxx/include/__mdspan/mdspan.h b/lib/libcxx/include/__mdspan/mdspan.h @@ -87,16 +87,17 @@ public: using data_handle_type = typename accessor_type::data_handle_type; using reference = typename accessor_type::reference; - _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); } - _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } - _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { + return extents_type::rank_dynamic(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept { return extents_type::static_extent(__r); } - _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept { return __map_.extents().extent(__r); - }; + } -public: //-------------------------------------------------------------------------------- // [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor @@ -185,7 +186,7 @@ public: requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) && (sizeof...(_OtherIndexTypes) == rank())) - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const { // Note the standard layouts would also check this, but user provided ones may not, so we // check the precondition here _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...), @@ -196,7 +197,8 @@ public: template <class _OtherIndexType> requires(is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&>) - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](const array< _OtherIndexType, rank()>& __indices) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference + operator[](const array< _OtherIndexType, rank()>& __indices) const { return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { return __map_(__indices[_Idxs]...); }(make_index_sequence<rank()>())); @@ -205,13 +207,13 @@ public: template <class _OtherIndexType> requires(is_convertible_v<const _OtherIndexType&, index_type> && is_nothrow_constructible_v<index_type, const _OtherIndexType&>) - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const { return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) { return __map_(__indices[_Idxs]...); }(make_index_sequence<rank()>())); } - _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { // Could leave this as only checked in debug mode: semantically size() is never // guaranteed to be related to any accessible range _LIBCPP_ASSERT_UNCATEGORIZED( @@ -237,24 +239,28 @@ public: swap(__x.__acc_, __y.__acc_); } - _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __map_.extents(); }; - _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; }; - _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; }; - _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; }; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { + return __map_.extents(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; } // per LWG-4021 "mdspan::is_always_meow() should be noexcept" - _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return mapping_type::is_always_unique(); }; - _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { + return mapping_type::is_always_unique(); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return mapping_type::is_always_exhaustive(); - }; - _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return mapping_type::is_always_strided(); - }; + } - _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); }; - _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); }; - _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); }; - _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); }; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); } private: _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{}; diff --git a/lib/libcxx/include/__memory/addressof.h b/lib/libcxx/include/__memory/addressof.h @@ -19,7 +19,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> -inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* addressof(_Tp& __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* +addressof(_Tp& __x) _NOEXCEPT { return __builtin_addressof(__x); } @@ -27,24 +28,25 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_NO_CFI _LIBCPP_HIDE_FROM_ABI _Tp* a // Objective-C++ Automatic Reference Counting uses qualified pointers // that require special addressof() signatures. template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI __strong _Tp* addressof(__strong _Tp& __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __strong _Tp* addressof(__strong _Tp& __x) _NOEXCEPT { return &__x; } # if __has_feature(objc_arc_weak) template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI __weak _Tp* addressof(__weak _Tp& __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __weak _Tp* addressof(__weak _Tp& __x) _NOEXCEPT { return &__x; } # endif template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI __autoreleasing _Tp* addressof(__autoreleasing _Tp& __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __autoreleasing _Tp* addressof(__autoreleasing _Tp& __x) _NOEXCEPT { return &__x; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI __unsafe_unretained _Tp* addressof(__unsafe_unretained _Tp& __x) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __unsafe_unretained _Tp* +addressof(__unsafe_unretained _Tp& __x) _NOEXCEPT { return &__x; } #endif diff --git a/lib/libcxx/include/__memory/align.h b/lib/libcxx/include/__memory/align.h @@ -11,6 +11,7 @@ #include <__config> #include <__cstddef/size_t.h> +#include <cstdint> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -18,7 +19,23 @@ _LIBCPP_BEGIN_NAMESPACE_STD -_LIBCPP_EXPORTED_FROM_ABI void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space); +inline namespace __align_inline { +_LIBCPP_HIDE_FROM_ABI inline void* align(size_t __align, size_t __sz, void*& __ptr, size_t& __space) { + void* __r = nullptr; + if (__sz <= __space) { + char* __p1 = static_cast<char*>(__ptr); + char* __p2 = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(__p1 + (__align - 1)) & -__align); + size_t __d = static_cast<size_t>(__p2 - __p1); + if (__d <= __space - __sz) { + __r = __p2; + __ptr = __r; + __space -= __d; + } + } + return __r; +} + +} // namespace __align_inline _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__memory/allocate_at_least.h b/lib/libcxx/include/__memory/allocate_at_least.h @@ -19,26 +19,31 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template <class _Pointer, class _SizeT = size_t> +struct __allocation_result { + _Pointer ptr; + _SizeT count; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __allocation_result(_Pointer __ptr, _SizeT __count) + : ptr(__ptr), count(__count) {} +}; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__allocation_result); + #if _LIBCPP_STD_VER >= 23 template <class _Alloc> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto __allocate_at_least(_Alloc& __alloc, size_t __n) { - return std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); + auto __res = std::allocator_traits<_Alloc>::allocate_at_least(__alloc, __n); + return __allocation_result{__res.ptr, __res.count}; } #else -template <class _Pointer> -struct __allocation_result { - _Pointer ptr; - size_t count; -}; - -template <class _Alloc> +template <class _Alloc, class _Traits = allocator_traits<_Alloc> > [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI -_LIBCPP_CONSTEXPR __allocation_result<typename allocator_traits<_Alloc>::pointer> +_LIBCPP_CONSTEXPR __allocation_result<typename _Traits::pointer, typename _Traits::size_type> __allocate_at_least(_Alloc& __alloc, size_t __n) { - return {__alloc.allocate(__n), __n}; + return __allocation_result<typename _Traits::pointer, typename _Traits::size_type>(__alloc.allocate(__n), __n); } #endif // _LIBCPP_STD_VER >= 23 diff --git a/lib/libcxx/include/__memory/allocator.h b/lib/libcxx/include/__memory/allocator.h @@ -14,7 +14,6 @@ #include <__cstddef/ptrdiff_t.h> #include <__cstddef/size_t.h> #include <__memory/addressof.h> -#include <__memory/allocate_at_least.h> #include <__memory/allocator_traits.h> #include <__new/allocate.h> #include <__new/exceptions.h> @@ -51,33 +50,21 @@ public: }; #endif // _LIBCPP_STD_VER <= 17 -// This class provides a non-trivial default constructor to the class that derives from it -// if the condition is satisfied. -// -// The second template parameter exists to allow giving a unique type to __non_trivial_if, -// which makes it possible to avoid breaking the ABI when making this a base class of an -// existing class. Without that, imagine we have classes D1 and D2, both of which used to -// have no base classes, but which now derive from __non_trivial_if. The layout of a class -// that inherits from both D1 and D2 will change because the two __non_trivial_if base -// classes are not allowed to share the same address. -// -// By making those __non_trivial_if base classes unique, we work around this problem and -// it is safe to start deriving from __non_trivial_if in existing classes. -template <bool _Cond, class _Unique> -struct __non_trivial_if {}; +template <bool, class _Unique> +struct __non_trivially_default_constructible_if {}; template <class _Unique> -struct __non_trivial_if<true, _Unique> { - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __non_trivial_if() _NOEXCEPT {} +struct __non_trivially_default_constructible_if<true, _Unique> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __non_trivially_default_constructible_if() {} }; -// allocator -// -// Note: For ABI compatibility between C++20 and previous standards, we make -// allocator<void> trivial in C++20. - template <class _Tp> -class allocator : private __non_trivial_if<!is_void<_Tp>::value, allocator<_Tp> > { +class allocator +// TODO(LLVM 24): Remove the opt-out +#ifdef _LIBCPP_DEPRECATED_ABI_NON_TRIVIAL_ALLOCATOR + : __non_trivially_default_constructible_if<!is_void<_Tp>::value, allocator<_Tp> > +#endif +{ static_assert(!is_const<_Tp>::value, "std::allocator does not support const types"); static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); @@ -133,10 +120,11 @@ public: typedef allocator<_Up> other; }; - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI pointer address(reference __x) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI pointer address(reference __x) const _NOEXCEPT { return std::addressof(__x); } - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer address(const_reference __x) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI const_pointer + address(const_reference __x) const _NOEXCEPT { return std::addressof(__x); } @@ -144,7 +132,7 @@ public: return allocate(__n); } - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return size_type(~0) / sizeof(_Tp); } diff --git a/lib/libcxx/include/__memory/allocator_traits.h b/lib/libcxx/include/__memory/allocator_traits.h @@ -314,23 +314,25 @@ struct allocator_traits { } template <class _Ap = _Alloc, __enable_if_t<__has_max_size_v<const _Ap>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type& __a) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type + max_size(const allocator_type& __a) _NOEXCEPT { _LIBCPP_SUPPRESS_DEPRECATED_PUSH return __a.max_size(); _LIBCPP_SUPPRESS_DEPRECATED_POP } template <class _Ap = _Alloc, __enable_if_t<!__has_max_size_v<const _Ap>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type max_size(const allocator_type&) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static size_type + max_size(const allocator_type&) _NOEXCEPT { return numeric_limits<size_type>::max() / sizeof(value_type); } template <class _Ap = _Alloc, __enable_if_t<__has_select_on_container_copy_construction_v<const _Ap>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type select_on_container_copy_construction(const allocator_type& __a) { return __a.select_on_container_copy_construction(); } template <class _Ap = _Alloc, __enable_if_t<!__has_select_on_container_copy_construction_v<const _Ap>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static allocator_type select_on_container_copy_construction(const allocator_type& __a) { return __a; } diff --git a/lib/libcxx/include/__memory/compressed_pair.h b/lib/libcxx/include/__memory/compressed_pair.h @@ -28,8 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD // understand how it works). // // ================================================================================================================== // -// The first member is aligned to the alignment of the second member to force padding in front of the compressed pair -// in case there are members before it. +// On GCC, the first member is aligned to the alignment of the second member to force padding in front of the compressed +// pair in case there are members before it. // // For example: // (assuming x86-64 linux) @@ -52,7 +52,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD // // Furthermore, that alignment must be the same as what was used in the old __compressed_pair layout, so we must // handle reference types specially since alignof(T&) == alignof(T). -// See https://github.com/llvm/llvm-project/issues/118559. +// See https://llvm.org/PR118559. +// +// On Clang, this is unnecessary, since we use anonymous structs instead, which automatically handle the alignment +// correctly. #ifndef _LIBCPP_ABI_NO_COMPRESSED_PAIR_PADDING @@ -64,7 +67,7 @@ inline const size_t __compressed_pair_alignment<_Tp&> = _LIBCPP_ALIGNOF(void*); template <class _ToPad> inline const bool __is_reference_or_unpadded_object = - (is_empty<_ToPad>::value && !__libcpp_is_final<_ToPad>::value) || sizeof(_ToPad) == __datasizeof_v<_ToPad>; + (is_empty<_ToPad>::value && !__is_final_v<_ToPad>) || sizeof(_ToPad) == __datasizeof_v<_ToPad>; template <class _Tp> inline const bool __is_reference_or_unpadded_object<_Tp&> = true; @@ -80,6 +83,10 @@ class __compressed_pair_padding { template <class _ToPad> class __compressed_pair_padding<_ToPad, true> {}; +# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) \ + _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1; \ + _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding_, __LINE__, _) + // TODO: Fix the ABI for GCC as well once https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121637 is fixed # ifdef _LIBCPP_COMPILER_GCC # define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ @@ -100,8 +107,7 @@ class __compressed_pair_padding<_ToPad, true> {}; # else # define _LIBCPP_COMPRESSED_PAIR(T1, Initializer1, T2, Initializer2) \ struct { \ - _LIBCPP_NO_UNIQUE_ADDRESS \ - __attribute__((__aligned__(::std::__compressed_pair_alignment<T2>))) T1 Initializer1; \ + _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1; \ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \ _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _); \ @@ -109,9 +115,7 @@ class __compressed_pair_padding<_ToPad, true> {}; # define _LIBCPP_COMPRESSED_TRIPLE(T1, Initializer1, T2, Initializer2, T3, Initializer3) \ struct { \ - _LIBCPP_NO_UNIQUE_ADDRESS \ - __attribute__((__aligned__(::std::__compressed_pair_alignment<T2>), \ - __aligned__(::std::__compressed_pair_alignment<T3>))) T1 Initializer1; \ + _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1; \ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T1> _LIBCPP_CONCAT3(__padding1_, __LINE__, _); \ _LIBCPP_NO_UNIQUE_ADDRESS T2 Initializer2; \ _LIBCPP_NO_UNIQUE_ADDRESS ::std::__compressed_pair_padding<T2> _LIBCPP_CONCAT3(__padding2_, __LINE__, _); \ @@ -121,6 +125,8 @@ class __compressed_pair_padding<_ToPad, true> {}; # endif #else +# define _LIBCPP_COMPRESSED_ELEMENT(T1, Initializer1) _LIBCPP_NO_UNIQUE_ADDRESS T1 Initializer1 + # define _LIBCPP_COMPRESSED_PAIR(T1, Name1, T2, Name2) \ _LIBCPP_NO_UNIQUE_ADDRESS T1 Name1; \ _LIBCPP_NO_UNIQUE_ADDRESS T2 Name2 diff --git a/lib/libcxx/include/__memory/construct_at.h b/lib/libcxx/include/__memory/construct_at.h @@ -14,7 +14,6 @@ #include <__config> #include <__memory/addressof.h> #include <__new/placement_new_delete.h> -#include <__type_traits/enable_if.h> #include <__type_traits/is_array.h> #include <__utility/declval.h> #include <__utility/forward.h> @@ -33,7 +32,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)...); } @@ -55,35 +54,25 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* __construct_at(_Tp* __l // The internal functions are available regardless of the language version (with the exception of the `__destroy_at` // taking an array). -template <class _Tp, __enable_if_t<!is_array<_Tp>::value, int> = 0> +template <class _Tp> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy_at(_Tp* __loc) { _LIBCPP_ASSERT_NON_NULL(__loc != nullptr, "null pointer given to destroy_at"); - __loc->~_Tp(); -} - #if _LIBCPP_STD_VER >= 20 -template <class _Tp, __enable_if_t<is_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr void __destroy_at(_Tp* __loc) { - _LIBCPP_ASSERT_NON_NULL(__loc != nullptr, "null pointer given to destroy_at"); - for (auto&& __val : *__loc) - std::__destroy_at(std::addressof(__val)); -} + if constexpr (is_array_v<_Tp>) { + for (auto&& __val : *__loc) + std::__destroy_at(std::addressof(__val)); + } else #endif - -#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) { - std::__destroy_at(__loc); + { + __loc->~_Tp(); + } } -# 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) { +#if _LIBCPP_STD_VER >= 17 +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy_at(_Tp* _LIBCPP_DIAGNOSE_NULLPTR __loc) { std::__destroy_at(__loc); } -# endif - #endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__memory/inout_ptr.h b/lib/libcxx/include/__memory/inout_ptr.h @@ -96,7 +96,7 @@ private: }; template <class _Pointer = void, class _Smart, class... _Args> -_LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto inout_ptr(_Smart& __s, _Args&&... __args) { using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>; return std::inout_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...); } diff --git a/lib/libcxx/include/__memory/is_sufficiently_aligned.h b/lib/libcxx/include/__memory/is_sufficiently_aligned.h @@ -23,7 +23,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 26 template <size_t _Alignment, class _Tp> -_LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_sufficiently_aligned(_Tp* __ptr) { return reinterpret_cast<uintptr_t>(__ptr) % _Alignment == 0; } diff --git a/lib/libcxx/include/__memory/out_ptr.h b/lib/libcxx/include/__memory/out_ptr.h @@ -88,7 +88,7 @@ private: }; template <class _Pointer = void, class _Smart, class... _Args> -_LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto out_ptr(_Smart& __s, _Args&&... __args) { using _Ptr = conditional_t<is_void_v<_Pointer>, __pointer_of_t<_Smart>, _Pointer>; return std::out_ptr_t<_Smart, _Ptr, _Args&&...>(__s, std::forward<_Args>(__args)...); } diff --git a/lib/libcxx/include/__memory/pointer_traits.h b/lib/libcxx/include/__memory/pointer_traits.h @@ -255,7 +255,7 @@ concept __resettable_smart_pointer_with_args = requires(_Smart __s, _Pointer __p // This function ensures safe conversions between fancy pointers at compile-time, where we avoid casts from/to // `__void_pointer` by obtaining the underlying raw pointer from the fancy pointer using `std::to_address`, // then dereferencing it to retrieve the pointed-to object, and finally constructing the target fancy pointer -// to that object using the `std::pointer_traits<>::pinter_to` function. +// to that object using the `std::pointer_traits<>::pointer_to` function. template <class _PtrTo, class _PtrFrom> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI _PtrTo __static_fancy_pointer_cast(const _PtrFrom& __p) { using __ptr_traits = pointer_traits<_PtrTo>; diff --git a/lib/libcxx/include/__memory/raw_storage_iterator.h b/lib/libcxx/include/__memory/raw_storage_iterator.h @@ -28,15 +28,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_RAW_STORAGE_ITERATOR) -_LIBCPP_SUPPRESS_DEPRECATED_PUSH template <class _OutputIterator, class _Tp> class _LIBCPP_DEPRECATED_IN_CXX17 raw_storage_iterator -# if _LIBCPP_STD_VER <= 14 || !defined(_LIBCPP_ABI_NO_ITERATOR_BASES) - : public iterator<output_iterator_tag, void, void, void, void> -# endif -{ - _LIBCPP_SUPPRESS_DEPRECATED_POP - + : public __iterator_base<raw_storage_iterator<_OutputIterator, _Tp>, output_iterator_tag, void, void, void, void> { private: _OutputIterator __x_; @@ -52,7 +46,7 @@ public: typedef void reference; _LIBCPP_HIDE_FROM_ABI explicit raw_storage_iterator(_OutputIterator __x) : __x_(__x) {} - _LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator*() { return *this; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator*() { return *this; } _LIBCPP_HIDE_FROM_ABI raw_storage_iterator& operator=(const _Tp& __element) { ::new ((void*)std::addressof(*__x_)) _Tp(__element); return *this; @@ -73,7 +67,7 @@ public: return __t; } # if _LIBCPP_STD_VER >= 14 - _LIBCPP_HIDE_FROM_ABI _OutputIterator base() const { return __x_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _OutputIterator base() const { return __x_; } # endif }; diff --git a/lib/libcxx/include/__memory/shared_count.h b/lib/libcxx/include/__memory/shared_count.h @@ -22,37 +22,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD // NOTE: Relaxed and acq/rel atomics (for increment and decrement respectively) // should be sufficient for thread safety. // See https://llvm.org/PR22803 -#if (defined(__clang__) && __has_builtin(__atomic_add_fetch) && defined(__ATOMIC_RELAXED) && \ - defined(__ATOMIC_ACQ_REL)) || \ - defined(_LIBCPP_COMPILER_GCC) -# define _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT 1 -#else -# define _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT 0 -#endif - -template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_relaxed_load(_ValueType const* __value) { -#if _LIBCPP_HAS_THREADS && defined(__ATOMIC_RELAXED) && \ - (__has_builtin(__atomic_load_n) || defined(_LIBCPP_COMPILER_GCC)) - return __atomic_load_n(__value, __ATOMIC_RELAXED); -#else - return *__value; -#endif -} - -template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const* __value) { -#if _LIBCPP_HAS_THREADS && defined(__ATOMIC_ACQUIRE) && \ - (__has_builtin(__atomic_load_n) || defined(_LIBCPP_COMPILER_GCC)) - return __atomic_load_n(__value, __ATOMIC_ACQUIRE); -#else - return *__value; -#endif -} template <class _Tp> inline _LIBCPP_HIDE_FROM_ABI _Tp __libcpp_atomic_refcount_increment(_Tp& __t) _NOEXCEPT { -#if _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT && _LIBCPP_HAS_THREADS +#if _LIBCPP_HAS_THREADS return __atomic_add_fetch(std::addressof(__t), 1, __ATOMIC_RELAXED); #else return __t += 1; @@ -61,7 +34,7 @@ inline _LIBCPP_HIDE_FROM_ABI _Tp __libcpp_atomic_refcount_increment(_Tp& __t) _N template <class _Tp> inline _LIBCPP_HIDE_FROM_ABI _Tp __libcpp_atomic_refcount_decrement(_Tp& __t) _NOEXCEPT { -#if _LIBCPP_HAS_BUILTIN_ATOMIC_SUPPORT && _LIBCPP_HAS_THREADS +#if _LIBCPP_HAS_THREADS return __atomic_add_fetch(std::addressof(__t), -1, __ATOMIC_ACQ_REL); #else return __t -= 1; @@ -95,7 +68,13 @@ public: return false; } #endif - _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { return __libcpp_relaxed_load(&__shared_owners_) + 1; } + _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { +#if _LIBCPP_HAS_THREADS + return __atomic_load_n(&__shared_owners_, __ATOMIC_RELAXED) + 1; +#else + return __shared_owners_ + 1; +#endif + } }; class _LIBCPP_EXPORTED_FROM_ABI __shared_weak_count : private __shared_count { diff --git a/lib/libcxx/include/__memory/shared_ptr.h b/lib/libcxx/include/__memory/shared_ptr.h @@ -41,19 +41,18 @@ #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_array.h> -#include <__type_traits/is_bounded_array.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_function.h> #include <__type_traits/is_reference.h> #include <__type_traits/is_same.h> -#include <__type_traits/is_unbounded_array.h> #include <__type_traits/nat.h> #include <__type_traits/negation.h> #include <__type_traits/remove_cv.h> #include <__type_traits/remove_extent.h> #include <__type_traits/remove_reference.h> #include <__utility/declval.h> +#include <__utility/exception_guard.h> #include <__utility/forward.h> #include <__utility/move.h> #include <__utility/swap.h> @@ -78,7 +77,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_weak_ptr(const bad_weak_ptr&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_weak_ptr& operator=(const bad_weak_ptr&) _NOEXCEPT = default; ~bad_weak_ptr() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; [[__noreturn__]] inline _LIBCPP_HIDE_FROM_ABI void __throw_bad_weak_ptr() { @@ -316,10 +315,8 @@ public: #endif // A shared_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require - // any bookkeeping, so it's always trivially relocatable. It is also replaceable because assignment just rebinds the - // shared_ptr to manage a different object. + // any bookkeeping, so it's always trivially relocatable. using __trivially_relocatable _LIBCPP_NODEBUG = shared_ptr; - using __replaceable _LIBCPP_NODEBUG = shared_ptr; private: element_type* __ptr_; @@ -352,23 +349,16 @@ public: template <class _Yp, class _Dp, __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr(_Yp* __p, _Dp __d) : __ptr_(__p) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; - typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT> _CntrlBlk; + auto __guard = std::__make_exception_guard([&] { __d(__p); }); + typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; + typedef __shared_ptr_pointer<_Yp*, _Dp, _AllocT> _CntrlBlk; #ifndef _LIBCPP_CXX03_LANG - __cntrl_ = new _CntrlBlk(__p, std::move(__d), _AllocT()); + __cntrl_ = new _CntrlBlk(__p, std::move(__d), _AllocT()); #else __cntrl_ = new _CntrlBlk(__p, __d, _AllocT()); #endif // not _LIBCPP_CXX03_LANG - __enable_weak_this(__p, __p); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __d(__p); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + __enable_weak_this(__p, __p); + __guard.__complete(); } template <class _Yp, @@ -376,28 +366,21 @@ public: class _Alloc, __enable_if_t<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, _Tp>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr(_Yp* __p, _Dp __d, _Alloc __a) : __ptr_(__p) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - typedef __shared_ptr_pointer<_Yp*, _Dp, _Alloc> _CntrlBlk; - typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; - typedef __allocator_destructor<_A2> _D2; - _A2 __a2(__a); - unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new ((void*)std::addressof(*__hold2.get())) + auto __guard = std::__make_exception_guard([&] { __d(__p); }); + typedef __shared_ptr_pointer<_Yp*, _Dp, _Alloc> _CntrlBlk; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; + typedef __allocator_destructor<_A2> _D2; + _A2 __a2(__a); + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); + ::new ((void*)std::addressof(*__hold2.get())) #ifndef _LIBCPP_CXX03_LANG - _CntrlBlk(__p, std::move(__d), __a); + _CntrlBlk(__p, std::move(__d), __a); #else _CntrlBlk(__p, __d, __a); #endif // not _LIBCPP_CXX03_LANG - __cntrl_ = std::addressof(*__hold2.release()); - __enable_weak_this(__p, __p); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __d(__p); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + __cntrl_ = std::addressof(*__hold2.release()); + __enable_weak_this(__p, __p); + __guard.__complete(); } template <class _Dp> @@ -406,22 +389,15 @@ public: _Dp __d, __enable_if_t<__shared_ptr_nullptr_deleter_ctor_reqs<_Dp>::value, __nullptr_sfinae_tag> = __nullptr_sfinae_tag()) : __ptr_(nullptr) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - typedef typename __shared_ptr_default_allocator<_Tp>::type _AllocT; - typedef __shared_ptr_pointer<nullptr_t, _Dp, _AllocT> _CntrlBlk; + auto __guard = std::__make_exception_guard([&] { __d(__p); }); + typedef typename __shared_ptr_default_allocator<_Tp>::type _AllocT; + typedef __shared_ptr_pointer<nullptr_t, _Dp, _AllocT> _CntrlBlk; #ifndef _LIBCPP_CXX03_LANG - __cntrl_ = new _CntrlBlk(__p, std::move(__d), _AllocT()); + __cntrl_ = new _CntrlBlk(__p, std::move(__d), _AllocT()); #else __cntrl_ = new _CntrlBlk(__p, __d, _AllocT()); #endif // not _LIBCPP_CXX03_LANG -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __d(__p); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); } template <class _Dp, class _Alloc> @@ -431,27 +407,20 @@ public: _Alloc __a, __enable_if_t<__shared_ptr_nullptr_deleter_ctor_reqs<_Dp>::value, __nullptr_sfinae_tag> = __nullptr_sfinae_tag()) : __ptr_(nullptr) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - typedef __shared_ptr_pointer<nullptr_t, _Dp, _Alloc> _CntrlBlk; - typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; - typedef __allocator_destructor<_A2> _D2; - _A2 __a2(__a); - unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new ((void*)std::addressof(*__hold2.get())) + auto __guard = std::__make_exception_guard([&] { __d(__p); }); + typedef __shared_ptr_pointer<nullptr_t, _Dp, _Alloc> _CntrlBlk; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; + typedef __allocator_destructor<_A2> _D2; + _A2 __a2(__a); + unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); + ::new ((void*)std::addressof(*__hold2.get())) #ifndef _LIBCPP_CXX03_LANG - _CntrlBlk(__p, std::move(__d), __a); + _CntrlBlk(__p, std::move(__d), __a); #else _CntrlBlk(__p, __d, __a); #endif // not _LIBCPP_CXX03_LANG - __cntrl_ = std::addressof(*__hold2.release()); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __d(__p); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + __cntrl_ = std::addressof(*__hold2.release()); + __guard.__complete(); } template <class _Yp> @@ -514,45 +483,16 @@ public: template <class _Yp, class _Dp, - __enable_if_t<!is_lvalue_reference<_Dp>::value && __compatible_with<_Yp, _Tp>::value && + __enable_if_t<__compatible_with<_Yp, _Tp>::value && is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI shared_ptr(unique_ptr<_Yp, _Dp>&& __r) : __ptr_(__r.get()) { -#if _LIBCPP_STD_VER >= 14 - if (__ptr_ == nullptr) - __cntrl_ = nullptr; - else -#endif - { - typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; - typedef __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer, _Dp, _AllocT> _CntrlBlk; - __cntrl_ = new _CntrlBlk(__r.get(), std::move(__r.get_deleter()), _AllocT()); - __enable_weak_this(__r.get(), __r.get()); - } - __r.release(); - } + using _AllocT = typename __shared_ptr_default_allocator<_Yp>::type; + using _Deleter = _If<is_lvalue_reference<_Dp>::value, reference_wrapper<__libcpp_remove_reference_t<_Dp> >, _Dp>; + using _CntrlBlk = __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer, _Deleter, _AllocT>; - template <class _Yp, - class _Dp, - class = void, - __enable_if_t<is_lvalue_reference<_Dp>::value && __compatible_with<_Yp, _Tp>::value && - is_convertible<typename unique_ptr<_Yp, _Dp>::pointer, element_type*>::value, - int> = 0> - _LIBCPP_HIDE_FROM_ABI shared_ptr(unique_ptr<_Yp, _Dp>&& __r) : __ptr_(__r.get()) { -#if _LIBCPP_STD_VER >= 14 - if (__ptr_ == nullptr) - __cntrl_ = nullptr; - else -#endif - { - typedef typename __shared_ptr_default_allocator<_Yp>::type _AllocT; - typedef __shared_ptr_pointer<typename unique_ptr<_Yp, _Dp>::pointer, - reference_wrapper<__libcpp_remove_reference_t<_Dp> >, - _AllocT> - _CntrlBlk; - __cntrl_ = new _CntrlBlk(__r.get(), std::ref(__r.get_deleter()), _AllocT()); - __enable_weak_this(__r.get(), __r.get()); - } + __cntrl_ = __ptr_ ? new _CntrlBlk(__r.get(), std::forward<_Dp>(__r.get_deleter()), _AllocT()) : nullptr; + __enable_weak_this(__r.get(), __r.get()); __r.release(); } @@ -628,37 +568,43 @@ public: shared_ptr(__p, __d, __a).swap(*this); } - _LIBCPP_HIDE_FROM_ABI element_type* get() const _NOEXCEPT { return __ptr_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI element_type* get() const _NOEXCEPT { return __ptr_; } - _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator*() const _NOEXCEPT { return *__ptr_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator*() const _NOEXCEPT { + return *__ptr_; + } _LIBCPP_HIDE_FROM_ABI element_type* operator->() const _NOEXCEPT { static_assert(!is_array<_Tp>::value, "std::shared_ptr<T>::operator-> is only valid when T is not an array type."); return __ptr_; } - _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { return __cntrl_ ? __cntrl_->use_count() : 0; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { + return __cntrl_ ? __cntrl_->use_count() : 0; + } #if _LIBCPP_STD_VER < 20 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_SHARED_PTR_UNIQUE) - _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI bool unique() const _NOEXCEPT { return use_count() == 1; } + [[__nodiscard__]] _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI bool unique() const _NOEXCEPT { + return use_count() == 1; + } #endif _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return get() != nullptr; } template <class _Up> - _LIBCPP_HIDE_FROM_ABI bool owner_before(shared_ptr<_Up> const& __p) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_before(shared_ptr<_Up> const& __p) const _NOEXCEPT { return __cntrl_ < __p.__cntrl_; } template <class _Up> - _LIBCPP_HIDE_FROM_ABI bool owner_before(weak_ptr<_Up> const& __p) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_before(weak_ptr<_Up> const& __p) const _NOEXCEPT { return __cntrl_ < __p.__cntrl_; } _LIBCPP_HIDE_FROM_ABI bool __owner_equivalent(const shared_ptr& __p) const { return __cntrl_ == __p.__cntrl_; } #if _LIBCPP_STD_VER >= 17 - _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator[](ptrdiff_t __i) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __add_lvalue_reference_t<element_type> operator[](ptrdiff_t __i) const { static_assert(is_array<_Tp>::value, "std::shared_ptr<T>::operator[] is only valid when T is an array type."); return __ptr_[__i]; } @@ -729,7 +675,7 @@ shared_ptr(unique_ptr<_Tp, _Dp>) -> shared_ptr<_Tp>; // std::allocate_shared and std::make_shared // template <class _Tp, class _Alloc, class... _Args, __enable_if_t<!is_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&&... __args) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&&... __args) { using _ControlBlock = __shared_ptr_emplace<_Tp, _Alloc>; using _ControlBlockAllocator = typename __allocator_traits_rebind<_Alloc, _ControlBlock>::type; __allocation_guard<_ControlBlockAllocator> __guard(__a, 1); @@ -740,21 +686,21 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&& } template <class _Tp, class... _Args, __enable_if_t<!is_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&&... __args) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&&... __args) { return std::allocate_shared<_Tp>(allocator<__remove_cv_t<_Tp> >(), std::forward<_Args>(__args)...); } #if _LIBCPP_STD_VER >= 20 template <class _Tp, class _Alloc, __enable_if_t<!is_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a) { using _ForOverwriteAllocator = __allocator_traits_rebind_t<_Alloc, __for_overwrite_tag>; _ForOverwriteAllocator __alloc(__a); return std::allocate_shared<_Tp>(__alloc); } template <class _Tp, __enable_if_t<!is_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() { return std::allocate_shared_for_overwrite<_Tp>(allocator<__remove_cv_t<_Tp>>()); } @@ -946,67 +892,69 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Array> __allocate_shared_bounded_array(const _ // bounded array variants template <class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a) { return std::__allocate_shared_bounded_array<_Tp>(__a); } template <class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +allocate_shared(const _Alloc& __a, const remove_extent_t<_Tp>& __u) { return std::__allocate_shared_bounded_array<_Tp>(__a, __u); } template <class _Tp, class _Alloc, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a) { using _ForOverwriteAllocator = __allocator_traits_rebind_t<_Alloc, __for_overwrite_tag>; _ForOverwriteAllocator __alloc(__a); return std::__allocate_shared_bounded_array<_Tp>(__alloc); } template <class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared() { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared() { return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>()); } template <class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(const remove_extent_t<_Tp>& __u) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(const remove_extent_t<_Tp>& __u) { return std::__allocate_shared_bounded_array<_Tp>(allocator<_Tp>(), __u); } template <class _Tp, __enable_if_t<is_bounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() { return std::__allocate_shared_bounded_array<_Tp>(allocator<__for_overwrite_tag>()); } // unbounded array variants template <class _Tp, class _Alloc, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n) { return std::__allocate_shared_unbounded_array<_Tp>(__a, __n); } template <class _Tp, class _Alloc, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +allocate_shared(const _Alloc& __a, size_t __n, const remove_extent_t<_Tp>& __u) { return std::__allocate_shared_unbounded_array<_Tp>(__a, __n, __u); } template <class _Tp, class _Alloc, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a, size_t __n) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc& __a, size_t __n) { using _ForOverwriteAllocator = __allocator_traits_rebind_t<_Alloc, __for_overwrite_tag>; _ForOverwriteAllocator __alloc(__a); return std::__allocate_shared_unbounded_array<_Tp>(__alloc, __n); } template <class _Tp, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(size_t __n) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(size_t __n) { return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n); } template <class _Tp, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(size_t __n, const remove_extent_t<_Tp>& __u) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(size_t __n, const remove_extent_t<_Tp>& __u) { return std::__allocate_shared_unbounded_array<_Tp>(allocator<_Tp>(), __n, __u); } template <class _Tp, __enable_if_t<is_unbounded_array<_Tp>::value, int> = 0> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite(size_t __n) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite(size_t __n) { return std::__allocate_shared_unbounded_array<_Tp>(allocator<__for_overwrite_tag>(), __n); } @@ -1135,7 +1083,8 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(shared_ptr<_Tp>& __x, shared_ptr<_Tp>& __ } template <class _Tp, class _Up> -inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> static_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +static_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { return shared_ptr<_Tp>(__r, static_cast< typename shared_ptr<_Tp>::element_type*>(__r.get())); } @@ -1143,13 +1092,14 @@ inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> static_pointer_cast(const shared_pt // We don't backport because it is an evolutionary change. #if _LIBCPP_STD_VER >= 20 template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> static_pointer_cast(shared_ptr<_Up>&& __r) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> static_pointer_cast(shared_ptr<_Up>&& __r) noexcept { return shared_ptr<_Tp>(std::move(__r), static_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); } #endif template <class _Tp, class _Up> -inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { +[[__nodiscard__]] inline + _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { typedef typename shared_ptr<_Tp>::element_type _ET; _ET* __p = dynamic_cast<_ET*>(__r.get()); return __p ? shared_ptr<_Tp>(__r, __p) : shared_ptr<_Tp>(); @@ -1159,14 +1109,14 @@ inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(const shared_p // We don't backport because it is an evolutionary change. #if _LIBCPP_STD_VER >= 20 template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> dynamic_pointer_cast(shared_ptr<_Up>&& __r) noexcept { auto* __p = dynamic_cast<typename shared_ptr<_Tp>::element_type*>(__r.get()); return __p ? shared_ptr<_Tp>(std::move(__r), __p) : shared_ptr<_Tp>(); } #endif template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { typedef typename shared_ptr<_Tp>::element_type _RTp; return shared_ptr<_Tp>(__r, const_cast<_RTp*>(__r.get())); } @@ -1175,13 +1125,13 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(const shared_ptr<_Up>& // We don't backport because it is an evolutionary change. #if _LIBCPP_STD_VER >= 20 template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(shared_ptr<_Up>&& __r) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> const_pointer_cast(shared_ptr<_Up>&& __r) noexcept { return shared_ptr<_Tp>(std::move(__r), const_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); } #endif template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(const shared_ptr<_Up>& __r) _NOEXCEPT { return shared_ptr<_Tp>(__r, reinterpret_cast< typename shared_ptr<_Tp>::element_type*>(__r.get())); } @@ -1189,7 +1139,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(const shared_ptr< // We don't backport because it is an evolutionary change. #if _LIBCPP_STD_VER >= 20 template <class _Tp, class _Up> -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(shared_ptr<_Up>&& __r) noexcept { return shared_ptr<_Tp>(std::move(__r), reinterpret_cast<typename shared_ptr<_Tp>::element_type*>(__r.get())); } #endif @@ -1197,7 +1147,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> reinterpret_pointer_cast(shared_ptr<_Up>&& #if _LIBCPP_HAS_RTTI template <class _Dp, class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _Dp* get_deleter(const shared_ptr<_Tp>& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _Dp* get_deleter(const shared_ptr<_Tp>& __p) _NOEXCEPT { return __p.template __get_deleter<_Dp>(); } @@ -1213,9 +1163,8 @@ public: #endif // A weak_ptr contains only two raw pointers which point to the heap and move constructing already doesn't require - // any bookkeeping, so it's always trivially relocatable. It's also replaceable for the same reason. + // any bookkeeping, so it's always trivially relocatable. using __trivially_relocatable _LIBCPP_NODEBUG = weak_ptr; - using __replaceable _LIBCPP_NODEBUG = weak_ptr; private: element_type* __ptr_; @@ -1253,15 +1202,19 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(weak_ptr& __r) _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI void reset() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { return __cntrl_ ? __cntrl_->use_count() : 0; } - _LIBCPP_HIDE_FROM_ABI bool expired() const _NOEXCEPT { return __cntrl_ == nullptr || __cntrl_->use_count() == 0; } - _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> lock() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI long use_count() const _NOEXCEPT { + return __cntrl_ ? __cntrl_->use_count() : 0; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool expired() const _NOEXCEPT { + return __cntrl_ == nullptr || __cntrl_->use_count() == 0; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> lock() const _NOEXCEPT; template <class _Up> - _LIBCPP_HIDE_FROM_ABI bool owner_before(const shared_ptr<_Up>& __r) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_before(const shared_ptr<_Up>& __r) const _NOEXCEPT { return __cntrl_ < __r.__cntrl_; } template <class _Up> - _LIBCPP_HIDE_FROM_ABI bool owner_before(const weak_ptr<_Up>& __r) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool owner_before(const weak_ptr<_Up>& __r) const _NOEXCEPT { return __cntrl_ < __r.__cntrl_; } @@ -1445,13 +1398,15 @@ protected: _LIBCPP_HIDE_FROM_ABI ~enable_shared_from_this() {} public: - _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> shared_from_this() { return shared_ptr<_Tp>(__weak_this_); } - _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp const> shared_from_this() const { return shared_ptr<const _Tp>(__weak_this_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> shared_from_this() { return shared_ptr<_Tp>(__weak_this_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp const> shared_from_this() const { + return shared_ptr<const _Tp>(__weak_this_); + } #if _LIBCPP_STD_VER >= 17 - _LIBCPP_HIDE_FROM_ABI weak_ptr<_Tp> weak_from_this() _NOEXCEPT { return __weak_this_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI weak_ptr<_Tp> weak_from_this() _NOEXCEPT { return __weak_this_; } - _LIBCPP_HIDE_FROM_ABI weak_ptr<const _Tp> weak_from_this() const _NOEXCEPT { return __weak_this_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI weak_ptr<const _Tp> weak_from_this() const _NOEXCEPT { return __weak_this_; } #endif // _LIBCPP_STD_VER >= 17 template <class _Up> @@ -1468,7 +1423,7 @@ struct hash<shared_ptr<_Tp> > { _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type; #endif - _LIBCPP_HIDE_FROM_ABI size_t operator()(const shared_ptr<_Tp>& __ptr) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const shared_ptr<_Tp>& __ptr) const _NOEXCEPT { return hash<typename shared_ptr<_Tp>::element_type*>()(__ptr.get()); } }; diff --git a/lib/libcxx/include/__memory/temp_value.h b/lib/libcxx/include/__memory/temp_value.h @@ -12,7 +12,6 @@ #include <__config> #include <__memory/addressof.h> #include <__memory/allocator_traits.h> -#include <__type_traits/aligned_storage.h> #include <__utility/forward.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -26,7 +25,7 @@ struct __temp_value { typedef allocator_traits<_Alloc> _Traits; #ifdef _LIBCPP_CXX03_LANG - typename aligned_storage<sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)>::type __v; + _ALIGNAS_TYPE(_Tp) char __v[sizeof(_Tp)]; #else union { _Tp __v; diff --git a/lib/libcxx/include/__memory/uninitialized_algorithms.h b/lib/libcxx/include/__memory/uninitialized_algorithms.h @@ -32,7 +32,6 @@ #include <__type_traits/is_trivially_assignable.h> #include <__type_traits/is_trivially_constructible.h> #include <__type_traits/is_trivially_relocatable.h> -#include <__type_traits/is_unbounded_array.h> #include <__type_traits/remove_const.h> #include <__type_traits/remove_extent.h> #include <__utility/exception_guard.h> @@ -61,17 +60,10 @@ template <class _ValueType, class _InputIterator, class _Sentinel1, class _Forwa inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy( _InputIterator __ifirst, _Sentinel1 __ilast, _ForwardIterator __ofirst, _EndPredicate __stop_copying) { _ForwardIterator __idx = __ofirst; -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif - for (; __ifirst != __ilast && !__stop_copying(__idx); ++__ifirst, (void)++__idx) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__ofirst, __idx); - throw; - } -#endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__ofirst, __idx); }); + for (; __ifirst != __ilast && !__stop_copying(__idx); ++__ifirst, (void)++__idx) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst); + __guard.__complete(); return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx)); } @@ -91,17 +83,10 @@ template <class _ValueType, class _InputIterator, class _Size, class _ForwardIte inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_copying) { _ForwardIterator __idx = __ofirst; -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif - for (; __n > 0 && !__stop_copying(__idx); ++__ifirst, (void)++__idx, (void)--__n) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__ofirst, __idx); - throw; - } -#endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__ofirst, __idx); }); + for (; __n > 0 && !__stop_copying(__idx); ++__ifirst, (void)++__idx, (void)--__n) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst); + __guard.__complete(); return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx)); } @@ -121,17 +106,10 @@ template <class _ValueType, class _ForwardIterator, class _Sentinel, class _Tp> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) { _ForwardIterator __idx = __first; -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif - for (; __idx != __last; ++__idx) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -#endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __idx != __last; ++__idx) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x); + __guard.__complete(); return __idx; } @@ -149,17 +127,10 @@ template <class _ValueType, class _ForwardIterator, class _Size, class _Tp> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { _ForwardIterator __idx = __first; -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif - for (; __n > 0; ++__idx, (void)--__n) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -#endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __n > 0; ++__idx, (void)--__n) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x); + __guard.__complete(); return __idx; } @@ -178,18 +149,11 @@ uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { template <class _ValueType, class _ForwardIterator, class _Sentinel> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) { - auto __idx = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __idx != __last; ++__idx) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType; -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -# endif + auto __idx = __first; + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __idx != __last; ++__idx) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType; + __guard.__complete(); return __idx; } @@ -205,17 +169,10 @@ inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterat template <class _ValueType, class _ForwardIterator, class _Size> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) { auto __idx = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __n > 0; ++__idx, (void)--__n) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType; -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -# endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __n > 0; ++__idx, (void)--__n) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType; + __guard.__complete(); return __idx; } @@ -231,18 +188,11 @@ inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_default_construct_n( template <class _ValueType, class _ForwardIterator, class _Sentinel> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) { - auto __idx = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __idx != __last; ++__idx) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -# endif + auto __idx = __first; + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __idx != __last; ++__idx) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(); + __guard.__complete(); return __idx; } @@ -258,17 +208,10 @@ inline _LIBCPP_HIDE_FROM_ABI void uninitialized_value_construct(_ForwardIterator template <class _ValueType, class _ForwardIterator, class _Size> inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) { auto __idx = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __n > 0; ++__idx, (void)--__n) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__first, __idx); - throw; - } -# endif + auto __guard = std::__make_exception_guard([&] { std::__destroy(__first, __idx); }); + for (; __n > 0; ++__idx, (void)--__n) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(); + __guard.__complete(); return __idx; } @@ -293,19 +236,12 @@ inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitiali _ForwardIterator __ofirst, _EndPredicate __stop_moving, _IterMove __iter_move) { - auto __idx = __ofirst; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __ifirst != __ilast && !__stop_moving(__idx); ++__idx, (void)++__ifirst) { - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst)); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__ofirst, __idx); - throw; + auto __idx = __ofirst; + auto __guard = std::__make_exception_guard([&] { std::__destroy(__ofirst, __idx); }); + for (; __ifirst != __ilast && !__stop_moving(__idx); ++__idx, (void)++__ifirst) { + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst)); } -# endif + __guard.__complete(); return {std::move(__ifirst), std::move(__idx)}; } @@ -331,18 +267,11 @@ template <class _ValueType, class _IterMove> inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move_n( _InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_moving, _IterMove __iter_move) { - auto __idx = __ofirst; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - for (; __n > 0 && !__stop_moving(__idx); ++__idx, (void)++__ifirst, --__n) - ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst)); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - std::__destroy(__ofirst, __idx); - throw; - } -# endif + auto __idx = __ofirst; + auto __guard = std::__make_exception_guard([&] { std::__destroy(__ofirst, __idx); }); + for (; __n > 0 && !__stop_moving(__idx); ++__idx, (void)++__ifirst, --__n) + ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst)); + __guard.__complete(); return {std::move(__ifirst), std::move(__idx)}; } diff --git a/lib/libcxx/include/__memory/unique_ptr.h b/lib/libcxx/include/__memory/unique_ptr.h @@ -32,18 +32,15 @@ #include <__type_traits/integral_constant.h> #include <__type_traits/is_array.h> #include <__type_traits/is_assignable.h> -#include <__type_traits/is_bounded_array.h> #include <__type_traits/is_constant_evaluated.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_convertible.h> #include <__type_traits/is_function.h> #include <__type_traits/is_pointer.h> #include <__type_traits/is_reference.h> -#include <__type_traits/is_replaceable.h> #include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_relocatable.h> -#include <__type_traits/is_unbounded_array.h> #include <__type_traits/is_void.h> #include <__type_traits/remove_extent.h> #include <__type_traits/type_identity.h> @@ -145,8 +142,6 @@ public: __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<deleter_type>::value, unique_ptr, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<pointer> && __is_replaceable_v<deleter_type>, unique_ptr, void>; private: _LIBCPP_COMPRESSED_PAIR(pointer, __ptr_, deleter_type, __deleter_); @@ -263,14 +258,17 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 __add_lvalue_reference_t<_Tp> operator*() const _NOEXCEPT_(_NOEXCEPT_(*std::declval<pointer>())) { return *__ptr_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer operator->() const _NOEXCEPT { return __ptr_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { return __deleter_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& get_deleter() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 pointer get() const _NOEXCEPT { return __ptr_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 deleter_type& get_deleter() _NOEXCEPT { + return __deleter_; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 const deleter_type& + get_deleter() const _NOEXCEPT { return __deleter_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit operator bool() const _NOEXCEPT { @@ -413,8 +411,6 @@ public: __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<deleter_type>::value, unique_ptr, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<pointer> && __is_replaceable_v<deleter_type>, unique_ptr, void>; private: template <class _Up, class _OtherDeleter> @@ -755,12 +751,13 @@ operator<=>(const unique_ptr<_T1, _D1>& __x, nullptr_t) { #if _LIBCPP_STD_VER >= 14 template <class _Tp, class... _Args, enable_if_t<!is_array<_Tp>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique(_Args&&... __args) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique(_Args&&... __args) { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } template <class _Tp, enable_if_t<__is_unbounded_array_v<_Tp>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique(size_t __n) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique(size_t __n) { typedef __remove_extent_t<_Tp> _Up; return unique_ptr<_Tp>(__private_constructor_tag(), new _Up[__n](), __n); } @@ -773,12 +770,13 @@ void make_unique(_Args&&...) = delete; #if _LIBCPP_STD_VER >= 20 template <class _Tp, enable_if_t<!is_array_v<_Tp>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique_for_overwrite() { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique_for_overwrite() { return unique_ptr<_Tp>(new _Tp); } template <class _Tp, enable_if_t<is_unbounded_array_v<_Tp>, int> = 0> -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> make_unique_for_overwrite(size_t __n) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr<_Tp> +make_unique_for_overwrite(size_t __n) { return unique_ptr<_Tp>(__private_constructor_tag(), new __remove_extent_t<_Tp>[__n], __n); } @@ -802,7 +800,7 @@ struct hash<__enable_hash_helper< unique_ptr<_Tp, _Dp>, typename unique_ptr<_Tp, _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type; #endif - _LIBCPP_HIDE_FROM_ABI size_t operator()(const unique_ptr<_Tp, _Dp>& __ptr) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const unique_ptr<_Tp, _Dp>& __ptr) const { typedef typename unique_ptr<_Tp, _Dp>::pointer pointer; return hash<pointer>()(__ptr.get()); } diff --git a/lib/libcxx/include/__memory/uses_allocator_construction.h b/lib/libcxx/include/__memory/uses_allocator_construction.h @@ -17,6 +17,7 @@ #include <__type_traits/remove_cv.h> #include <__utility/declval.h> #include <__utility/pair.h> +#include <__utility/piecewise_construct.h> #include <tuple> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/lib/libcxx/include/__memory_resource/memory_resource.h b/lib/libcxx/include/__memory_resource/memory_resource.h @@ -42,7 +42,9 @@ public: do_deallocate(__p, __bytes, __align); } - _LIBCPP_HIDE_FROM_ABI bool is_equal(const memory_resource& __other) const noexcept { return do_is_equal(__other); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool is_equal(const memory_resource& __other) const noexcept { + return do_is_equal(__other); + } private: virtual void* do_allocate(size_t, size_t) = 0; @@ -68,7 +70,7 @@ operator!=(const memory_resource& __lhs, const memory_resource& __rhs) noexcept // [mem.res.global] -[[__gnu__::__returns_nonnull__]] _LIBCPP_AVAILABILITY_PMR _LIBCPP_EXPORTED_FROM_ABI memory_resource* +[[nodiscard, __gnu__::__returns_nonnull__]] _LIBCPP_AVAILABILITY_PMR _LIBCPP_EXPORTED_FROM_ABI memory_resource* get_default_resource() noexcept; [[__gnu__::__returns_nonnull__]] _LIBCPP_AVAILABILITY_PMR _LIBCPP_EXPORTED_FROM_ABI memory_resource* diff --git a/lib/libcxx/include/__memory_resource/monotonic_buffer_resource.h b/lib/libcxx/include/__memory_resource/monotonic_buffer_resource.h @@ -93,7 +93,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { return __res_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { return __res_; } protected: void* do_allocate(size_t __bytes, size_t __alignment) override; // key function diff --git a/lib/libcxx/include/__memory_resource/polymorphic_allocator.h b/lib/libcxx/include/__memory_resource/polymorphic_allocator.h @@ -18,6 +18,7 @@ #include <__new/exceptions.h> #include <__new/placement_new_delete.h> #include <__utility/exception_guard.h> +#include <__utility/piecewise_construct.h> #include <limits> #include <tuple> @@ -50,7 +51,9 @@ public: _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {} - _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) {} + _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* _LIBCPP_DIAGNOSE_NULLPTR __r) noexcept : __res_(__r) { + _LIBCPP_ASSERT_NON_NULL(__r, "Attempted to pass a nullptr resource to polymorphic_alloator"); + } _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(const polymorphic_allocator&) = default; @@ -133,10 +136,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> @@ -170,11 +173,13 @@ public: __p->~_Tp(); } - _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI polymorphic_allocator select_on_container_copy_construction() const noexcept { return polymorphic_allocator(); } - _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { return __res_; } + [[nodiscard, __gnu__::__returns_nonnull__]] _LIBCPP_HIDE_FROM_ABI memory_resource* resource() const noexcept { + return __res_; + } _LIBCPP_HIDE_FROM_ABI friend bool operator==(const polymorphic_allocator& __lhs, const polymorphic_allocator& __rhs) noexcept { @@ -192,20 +197,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/lib/libcxx/include/__memory_resource/pool_options.h b/lib/libcxx/include/__memory_resource/pool_options.h @@ -24,7 +24,7 @@ namespace pmr { // [mem.res.pool.options] -struct _LIBCPP_EXPORTED_FROM_ABI pool_options { +struct pool_options { size_t max_blocks_per_chunk = 0; size_t largest_required_pool_block = 0; }; diff --git a/lib/libcxx/include/__memory_resource/synchronized_pool_resource.h b/lib/libcxx/include/__memory_resource/synchronized_pool_resource.h @@ -56,9 +56,11 @@ public: __unsync_.release(); } - _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { return __unsync_.upstream_resource(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { + return __unsync_.upstream_resource(); + } - _LIBCPP_HIDE_FROM_ABI pool_options options() const { return __unsync_.options(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI pool_options options() const { return __unsync_.options(); } protected: _LIBCPP_HIDE_FROM_ABI_VIRTUAL void* do_allocate(size_t __bytes, size_t __align) override { diff --git a/lib/libcxx/include/__memory_resource/unsynchronized_pool_resource.h b/lib/libcxx/include/__memory_resource/unsynchronized_pool_resource.h @@ -76,7 +76,7 @@ public: void release(); - _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { return __res_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI memory_resource* upstream_resource() const { return __res_; } [[__gnu__::__pure__]] pool_options options() const; diff --git a/lib/libcxx/include/__mutex/mutex.h b/lib/libcxx/include/__mutex/mutex.h @@ -37,11 +37,11 @@ public: # endif _LIBCPP_ACQUIRE_CAPABILITY() void lock(); - _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_TRY_ACQUIRE_CAPABILITY(true) bool try_lock() _NOEXCEPT; _LIBCPP_RELEASE_CAPABILITY void unlock() _NOEXCEPT; typedef __libcpp_mutex_t* native_handle_type; - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } }; static_assert(is_nothrow_default_constructible<mutex>::value, "the default constructor for std::mutex must be nothrow"); diff --git a/lib/libcxx/include/__mutex/once_flag.h b/lib/libcxx/include/__mutex/once_flag.h @@ -10,12 +10,11 @@ #define _LIBCPP___MUTEX_ONCE_FLAG_H #include <__config> -#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 <__type_traits/invoke.h> #include <__utility/forward.h> +#include <__utility/integer_sequence.h> #include <__utility/move.h> #include <cstdint> #ifndef _LIBCPP_CXX03_LANG @@ -88,14 +87,9 @@ 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()); - } - -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_))...); + [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> void { + std::__invoke(std::get<_Indices>(std::move(__f_))...); + }(__make_index_sequence<tuple_size<_Fp>::value>()); } }; @@ -121,6 +115,15 @@ void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) { _LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*)); +template <class _ValueType> +inline _LIBCPP_HIDE_FROM_ABI _ValueType __libcpp_acquire_load(_ValueType const* __value) { +#if _LIBCPP_HAS_THREADS + return __atomic_load_n(__value, __ATOMIC_ACQUIRE); +#else + return *__value; +#endif +} + #ifndef _LIBCPP_CXX03_LANG template <class _Callable, class... _Args> diff --git a/lib/libcxx/include/__mutex/tag_types.h b/lib/libcxx/include/__mutex/tag_types.h @@ -17,15 +17,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD -struct _LIBCPP_EXPORTED_FROM_ABI defer_lock_t { +struct defer_lock_t { explicit defer_lock_t() = default; }; -struct _LIBCPP_EXPORTED_FROM_ABI try_to_lock_t { +struct try_to_lock_t { explicit try_to_lock_t() = default; }; -struct _LIBCPP_EXPORTED_FROM_ABI adopt_lock_t { +struct adopt_lock_t { explicit adopt_lock_t() = default; }; diff --git a/lib/libcxx/include/__mutex/unique_lock.h b/lib/libcxx/include/__mutex/unique_lock.h @@ -15,6 +15,7 @@ #include <__memory/addressof.h> #include <__mutex/tag_types.h> #include <__system_error/throw_system_error.h> +#include <__utility/move.h> #include <__utility/swap.h> #include <cerrno> @@ -22,6 +23,9 @@ # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template <class _Mutex> @@ -74,13 +78,8 @@ public: } _LIBCPP_HIDE_FROM_ABI unique_lock& operator=(unique_lock&& __u) _NOEXCEPT { - if (__owns_) - __m_->unlock(); - - __m_ = __u.__m_; - __owns_ = __u.__owns_; - __u.__m_ = nullptr; - __u.__owns_ = false; + if (this != std::addressof(__u)) + unique_lock(std::move(__u)).swap(*this); return *this; } @@ -170,4 +169,6 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mu _LIBCPP_END_NAMESPACE_STD +_LIBCPP_POP_MACROS + #endif // _LIBCPP___MUTEX_UNIQUE_LOCK_H diff --git a/lib/libcxx/include/__new/align_val_t.h b/lib/libcxx/include/__new/align_val_t.h @@ -16,6 +16,12 @@ # pragma GCC system_header #endif +// <vcruntime_exception.h> defines its own std::align_val_t type, +// which we use in order to be ABI-compatible with other STLs on Windows. +#if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION && defined(_LIBCPP_ABI_VCRUNTIME) +# include <vcruntime_new.h> +#endif + _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD #if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION && !defined(_LIBCPP_ABI_VCRUNTIME) # ifndef _LIBCPP_CXX03_LANG diff --git a/lib/libcxx/include/__new/allocate.h b/lib/libcxx/include/__new/allocate.h @@ -13,7 +13,6 @@ #include <__cstddef/max_align_t.h> #include <__cstddef/size_t.h> #include <__new/align_val_t.h> -#include <__new/global_new_delete.h> // for _LIBCPP_HAS_SIZED_DEALLOCATION #include <__type_traits/type_identity.h> #include <__utility/element_count.h> @@ -43,7 +42,7 @@ __libcpp_allocate(__element_count __n, [[__maybe_unused__]] size_t __align = _LI return static_cast<_Tp*>(__builtin_operator_new(__size)); } -#if _LIBCPP_HAS_SIZED_DEALLOCATION +#if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L # define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) __VA_ARGS__ #else # define _LIBCPP_ONLY_IF_SIZED_DEALLOCATION(...) /* nothing */ diff --git a/lib/libcxx/include/__new/exceptions.h b/lib/libcxx/include/__new/exceptions.h @@ -17,6 +17,12 @@ # pragma GCC system_header #endif +// <vcruntime_exception.h> defines its own std::bad_alloc type, +// which we use in order to be ABI-compatible with other STLs on Windows. +#if defined(_LIBCPP_ABI_VCRUNTIME) +# include <vcruntime_exception.h> +#endif + _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD #if !defined(_LIBCPP_ABI_VCRUNTIME) @@ -26,7 +32,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_alloc(const bad_alloc&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_alloc& operator=(const bad_alloc&) _NOEXCEPT = default; ~bad_alloc() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; class _LIBCPP_EXPORTED_FROM_ABI bad_array_new_length : public bad_alloc { @@ -35,7 +41,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_array_new_length(const bad_array_new_length&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_array_new_length& operator=(const bad_array_new_length&) _NOEXCEPT = default; ~bad_array_new_length() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; #elif defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS == 0 // !_LIBCPP_ABI_VCRUNTIME diff --git a/lib/libcxx/include/__new/global_new_delete.h b/lib/libcxx/include/__new/global_new_delete.h @@ -12,7 +12,6 @@ #include <__config> #include <__cstddef/size_t.h> #include <__new/align_val_t.h> -#include <__new/exceptions.h> #include <__new/nothrow_t.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -25,12 +24,6 @@ # define _THROW_BAD_ALLOC #endif -#if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L -# define _LIBCPP_HAS_SIZED_DEALLOCATION 1 -#else -# define _LIBCPP_HAS_SIZED_DEALLOCATION 0 -#endif - #if defined(_LIBCPP_ABI_VCRUNTIME) # include <new.h> #else @@ -39,7 +32,7 @@ _LIBCPP_NOALIAS; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p) _NOEXCEPT; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, const std::nothrow_t&) _NOEXCEPT; -# if _LIBCPP_HAS_SIZED_DEALLOCATION +# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::size_t __sz) _NOEXCEPT; # endif @@ -48,7 +41,7 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::size_t __sz) _ _LIBCPP_NOALIAS; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p) _NOEXCEPT; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, const std::nothrow_t&) _NOEXCEPT; -# if _LIBCPP_HAS_SIZED_DEALLOCATION +# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::size_t __sz) _NOEXCEPT; # endif @@ -58,7 +51,7 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::size_t __sz) operator new(std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _LIBCPP_NOALIAS; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::align_val_t) _NOEXCEPT; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT; -# if _LIBCPP_HAS_SIZED_DEALLOCATION +# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; # endif @@ -68,7 +61,7 @@ operator new[](std::size_t __sz, std::align_val_t) _THROW_BAD_ALLOC; operator new[](std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _LIBCPP_NOALIAS; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::align_val_t) _NOEXCEPT; _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT; -# if _LIBCPP_HAS_SIZED_DEALLOCATION +# if defined(__cpp_sized_deallocation) && __cpp_sized_deallocation >= 201309L _LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; # endif # endif diff --git a/lib/libcxx/include/__new/interference_size.h b/lib/libcxx/include/__new/interference_size.h @@ -20,13 +20,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -# if defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE) - inline constexpr size_t hardware_destructive_interference_size = __GCC_DESTRUCTIVE_SIZE; inline constexpr size_t hardware_constructive_interference_size = __GCC_CONSTRUCTIVE_SIZE; -# endif // defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE) - #endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__new/launder.h b/lib/libcxx/include/__new/launder.h @@ -10,8 +10,6 @@ #define _LIBCPP___NEW_LAUNDER_H #include <__config> -#include <__type_traits/is_function.h> -#include <__type_traits/is_void.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -20,15 +18,15 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __launder(_Tp* __p) _NOEXCEPT { - static_assert(!(is_function<_Tp>::value), "can't launder functions"); - static_assert(!is_void<_Tp>::value, "can't launder cv-void"); + // The compiler diagnoses misuses of __builtin_launder, so we don't need to add any static_asserts + // to implement the Mandates. return __builtin_launder(__p); } #if _LIBCPP_STD_VER >= 17 template <class _Tp> [[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp* launder(_Tp* __p) noexcept { - return std::__launder(__p); + return __builtin_launder(__p); } #endif _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__new/nothrow_t.h b/lib/libcxx/include/__new/nothrow_t.h @@ -19,7 +19,7 @@ # include <new.h> #else _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD -struct _LIBCPP_EXPORTED_FROM_ABI nothrow_t { +struct nothrow_t { explicit nothrow_t() = default; }; extern _LIBCPP_EXPORTED_FROM_ABI const nothrow_t nothrow; diff --git a/lib/libcxx/include/__numeric/gcd_lcm.h b/lib/libcxx/include/__numeric/gcd_lcm.h @@ -33,28 +33,26 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -template <typename _Result, typename _Source, bool _IsSigned = is_signed<_Source>::value> -struct __ct_abs; - -template <typename _Result, typename _Source> -struct __ct_abs<_Result, _Source, true> { - constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { +template <class _Result, class _Source> +constexpr _LIBCPP_HIDE_FROM_ABI _Result __abs_in_type(_Source __t) noexcept { + if constexpr (is_signed_v<_Source>) { if (__t >= 0) return __t; if (__t == numeric_limits<_Source>::min()) return -static_cast<_Result>(__t); return -__t; + } else { + return __t; } -}; - -template <typename _Result, typename _Source> -struct __ct_abs<_Result, _Source, false> { - constexpr _LIBCPP_HIDE_FROM_ABI _Result operator()(_Source __t) const noexcept { return __t; } -}; +} -template <class _Tp> -constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { - static_assert(!is_signed<_Tp>::value, ""); +template <class _Tp, class _Up> +constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) { + static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to gcd must be integer types"); + static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to gcd cannot be bool"); + static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to gcd cannot be bool"); + using _Rp = common_type_t<_Tp, _Up>; + using _Wp = make_unsigned_t<_Rp>; // Using Binary GCD algorithm https://en.wikipedia.org/wiki/Binary_GCD_algorithm, based on an implementation // from https://lemire.me/blog/2024/04/13/greatest-common-divisor-the-extended-euclidean-algorithm-and-speed/ @@ -67,22 +65,25 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { // // And standard gcd algorithm where instead of modulo, minus is used. + auto __a = static_cast<_Wp>(std::__abs_in_type<_Rp>(__m)); + auto __b = static_cast<_Wp>(std::__abs_in_type<_Rp>(__n)); + if (__a < __b) { - _Tp __tmp = __b; + _Wp __tmp = __b; __b = __a; __a = __tmp; } if (__b == 0) - return __a; + return static_cast<_Rp>(__a); __a %= __b; // Make both argument of the same size, and early result in the easy case. if (__a == 0) - return __b; + return static_cast<_Rp>(__b); - _Tp __c = __a | __b; + _Wp __c = __a | __b; int __shift = std::__countr_zero(__c); __a >>= std::__countr_zero(__a); do { - _Tp __t = __b >> std::__countr_zero(__b); + _Wp __t = __b >> std::__countr_zero(__b); if (__a > __t) { __b = __a - __t; __a = __t; @@ -90,18 +91,7 @@ constexpr _LIBCPP_HIDDEN _Tp __gcd(_Tp __a, _Tp __b) { __b = __t - __a; } } while (__b != 0); - return __a << __shift; -} - -template <class _Tp, class _Up> -constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> gcd(_Tp __m, _Up __n) { - static_assert(is_integral<_Tp>::value && is_integral<_Up>::value, "Arguments to gcd must be integer types"); - static_assert(!is_same<__remove_cv_t<_Tp>, bool>::value, "First argument to gcd cannot be bool"); - static_assert(!is_same<__remove_cv_t<_Up>, bool>::value, "Second argument to gcd cannot be bool"); - using _Rp = common_type_t<_Tp, _Up>; - using _Wp = make_unsigned_t<_Rp>; - return static_cast<_Rp>( - std::__gcd(static_cast<_Wp>(__ct_abs<_Rp, _Tp>()(__m)), static_cast<_Wp>(__ct_abs<_Rp, _Up>()(__n)))); + return static_cast<_Rp>(__a << __shift); } template <class _Tp, class _Up> @@ -113,8 +103,8 @@ constexpr _LIBCPP_HIDE_FROM_ABI common_type_t<_Tp, _Up> lcm(_Tp __m, _Up __n) { return 0; using _Rp = common_type_t<_Tp, _Up>; - _Rp __val1 = __ct_abs<_Rp, _Tp>()(__m) / std::gcd(__m, __n); - _Rp __val2 = __ct_abs<_Rp, _Up>()(__n); + _Rp __val1 = std::__abs_in_type<_Rp>(__m) / std::gcd(__m, __n); + _Rp __val2 = std::__abs_in_type<_Rp>(__n); _Rp __res; [[maybe_unused]] bool __overflow = __builtin_mul_overflow(__val1, __val2, std::addressof(__res)); _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__overflow, "Overflow in lcm"); diff --git a/lib/libcxx/include/__numeric/midpoint.h b/lib/libcxx/include/__numeric/midpoint.h @@ -12,16 +12,13 @@ #include <__config> #include <__cstddef/ptrdiff_t.h> -#include <__type_traits/enable_if.h> #include <__type_traits/is_floating_point.h> #include <__type_traits/is_integral.h> -#include <__type_traits/is_null_pointer.h> #include <__type_traits/is_object.h> -#include <__type_traits/is_pointer.h> #include <__type_traits/is_same.h> #include <__type_traits/is_void.h> #include <__type_traits/make_unsigned.h> -#include <__type_traits/remove_pointer.h> +#include <__type_traits/remove_cv.h> #include <limits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -35,8 +32,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 template <class _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<is_integral_v<_Tp> && !is_same_v<bool, _Tp> && !is_null_pointer_v<_Tp>, _Tp> -midpoint(_Tp __a, _Tp __b) noexcept _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { + requires(is_integral_v<_Tp> && !is_same_v<remove_cv_t<_Tp>, bool>) +[[nodiscard]] +_LIBCPP_HIDE_FROM_ABI constexpr _Tp midpoint(_Tp __a, _Tp __b) noexcept _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { using _Up = make_unsigned_t<_Tp>; constexpr _Up __bitshift = numeric_limits<_Up>::digits - 1; @@ -48,23 +46,20 @@ midpoint(_Tp __a, _Tp __b) noexcept _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK return __a + __half_diff; } -template <class _Tp, enable_if_t<is_object_v<_Tp> && !is_void_v<_Tp> && (sizeof(_Tp) > 0), int> = 0> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp* midpoint(_Tp* __a, _Tp* __b) noexcept { +template <class _Tp> + requires(is_object_v<_Tp> && (sizeof(_Tp) > 0)) +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* midpoint(_Tp* __a, _Tp* __b) noexcept { return __a + std::midpoint(ptrdiff_t(0), __b - __a); } -template <typename _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr int __sign(_Tp __val) { - return (_Tp(0) < __val) - (__val < _Tp(0)); -} - template <typename _Fp> _LIBCPP_HIDE_FROM_ABI constexpr _Fp __fp_abs(_Fp __f) { return __f >= 0 ? __f : -__f; } template <class _Fp> -_LIBCPP_HIDE_FROM_ABI constexpr enable_if_t<is_floating_point_v<_Fp>, _Fp> midpoint(_Fp __a, _Fp __b) noexcept { + requires(is_floating_point_v<_Fp>) +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Fp midpoint(_Fp __a, _Fp __b) noexcept { constexpr _Fp __lo = numeric_limits<_Fp>::min() * 2; constexpr _Fp __hi = numeric_limits<_Fp>::max() / 2; diff --git a/lib/libcxx/include/__numeric/pstl.h b/lib/libcxx/include/__numeric/pstl.h @@ -70,7 +70,7 @@ template <class _ExecutionPolicy, class _ForwardIterator, class _RawPolicy = __remove_cvref_t<_ExecutionPolicy>, enable_if_t<is_execution_policy_v<_RawPolicy>, int> = 0> -_LIBCPP_HIDE_FROM_ABI __iter_value_type<_ForwardIterator> +_LIBCPP_HIDE_FROM_ABI __iterator_value_type<_ForwardIterator> reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator __last) { _LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(_ForwardIterator, "reduce requires ForwardIterators"); using _Implementation = __pstl::__dispatch<__pstl::__reduce, __pstl::__current_configuration, _RawPolicy>; @@ -78,7 +78,7 @@ reduce(_ExecutionPolicy&& __policy, _ForwardIterator __first, _ForwardIterator _ std::forward<_ExecutionPolicy>(__policy), std::move(__first), std::move(__last), - __iter_value_type<_ForwardIterator>(), + __iterator_value_type<_ForwardIterator>(), plus{}); } diff --git a/lib/libcxx/include/__numeric/saturation_arithmetic.h b/lib/libcxx/include/__numeric/saturation_arithmetic.h @@ -30,6 +30,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { +# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101 + return __builtin_elementwise_add_sat(__x, __y); +# else if (_Tp __sum; !__builtin_add_overflow(__x, __y, std::addressof(__sum))) return __sum; // Handle overflow @@ -44,10 +47,14 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __add_sat(_Tp __x, _Tp __y) noexcept { // Overflows if (x < 0 && y < 0) return std::numeric_limits<_Tp>::min(); } +# endif } template <__signed_or_unsigned_integer _Tp> _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { +# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101 + return __builtin_elementwise_sub_sat(__x, __y); +# else if (_Tp __sub; !__builtin_sub_overflow(__x, __y, std::addressof(__sub))) return __sub; // Handle overflow @@ -63,6 +70,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp __sub_sat(_Tp __x, _Tp __y) noexcept { // Overflows if (x < 0 && y > 0) return std::numeric_limits<_Tp>::min(); } +# endif } template <__signed_or_unsigned_integer _Tp> @@ -113,27 +121,27 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Rp __saturate_cast(_Tp __x) noexcept { #if _LIBCPP_STD_VER >= 26 template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp add_sat(_Tp __x, _Tp __y) noexcept { return std::__add_sat(__x, __y); } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp sub_sat(_Tp __x, _Tp __y) noexcept { return std::__sub_sat(__x, __y); } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp mul_sat(_Tp __x, _Tp __y) noexcept { return std::__mul_sat(__x, __y); } template <__signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp div_sat(_Tp __x, _Tp __y) noexcept { return std::__div_sat(__x, __y); } template <__signed_or_unsigned_integer _Rp, __signed_or_unsigned_integer _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Rp saturate_cast(_Tp __x) noexcept { return std::__saturate_cast<_Rp>(__x); } diff --git a/lib/libcxx/include/__ostream/basic_ostream.h b/lib/libcxx/include/__ostream/basic_ostream.h @@ -53,7 +53,7 @@ public: typedef typename traits_type::off_type off_type; // 27.7.2.2 Constructor/destructor: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_ostream(basic_streambuf<char_type, traits_type>* __sb) { this->init(__sb); } ~basic_ostream() override; @@ -67,7 +67,7 @@ protected: // 27.7.2.3 Assign/swap inline _LIBCPP_HIDE_FROM_ABI basic_ostream& operator=(basic_ostream&& __rhs); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_ostream& __rhs) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_ostream& __rhs) { basic_ios<char_type, traits_type>::swap(__rhs); } @@ -76,17 +76,17 @@ public: class sentry; // 27.7.2.6 Formatted output: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(basic_ostream& (*__pf)(basic_ostream&)) { return __pf(*this); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) { __pf(*this); return *this; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& operator<<(ios_base& (*__pf)(ios_base&)) { __pf(*this); return *this; } @@ -174,9 +174,9 @@ public: basic_ostream& flush(); // 27.7.2.5 seeks: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type tellp(); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(pos_type __pos); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir); + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type tellp(); + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(pos_type __pos); + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_ostream& seekp(off_type __off, ios_base::seekdir __dir); protected: _LIBCPP_HIDE_FROM_ABI basic_ostream() {} // extension, intentially does not initialize diff --git a/lib/libcxx/include/__pstl/backends/default.h b/lib/libcxx/include/__pstl/backends/default.h @@ -102,7 +102,7 @@ struct __find<__default_backend_tag, _ExecutionPolicy> { operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) const noexcept { using _FindIf = __dispatch<__find_if, __current_configuration, _ExecutionPolicy>; return _FindIf()( - __policy, std::move(__first), std::move(__last), [&](__iter_reference<_ForwardIterator> __element) { + __policy, std::move(__first), std::move(__last), [&](__iterator_reference<_ForwardIterator> __element) { return __element == __value; }); } @@ -137,7 +137,7 @@ struct __all_of<__default_backend_tag, _ExecutionPolicy> { [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<bool> operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred) const noexcept { using _AnyOf = __dispatch<__any_of, __current_configuration, _ExecutionPolicy>; - auto __res = _AnyOf()(__policy, __first, __last, [&](__iter_reference<_ForwardIterator> __value) { + auto __res = _AnyOf()(__policy, __first, __last, [&](__iterator_reference<_ForwardIterator> __value) { return !__pred(__value); }); if (!__res) @@ -204,7 +204,7 @@ struct __fill<__default_backend_tag, _ExecutionPolicy> { [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept { using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __value; }); } }; @@ -233,7 +233,7 @@ struct __replace<__default_backend_tag, _ExecutionPolicy> { operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __old, _Tp const& __new) const noexcept { using _ReplaceIf = __dispatch<__replace_if, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ReplaceIf()( __policy, std::move(__first), std::move(__last), [&](_Ref __element) { return __element == __old; }, __new); } @@ -246,7 +246,7 @@ struct __replace_if<__default_backend_tag, _ExecutionPolicy> { _Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Pred&& __pred, _Tp const& __new_value) const noexcept { using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { if (__pred(__element)) __element = __new_value; @@ -260,7 +260,7 @@ struct __generate<__default_backend_tag, _ExecutionPolicy> { [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Generator&& __gen) const noexcept { using _ForEach = __dispatch<__for_each, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ForEach()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) { __element = __gen(); }); } }; @@ -271,7 +271,7 @@ struct __generate_n<__default_backend_tag, _ExecutionPolicy> { [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__empty> operator()(_Policy&& __policy, _ForwardIterator __first, _Size __n, _Generator&& __gen) const noexcept { using _ForEachN = __dispatch<__for_each_n, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ForEachN()(__policy, std::move(__first), __n, [&](_Ref __element) { __element = __gen(); }); } }; @@ -295,11 +295,11 @@ struct __sort<__default_backend_tag, _ExecutionPolicy> { template <class _ExecutionPolicy> struct __count_if<__default_backend_tag, _ExecutionPolicy> { template <class _Policy, class _ForwardIterator, class _Predicate> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> operator()( + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iterator_difference_type<_ForwardIterator>> operator()( _Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred) const noexcept { using _TransformReduce = __dispatch<__transform_reduce, __current_configuration, _ExecutionPolicy>; - using _DiffT = __iter_diff_t<_ForwardIterator>; - using _Ref = __iter_reference<_ForwardIterator>; + using _DiffT = __iterator_difference_type<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _TransformReduce()( __policy, std::move(__first), std::move(__last), _DiffT{}, std::plus{}, [&](_Ref __element) -> _DiffT { return __pred(__element) ? _DiffT(1) : _DiffT(0); @@ -310,10 +310,10 @@ struct __count_if<__default_backend_tag, _ExecutionPolicy> { template <class _ExecutionPolicy> struct __count<__default_backend_tag, _ExecutionPolicy> { template <class _Policy, class _ForwardIterator, class _Tp> - [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iter_diff_t<_ForwardIterator>> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<__iterator_difference_type<_ForwardIterator>> operator()(_Policy&& __policy, _ForwardIterator __first, _ForwardIterator __last, _Tp const& __value) const noexcept { using _CountIf = __dispatch<__count_if, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _CountIf()(__policy, std::move(__first), std::move(__last), [&](_Ref __element) -> bool { return __element == __value; }); @@ -402,7 +402,7 @@ struct __replace_copy_if<__default_backend_tag, _ExecutionPolicy> { _Pred&& __pred, _Tp const& __new_value) const noexcept { using _Transform = __dispatch<__transform, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; auto __res = _Transform()(__policy, std::move(__first), std::move(__last), std::move(__out_it), [&](_Ref __element) { return __pred(__element) ? __new_value : __element; @@ -424,7 +424,7 @@ struct __replace_copy<__default_backend_tag, _ExecutionPolicy> { _Tp const& __old_value, _Tp const& __new_value) const noexcept { using _ReplaceCopyIf = __dispatch<__replace_copy_if, __current_configuration, _ExecutionPolicy>; - using _Ref = __iter_reference<_ForwardIterator>; + using _Ref = __iterator_reference<_ForwardIterator>; return _ReplaceCopyIf()( __policy, std::move(__first), diff --git a/lib/libcxx/include/__pstl/backends/libdispatch.h b/lib/libcxx/include/__pstl/backends/libdispatch.h @@ -269,7 +269,7 @@ struct __cpu_traits<__libdispatch_backend_tag> { return __empty{}; } - using _Value = __iter_value_type<_RandomAccessIterator>; + using _Value = __iterator_value_type<_RandomAccessIterator>; auto __destroy = [__size](_Value* __ptr) { std::destroy_n(__ptr, __size); @@ -282,7 +282,7 @@ struct __cpu_traits<__libdispatch_backend_tag> { // Initialize all elements to a moved-from state // TODO: Don't do this - this can be done in the first merge - see https://llvm.org/PR63928 std::__construct_at(__values.get(), std::move(*__first)); - for (__iter_diff_t<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { + for (__iterator_difference_type<_RandomAccessIterator> __i = 1; __i != __size; ++__i) { std::__construct_at(__values.get() + __i, std::move(__values.get()[__i - 1])); } *__first = std::move(__values.get()[__size - 1]); diff --git a/lib/libcxx/include/__pstl/cpu_algos/find_if.h b/lib/libcxx/include/__pstl/cpu_algos/find_if.h @@ -119,7 +119,7 @@ struct __cpu_parallel_find_if { true); } else if constexpr (__is_unsequenced_execution_policy_v<_RawExecutionPolicy> && __has_random_access_iterator_category_or_concept<_ForwardIterator>::value) { - using __diff_t = __iter_diff_t<_ForwardIterator>; + using __diff_t = __iterator_difference_type<_ForwardIterator>; return __pstl::__simd_first<_Backend>( __first, __diff_t(0), __last - __first, [&__pred](_ForwardIterator __iter, __diff_t __i) { return __pred(__iter[__i]); diff --git a/lib/libcxx/include/__pstl/cpu_algos/transform.h b/lib/libcxx/include/__pstl/cpu_algos/transform.h @@ -84,9 +84,8 @@ struct __cpu_parallel_transform { __first, __last - __first, __result, - [&](__iter_reference<_ForwardIterator> __in_value, __iter_reference<_ForwardOutIterator> __out_value) { - __out_value = __op(__in_value); - }); + [&](__iterator_reference<_ForwardIterator> __in_value, + __iterator_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in_value); }); } else { return std::transform(__first, __last, __result, __op); } @@ -138,9 +137,9 @@ struct __cpu_parallel_transform_binary { __last1 - __first1, __first2, __result, - [&](__iter_reference<_ForwardIterator1> __in1, - __iter_reference<_ForwardIterator2> __in2, - __iter_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); }); + [&](__iterator_reference<_ForwardIterator1> __in1, + __iterator_reference<_ForwardIterator2> __in2, + __iterator_reference<_ForwardOutIterator> __out_value) { __out_value = __op(__in1, __in2); }); } else { return std::transform(__first1, __last1, __first2, __result, __op); } diff --git a/lib/libcxx/include/__pstl/cpu_algos/transform_reduce.h b/lib/libcxx/include/__pstl/cpu_algos/transform_reduce.h @@ -148,9 +148,10 @@ struct __cpu_parallel_transform_reduce_binary { __has_random_access_iterator_category_or_concept<_ForwardIterator1>::value && __has_random_access_iterator_category_or_concept<_ForwardIterator2>::value) { return __pstl::__simd_transform_reduce<_Backend>( - __last1 - __first1, std::move(__init), std::move(__reduce), [&](__iter_diff_t<_ForwardIterator1> __i) { - return __transform(__first1[__i], __first2[__i]); - }); + __last1 - __first1, + std::move(__init), + std::move(__reduce), + [&](__iterator_difference_type<_ForwardIterator1> __i) { return __transform(__first1[__i], __first2[__i]); }); } else { return std::transform_reduce( std::move(__first1), @@ -200,7 +201,7 @@ struct __cpu_parallel_transform_reduce { __last - __first, std::move(__init), std::move(__reduce), - [=, &__transform](__iter_diff_t<_ForwardIterator> __i) { return __transform(__first[__i]); }); + [=, &__transform](__iterator_difference_type<_ForwardIterator> __i) { return __transform(__first[__i]); }); } else { return std::transform_reduce( std::move(__first), std::move(__last), std::move(__init), std::move(__reduce), std::move(__transform)); diff --git a/lib/libcxx/include/__random/binomial_distribution.h b/lib/libcxx/include/__random/binomial_distribution.h @@ -97,13 +97,19 @@ public: } }; -// The LLVM C library provides this with conflicting `noexcept` attributes. -#if !defined(_LIBCPP_MSVCRT_LIKE) && !defined(__LLVM_LIBC__) -extern "C" double lgamma_r(double, int*); +// Some libc declares the math functions to be `noexcept`. +#if _LIBCPP_GLIBC_PREREQ(2, 8) || defined(__LLVM_LIBC__) +# define _LIBCPP_LGAMMA_R_NOEXCEPT _NOEXCEPT +#else +# define _LIBCPP_LGAMMA_R_NOEXCEPT +#endif + +#if !defined(_LIBCPP_MSVCRT_LIKE) +extern "C" double lgamma_r(double, int*) _LIBCPP_LGAMMA_R_NOEXCEPT; #endif inline _LIBCPP_HIDE_FROM_ABI double __libcpp_lgamma(double __d) { -#if defined(_LIBCPP_MSVCRT_LIKE) || defined(__LLVM_LIBC__) +#if defined(_LIBCPP_MSVCRT_LIKE) return lgamma(__d); #else int __sign; diff --git a/lib/libcxx/include/__random/mersenne_twister_engine.h b/lib/libcxx/include/__random/mersenne_twister_engine.h @@ -62,24 +62,6 @@ _LIBCPP_HIDE_FROM_ABI bool operator==(const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __x, const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __y); -template <class _UInt, - size_t _Wp, - size_t _Np, - size_t _Mp, - size_t _Rp, - _UInt _Ap, - size_t _Up, - _UInt _Dp, - size_t _Sp, - _UInt _Bp, - size_t _Tp, - _UInt _Cp, - size_t _Lp, - _UInt _Fp> -_LIBCPP_HIDE_FROM_ABI bool -operator!=(const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __x, - const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __y); - template <class _CharT, class _Traits, class _UInt, @@ -194,14 +176,31 @@ public: _LIBCPP_HIDE_FROM_ABI explicit mersenne_twister_engine(_Sseq& __q) { seed(__q); } - _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd = default_seed); + _LIBCPP_HIDE_FROM_ABI void seed(result_type __sd = default_seed) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { + __x_[0] = __sd & _Max; + for (size_t __i = 1; __i < __n; ++__i) + __x_[__i] = (__f * (__x_[__i - 1] ^ __rshift<__w - 2>(__x_[__i - 1])) + __i) & _Max; + __i_ = 0; + } template <class _Sseq, __enable_if_t<__is_seed_sequence<_Sseq, mersenne_twister_engine>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI void seed(_Sseq& __q) { __seed(__q, integral_constant<unsigned, 1 + (__w - 1) / 32>()); } // generating functions - _LIBCPP_HIDE_FROM_ABI result_type operator()(); + _LIBCPP_HIDE_FROM_ABI result_type operator()() { + const size_t __j = (__i_ + 1) % __n; + const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); + const result_type __yp = (__x_[__i_] & ~__mask) | (__x_[__j] & __mask); + const size_t __k = (__i_ + __m) % __n; + __x_[__i_] = __x_[__k] ^ __rshift<1>(__yp) ^ (__a * (__yp & 1)); + result_type __z = __x_[__i_] ^ (__rshift<__u>(__x_[__i_]) & __d); + __i_ = __j; + __z ^= __lshift<__s>(__z) & __b; + __z ^= __lshift<__t>(__z) & __c; + return __z ^ __rshift<__l>(__z); + } + _LIBCPP_HIDE_FROM_ABI void discard(unsigned long long __z) { for (; __z; --__z) operator()(); @@ -225,24 +224,6 @@ public: const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __x, const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __y); - template <class _UInt, - size_t _Wp, - size_t _Np, - size_t _Mp, - size_t _Rp, - _UInt _Ap, - size_t _Up, - _UInt _Dp, - size_t _Sp, - _UInt _Bp, - size_t _Tp, - _UInt _Cp, - size_t _Lp, - _UInt _Fp> - friend bool operator!=( - const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __x, - const mersenne_twister_engine<_UInt, _Wp, _Np, _Mp, _Rp, _Ap, _Up, _Dp, _Sp, _Bp, _Tp, _Cp, _Lp, _Fp>& __y); - template <class _CharT, class _Traits, class _UInt, @@ -285,9 +266,38 @@ public: private: template <class _Sseq> - _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 1>); + _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 1>) { + const unsigned __k = 1; + uint32_t __ar[__n * __k]; + __q.generate(__ar, __ar + __n * __k); + for (size_t __i = 0; __i < __n; ++__i) + __x_[__i] = static_cast<result_type>(__ar[__i] & _Max); + const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); + __i_ = 0; + if ((__x_[0] & ~__mask) == 0) { + for (size_t __i = 1; __i < __n; ++__i) + if (__x_[__i] != 0) + return; + __x_[0] = result_type(1) << (__w - 1); + } + } + template <class _Sseq> - _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 2>); + _LIBCPP_HIDE_FROM_ABI void __seed(_Sseq& __q, integral_constant<unsigned, 2>) { + const unsigned __k = 2; + uint32_t __ar[__n * __k]; + __q.generate(__ar, __ar + __n * __k); + for (size_t __i = 0; __i < __n; ++__i) + __x_[__i] = static_cast<result_type>((__ar[2 * __i] + ((uint64_t)__ar[2 * __i + 1] << 32)) & _Max); + const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); + __i_ = 0; + if ((__x_[0] & ~__mask) == 0) { + for (size_t __i = 1; __i < __n; ++__i) + if (__x_[__i] != 0) + return; + __x_[0] = result_type(1) << (__w - 1); + } + } template <size_t __count, __enable_if_t<__count< __w, int> = 0> _LIBCPP_HIDE_FROM_ABI static result_type __lshift(result_type __x) { @@ -310,120 +320,6 @@ private: } }; -template <class _UIntType, - size_t __w, - size_t __n, - size_t __m, - size_t __r, - _UIntType __a, - size_t __u, - _UIntType __d, - size_t __s, - _UIntType __b, - size_t __t, - _UIntType __c, - size_t __l, - _UIntType __f> -void mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, __d, __s, __b, __t, __c, __l, __f>::seed( - result_type __sd) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK { // __w >= 2 - __x_[0] = __sd & _Max; - for (size_t __i = 1; __i < __n; ++__i) - __x_[__i] = (__f * (__x_[__i - 1] ^ __rshift<__w - 2>(__x_[__i - 1])) + __i) & _Max; - __i_ = 0; -} - -template <class _UIntType, - size_t __w, - size_t __n, - size_t __m, - size_t __r, - _UIntType __a, - size_t __u, - _UIntType __d, - size_t __s, - _UIntType __b, - size_t __t, - _UIntType __c, - size_t __l, - _UIntType __f> -template <class _Sseq> -void mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, __d, __s, __b, __t, __c, __l, __f>::__seed( - _Sseq& __q, integral_constant<unsigned, 1>) { - const unsigned __k = 1; - uint32_t __ar[__n * __k]; - __q.generate(__ar, __ar + __n * __k); - for (size_t __i = 0; __i < __n; ++__i) - __x_[__i] = static_cast<result_type>(__ar[__i] & _Max); - const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); - __i_ = 0; - if ((__x_[0] & ~__mask) == 0) { - for (size_t __i = 1; __i < __n; ++__i) - if (__x_[__i] != 0) - return; - __x_[0] = result_type(1) << (__w - 1); - } -} - -template <class _UIntType, - size_t __w, - size_t __n, - size_t __m, - size_t __r, - _UIntType __a, - size_t __u, - _UIntType __d, - size_t __s, - _UIntType __b, - size_t __t, - _UIntType __c, - size_t __l, - _UIntType __f> -template <class _Sseq> -void mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, __d, __s, __b, __t, __c, __l, __f>::__seed( - _Sseq& __q, integral_constant<unsigned, 2>) { - const unsigned __k = 2; - uint32_t __ar[__n * __k]; - __q.generate(__ar, __ar + __n * __k); - for (size_t __i = 0; __i < __n; ++__i) - __x_[__i] = static_cast<result_type>((__ar[2 * __i] + ((uint64_t)__ar[2 * __i + 1] << 32)) & _Max); - const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); - __i_ = 0; - if ((__x_[0] & ~__mask) == 0) { - for (size_t __i = 1; __i < __n; ++__i) - if (__x_[__i] != 0) - return; - __x_[0] = result_type(1) << (__w - 1); - } -} - -template <class _UIntType, - size_t __w, - size_t __n, - size_t __m, - size_t __r, - _UIntType __a, - size_t __u, - _UIntType __d, - size_t __s, - _UIntType __b, - size_t __t, - _UIntType __c, - size_t __l, - _UIntType __f> -_UIntType -mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, __d, __s, __b, __t, __c, __l, __f>::operator()() { - const size_t __j = (__i_ + 1) % __n; - const result_type __mask = __r == _Dt ? result_type(~0) : (result_type(1) << __r) - result_type(1); - const result_type __yp = (__x_[__i_] & ~__mask) | (__x_[__j] & __mask); - const size_t __k = (__i_ + __m) % __n; - __x_[__i_] = __x_[__k] ^ __rshift<1>(__yp) ^ (__a * (__yp & 1)); - result_type __z = __x_[__i_] ^ (__rshift<__u>(__x_[__i_]) & __d); - __i_ = __j; - __z ^= __lshift<__s>(__z) & __b; - __z ^= __lshift<__t>(__z) & __c; - return __z ^ __rshift<__l>(__z); -} - template <class _UInt, size_t _Wp, size_t _Np, diff --git a/lib/libcxx/include/__random/piecewise_constant_distribution.h b/lib/libcxx/include/__random/piecewise_constant_distribution.h @@ -9,9 +9,11 @@ #ifndef _LIBCPP___RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_H #define _LIBCPP___RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_H +#include <__algorithm/copy_n.h> #include <__algorithm/upper_bound.h> #include <__config> #include <__cstddef/ptrdiff_t.h> +#include <__iterator/back_insert_iterator.h> #include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include <__vector/vector.h> @@ -190,8 +192,7 @@ piecewise_constant_distribution<_RealType>::param_type::param_type( __areas_.assign(1, 0.0); } else { __densities_.reserve(__b_.size() - 1); - for (size_t __i = 0; __i < __b_.size() - 1; ++__i, ++__f_w) - __densities_.push_back(*__f_w); + std::copy_n(__f_w, __b_.size() - 1, std::back_inserter(__densities_)); __init(); } } diff --git a/lib/libcxx/include/__random/piecewise_linear_distribution.h b/lib/libcxx/include/__random/piecewise_linear_distribution.h @@ -9,9 +9,11 @@ #ifndef _LIBCPP___RANDOM_PIECEWISE_LINEAR_DISTRIBUTION_H #define _LIBCPP___RANDOM_PIECEWISE_LINEAR_DISTRIBUTION_H +#include <__algorithm/copy_n.h> #include <__algorithm/upper_bound.h> #include <__config> #include <__cstddef/ptrdiff_t.h> +#include <__iterator/back_insert_iterator.h> #include <__random/is_valid.h> #include <__random/uniform_real_distribution.h> #include <__vector/comparison.h> @@ -194,8 +196,7 @@ piecewise_linear_distribution<_RealType>::param_type::param_type( __areas_.assign(1, 0.0); } else { __densities_.reserve(__b_.size()); - for (size_t __i = 0; __i < __b_.size(); ++__i, ++__f_w) - __densities_.push_back(*__f_w); + std::copy_n(__f_w, __b_.size(), std::back_inserter(__densities_)); __init(); } } diff --git a/lib/libcxx/include/__ranges/adjacent_transform_view.h b/lib/libcxx/include/__ranges/adjacent_transform_view.h @@ -0,0 +1,406 @@ +// -*- 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_ADJACENT_TRANSFORM_VIEW_H +#define _LIBCPP___RANGES_ADJACENT_TRANSFORM_VIEW_H + +#include <__config> + +#include <__algorithm/min.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/equality_comparable.h> +#include <__concepts/invocable.h> +#include <__cstddef/size_t.h> +#include <__functional/bind_back.h> +#include <__functional/invoke.h> +#include <__functional/operations.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/prev.h> +#include <__memory/addressof.h> +#include <__ranges/access.h> +#include <__ranges/adjacent_view.h> +#include <__ranges/all.h> +#include <__ranges/concepts.h> +#include <__ranges/empty_view.h> +#include <__ranges/movable_box.h> +#include <__ranges/range_adaptor.h> +#include <__ranges/size.h> +#include <__ranges/view_interface.h> +#include <__ranges/zip_transform_view.h> +#include <__type_traits/common_type.h> +#include <__type_traits/decay.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/is_object.h> +#include <__type_traits/is_referenceable.h> +#include <__type_traits/make_unsigned.h> +#include <__type_traits/maybe_const.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/in_place.h> +#include <__utility/integer_sequence.h> +#include <__utility/move.h> + +#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 <class _Fn, size_t _Np> +struct __apply_n { + template <class _Tp, size_t... _Is> + static auto __apply(index_sequence<_Is...>) -> invoke_result_t<_Fn, decltype((void)_Is, std::declval<_Tp>())...>; + + template <class _Tp> + static auto operator()(_Tp&&) -> decltype(__apply<_Tp>(make_index_sequence<_Np>{})); +}; + +template <forward_range _View, move_constructible _Fn, size_t _Np> + requires view<_View> && (_Np > 0) && is_object_v<_Fn> && + regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> && + __referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>> +class adjacent_transform_view : public view_interface<adjacent_transform_view<_View, _Fn, _Np>> { +private: + _LIBCPP_NO_UNIQUE_ADDRESS adjacent_view<_View, _Np> __inner_; + _LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Fn> __fun_; + + using _InnerView _LIBCPP_NODEBUG = adjacent_view<_View, _Np>; + + template <bool _Const> + using __inner_iterator _LIBCPP_NODEBUG = iterator_t<__maybe_const<_Const, _InnerView>>; + + template <bool _Const> + using __inner_sentinel _LIBCPP_NODEBUG = sentinel_t<__maybe_const<_Const, _InnerView>>; + + template <bool> + class __iterator; + + template <bool> + class __sentinel; + +public: + _LIBCPP_HIDE_FROM_ABI adjacent_transform_view() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_transform_view(_View __base, _Fn __fun) + : __inner_(std::move(__base)), __fun_(std::in_place, std::move(__fun)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __inner_.base(); + } + _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__inner_).base(); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return __iterator<false>(*this, __inner_.begin()); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires range<const _InnerView> && regular_invocable<__apply_n<const _Fn&, _Np>, range_reference_t<const _View>> + { + return __iterator<true>(*this, __inner_.begin()); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() { + if constexpr (common_range<_InnerView>) { + return __iterator<false>(*this, __inner_.end()); + } else { + return __sentinel<false>(__inner_.end()); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires range<const _InnerView> && regular_invocable<__apply_n<const _Fn&, _Np>, range_reference_t<const _View>> + { + if constexpr (common_range<const _InnerView>) { + return __iterator<true>(*this, __inner_.end()); + } else { + return __sentinel<true>(__inner_.end()); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_InnerView> + { + return __inner_.size(); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range<const _InnerView> + { + return __inner_.size(); + } +}; + +template <forward_range _View, move_constructible _Fn, size_t _Np> + requires view<_View> && (_Np > 0) && is_object_v<_Fn> && + regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> && + __referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>> +template <bool _Const> +class adjacent_transform_view<_View, _Fn, _Np>::__iterator { + friend adjacent_transform_view; + + using _Parent _LIBCPP_NODEBUG = __maybe_const<_Const, adjacent_transform_view>; + using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; + + _Parent* __parent_ = nullptr; + __inner_iterator<_Const> __inner_; + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, __inner_iterator<_Const> __inner) + : __parent_(std::addressof(__parent)), __inner_(std::move(__inner)) {} + + static consteval auto __get_iterator_category() { + using _Cat = iterator_traits<iterator_t<_Base>>::iterator_category; + if constexpr (!is_reference_v< + invoke_result_t<__apply_n<__maybe_const<_Const, _Fn>&, _Np>, range_reference_t<_Base>>>) + return input_iterator_tag{}; + else if constexpr (derived_from<_Cat, random_access_iterator_tag>) + return random_access_iterator_tag{}; + else if constexpr (derived_from<_Cat, bidirectional_iterator_tag>) + return bidirectional_iterator_tag{}; + else if constexpr (derived_from<_Cat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + template <size_t... _Is> + static consteval bool __noexcept_dereference(index_sequence<_Is...>) { + return noexcept(std::invoke( + std::declval<__maybe_const<_Const, _Fn>&>(), ((void)_Is, *std::declval<iterator_t<_Base> const&>())...)); + } + +public: + using iterator_category = decltype(__get_iterator_category()); + using iterator_concept = typename __inner_iterator<_Const>::iterator_concept; + using value_type = + remove_cvref_t<invoke_result_t<__apply_n<__maybe_const<_Const, _Fn>&, _Np>, range_reference_t<_Base>>>; + 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<__inner_iterator<false>, __inner_iterator<true>> + : __parent_(__i.__parent_), __inner_(std::move(__i.__inner_)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const + noexcept(__noexcept_dereference(make_index_sequence<_Np>{})) { + return std::apply( + [&](const auto&... __iters) -> decltype(auto) { return std::invoke(*__parent_->__fun_, *__iters...); }, + __adjacent_view_iter_access::__get_current(__inner_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + ++__inner_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { + 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( + [&](const auto&... __iters) -> decltype(auto) { return std::invoke(*__parent_->__fun_, __iters[__n]...); }, + __adjacent_view_iter_access::__get_current(__inner_)); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { + return __x.__inner_ == __y.__inner_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__inner_ < __y.__inner_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__inner_ > __y.__inner_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__inner_ <= __y.__inner_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__inner_ >= __y.__inner_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> && three_way_comparable<__inner_iterator<_Const>> + { + 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<__inner_iterator<_Const>, __inner_iterator<_Const>> + { + return __x.__inner_ - __y.__inner_; + } +}; + +template <forward_range _View, move_constructible _Fn, size_t _Np> + requires view<_View> && (_Np > 0) && is_object_v<_Fn> && + regular_invocable<__apply_n<_Fn&, _Np>, range_reference_t<_View>> && + __referenceable<invoke_result_t<__apply_n<_Fn&, _Np>, range_reference_t<_View>>> +template <bool _Const> +class adjacent_transform_view<_View, _Fn, _Np>::__sentinel { + friend adjacent_transform_view; + + __inner_sentinel<_Const> __inner_; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(__inner_sentinel<_Const> __inner) + : __inner_(std::move(__inner)) {} + +public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __i) + requires _Const && convertible_to<__inner_sentinel<false>, __inner_sentinel<_Const>> + : __inner_(std::move(__i.__inner_)) {} + + template <bool _OtherConst> + requires sentinel_for<__inner_sentinel<_Const>, __inner_iterator<_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<__inner_sentinel<_Const>, __inner_iterator<_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<__inner_sentinel<_Const>, __inner_iterator<_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 __adjacent_transform { + +template <size_t _Np> +struct __fn : __range_adaptor_closure<__fn<_Np>> { + template <class _Range, class _Fn> + requires(_Np == 0 && forward_range<_Range &&>) + _LIBCPP_HIDE_FROM_ABI static constexpr auto + operator()(_Range&&, _Fn&& __fn) noexcept(noexcept(views::zip_transform(std::forward<_Fn>(__fn)))) + -> decltype(views::zip_transform(std::forward<_Fn>(__fn))) { + return views::zip_transform(std::forward<_Fn>(__fn)); + } + + template <class _Range, class _Fn> + _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range, _Fn&& __fn) noexcept( + noexcept(adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>( + std::forward<_Range>(__range), std::forward<_Fn>(__fn)))) + -> decltype(adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>( + std::forward<_Range>(__range), std::forward<_Fn>(__fn))) { + return adjacent_transform_view<views::all_t<_Range&&>, decay_t<_Fn>, _Np>( + std::forward<_Range>(__range), std::forward<_Fn>(__fn)); + } + + template <class _Fn> + requires constructible_from<decay_t<_Fn>, _Fn> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __f) const + noexcept(is_nothrow_constructible_v<decay_t<_Fn>, _Fn>) { + return __pipeable(std::__bind_back(*this, std::forward<_Fn>(__f))); + } +}; + +} // namespace __adjacent_transform +inline namespace __cpo { +template <size_t _Np> +inline constexpr auto adjacent_transform = __adjacent_transform::__fn<_Np>{}; +inline constexpr auto pairwise_transform = adjacent_transform<2>; +} // namespace __cpo +} // namespace views +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_ADJACENT_TRANSFORM_VIEW_H diff --git a/lib/libcxx/include/__ranges/adjacent_view.h b/lib/libcxx/include/__ranges/adjacent_view.h @@ -0,0 +1,419 @@ +// -*- 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_ADJACENT_VIEW_H +#define _LIBCPP___RANGES_ADJACENT_VIEW_H + +#include <__config> + +#include <__algorithm/min.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/equality_comparable.h> +#include <__cstddef/size_t.h> +#include <__functional/invoke.h> +#include <__functional/operations.h> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> +#include <__iterator/next.h> +#include <__iterator/prev.h> +#include <__ranges/access.h> +#include <__ranges/all.h> +#include <__ranges/concepts.h> +#include <__ranges/empty_view.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/range_adaptor.h> +#include <__ranges/size.h> +#include <__ranges/view_interface.h> +#include <__tuple/tuple_transform.h> +#include <__type_traits/common_type.h> +#include <__type_traits/is_nothrow_constructible.h> +#include <__type_traits/make_unsigned.h> +#include <__type_traits/maybe_const.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/integer_sequence.h> +#include <__utility/move.h> +#include <array> +#include <tuple> + +#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 <forward_range _View, size_t _Np> + requires view<_View> && (_Np > 0) +class adjacent_view : public view_interface<adjacent_view<_View, _Np>> { +private: + _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); + + template <bool> + class __iterator; + + template <bool> + class __sentinel; + + struct __as_sentinel {}; + +public: + _LIBCPP_HIDE_FROM_ABI adjacent_view() + requires default_initializable<_View> + = default; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_view(_View __base) : __base_(std::move(__base)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __base_; + } + _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + requires(!__simple_view<_View>) + { + return __iterator<false>(ranges::begin(__base_), ranges::end(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + requires range<const _View> // LWG4482 This is under-constrained. + { + return __iterator<true>(ranges::begin(__base_), ranges::end(__base_)); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() + requires(!__simple_view<_View>) + { + if constexpr (common_range<_View>) { + return __iterator<false>(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_)); + } else { + return __sentinel<false>(ranges::end(__base_)); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + requires range<const _View> // LWG4482 This is under-constrained. + { + if constexpr (common_range<const _View>) { + return __iterator<true>(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_)); + } else { + return __sentinel<true>(ranges::end(__base_)); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_View> + { + using _ST = decltype(ranges::size(__base_)); + using _CT = common_type_t<_ST, size_t>; + auto __sz = static_cast<_CT>(ranges::size(__base_)); + __sz -= std::min<_CT>(__sz, _Np - 1); + return static_cast<_ST>(__sz); + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range<const _View> + { + using _ST = decltype(ranges::size(__base_)); + using _CT = common_type_t<_ST, size_t>; + auto __sz = static_cast<_CT>(ranges::size(__base_)); + __sz -= std::min<_CT>(__sz, _Np - 1); + return static_cast<_ST>(__sz); + } +}; + +struct __adjacent_view_iter_access { + template <class _Iter> + _LIBCPP_HIDE_FROM_ABI constexpr static auto& __get_current(_Iter& __it) noexcept { + return __it.__current_; + } +}; + +template <forward_range _View, size_t _Np> + requires view<_View> && (_Np > 0) +template <bool _Const> +class adjacent_view<_View, _Np>::__iterator { + friend __adjacent_view_iter_access; + friend adjacent_view; + using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; + array<iterator_t<_Base>, _Np> __current_ = array<iterator_t<_Base>, _Np>(); + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(iterator_t<_Base> __first, sentinel_t<_Base> __last) { + __current_[0] = __first; + for (size_t __i = 1; __i < _Np; ++__i) { + __current_[__i] = ranges::next(__current_[__i - 1], 1, __last); + } + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__as_sentinel, iterator_t<_Base> __first, iterator_t<_Base> __last) { + if constexpr (!bidirectional_range<_Base>) { + __current_.fill(__last); + } else { + __current_[_Np - 1] = __last; + for (int __i = static_cast<int>(_Np) - 2; __i >= 0; --__i) { + __current_[__i] = ranges::prev(__current_[__i + 1], 1, __first); + } + } + } + + template <class _Iter, size_t... _Is> + _LIBCPP_HIDE_FROM_ABI explicit constexpr __iterator(_Iter&& __i, index_sequence<_Is...>) + : __current_{std::move(__i.__current_[_Is])...} {} + + static consteval auto __get_iterator_concept() { + if constexpr (random_access_range<_Base>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_range<_Base>) + return bidirectional_iterator_tag{}; + else + return forward_iterator_tag{}; + } + + template <class _Tp, size_t _Index> + using __always _LIBCPP_NODEBUG = _Tp; + + template <class _Tp, size_t... _Is> + static auto __repeat_tuple_helper(index_sequence<_Is...>) -> tuple<__always<_Tp, _Is>...>; + +public: + using iterator_category = input_iterator_tag; + using iterator_concept = decltype(__get_iterator_concept()); + using value_type = decltype(__repeat_tuple_helper<range_value_t<_Base>>(make_index_sequence<_Np>{})); + 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<iterator_t<_View>, iterator_t<const _View>> + : __iterator(std::move(__i), make_index_sequence<_Np>{}) {} + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { + return std::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_); + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { + for (auto& __i : __current_) { + ++__i; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) { + auto __tmp = *this; + ++*this; + return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--() + requires bidirectional_range<_Base> + { + for (auto& __i : __current_) { + --__i; + } + 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> + { + for (auto& __i : __current_) { + __i += __x; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x) + requires random_access_range<_Base> + { + for (auto& __i : __current_) { + __i -= __x; + } + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const + requires random_access_range<_Base> + { + return std::__tuple_transform([&](auto& __i) -> decltype(auto) { return __i[__n]; }, __current_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { + return __x.__current_.back() == __y.__current_.back(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __x.__current_.back() < __y.__current_.back(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return __y < __x; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__y < __x); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> + { + return !(__x < __y); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y) + requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>> + { + return __x.__current_.back() <=> __y.__current_.back(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n) + requires random_access_range<_Base> + { + auto __r = __i; + __r += __n; + return __r; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i) + requires random_access_range<_Base> + { + return __i + __n; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n) + requires random_access_range<_Base> + { + auto __r = __i; + __r -= __n; + return __r; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) + requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>> + { + return __x.__current_.back() - __y.__current_.back(); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept( + noexcept(ranges::iter_move(std::declval<const iterator_t<_Base>&>())) && + is_nothrow_move_constructible_v<range_rvalue_reference_t<_Base>>) { + return std::__tuple_transform(ranges::iter_move, __i.__current_); + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr void iter_swap(const __iterator& __l, const __iterator& __r) noexcept( + noexcept(ranges::iter_swap(std::declval<iterator_t<_Base>>(), std::declval<iterator_t<_Base>>()))) + requires indirectly_swappable<iterator_t<_Base>> + { + for (size_t __i = 0; __i < _Np; ++__i) { + ranges::iter_swap(__l.__current_[__i], __r.__current_[__i]); + } + } +}; + +template <forward_range _View, size_t _Np> + requires view<_View> && (_Np > 0) +template <bool _Const> +class adjacent_view<_View, _Np>::__sentinel { + friend adjacent_view; + using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>; + sentinel_t<_Base> __end_ = sentinel_t<_Base>(); + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(sentinel_t<_Base> __end) { __end_ = std::move(__end); } + +public: + _LIBCPP_HIDE_FROM_ABI __sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __i) + requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>> + : __end_(std::move(__i.__end_)) {} + + template <bool _OtherConst> + requires sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) { + return __x.__current_.back() == __y.__end_; + } + + template <bool _OtherConst> + requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) { + return __x.__current_.back() - __y.__end_; + } + + template <bool _OtherConst> + requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<__maybe_const<_OtherConst, _View>>> + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _View>> + operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) { + return __y.__end_ - __x.__current_.back(); + } +}; + +template <class _View, size_t _Np> +constexpr bool enable_borrowed_range<adjacent_view<_View, _Np>> = enable_borrowed_range<_View>; + +namespace views { +namespace __adjacent { + +template <size_t _Np> +struct __fn : __range_adaptor_closure<__fn<_Np>> { + template <class _Range> + requires(_Np == 0 && forward_range<_Range &&>) + _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&&) noexcept { + return empty_view<tuple<>>{}; + } + + template <class _Ranges> + _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Ranges&& __range) noexcept( + noexcept(adjacent_view<views::all_t<_Ranges&&>, _Np>(std::forward<_Ranges>(__range)))) + -> decltype(adjacent_view<views::all_t<_Ranges&&>, _Np>(std::forward<_Ranges>(__range))) { + return adjacent_view<views::all_t<_Ranges&&>, _Np>(std::forward<_Ranges>(__range)); + } +}; + +} // namespace __adjacent +inline namespace __cpo { +template <size_t _Np> +inline constexpr auto adjacent = __adjacent::__fn<_Np>{}; +inline constexpr auto pairwise = adjacent<2>; +} // namespace __cpo +} // namespace views +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_ADJACENT_VIEW_H diff --git a/lib/libcxx/include/__ranges/as_rvalue_view.h b/lib/libcxx/include/__ranges/as_rvalue_view.h @@ -48,27 +48,27 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit as_rvalue_view(_View __base) : __base_(std::move(__base)) {} - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!__simple_view<_View>) { return move_iterator(ranges::begin(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _View> { return move_iterator(ranges::begin(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!__simple_view<_View>) { if constexpr (common_range<_View>) { @@ -78,7 +78,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _View> { if constexpr (common_range<const _View>) { @@ -88,13 +88,13 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { return ranges::size(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _View> { return ranges::size(__base_); @@ -117,7 +117,7 @@ struct __fn : __range_adaptor_closure<__fn> { return /*---------------------------------*/ as_rvalue_view(std::forward<_Range>(__range)); } - template <class _Range> + template <input_range _Range> requires same_as<range_rvalue_reference_t<_Range>, range_reference_t<_Range>> [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Range&& __range) noexcept(noexcept(views::all(std::forward<_Range>(__range)))) diff --git a/lib/libcxx/include/__ranges/chunk_by_view.h b/lib/libcxx/include/__ranges/chunk_by_view.h @@ -100,17 +100,17 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_by_view(_View __base, _Pred __pred) : __base_(std::move(__base)), __pred_(in_place, std::move(__pred)) {} - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { // Note: this duplicates a check in `optional` but provides a better error message. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate."); @@ -122,7 +122,7 @@ public: return {*this, std::move(__first), *__cached_begin_}; } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() { if constexpr (common_range<_View>) { return __iterator{*this, ranges::end(__base_), ranges::end(__base_)}; } else { @@ -155,7 +155,7 @@ public: _LIBCPP_HIDE_FROM_ABI __iterator() = default; - _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { // If the iterator is at end, this would return an empty range which can be checked by the calling code and doesn't // necessarily lead to a bad access. _LIBCPP_ASSERT_PEDANTIC(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator."); diff --git a/lib/libcxx/include/__ranges/common_view.h b/lib/libcxx/include/__ranges/common_view.h @@ -56,16 +56,16 @@ public: return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { if constexpr (random_access_range<_View> && sized_range<_View>) return ranges::begin(__base_); else return common_iterator<iterator_t<_View>, sentinel_t<_View>>(ranges::begin(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _View> { if constexpr (random_access_range<const _View> && sized_range<const _View>) @@ -74,14 +74,14 @@ public: return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::begin(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() { if constexpr (random_access_range<_View> && sized_range<_View>) return ranges::begin(__base_) + ranges::size(__base_); else return common_iterator<iterator_t<_View>, sentinel_t<_View>>(ranges::end(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _View> { if constexpr (random_access_range<const _View> && sized_range<const _View>) @@ -90,13 +90,13 @@ public: return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::end(__base_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { return ranges::size(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _View> { return ranges::size(__base_); diff --git a/lib/libcxx/include/__ranges/drop_view.h b/lib/libcxx/include/__ranges/drop_view.h @@ -80,14 +80,14 @@ public: _LIBCPP_ASSERT_UNCATEGORIZED(__count_ >= 0, "count must be greater than or equal to zero."); } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!(__simple_view<_View> && random_access_range<const _View> && sized_range<const _View>)) { if constexpr (random_access_range<_View> && sized_range<_View>) { @@ -104,20 +104,20 @@ public: return __tmp; } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires random_access_range<const _View> && sized_range<const _View> { const auto __dist = std::min(ranges::distance(__base_), __count_); return ranges::begin(__base_) + __dist; } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!__simple_view<_View>) { return ranges::end(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _View> { return ranges::end(__base_); @@ -129,13 +129,13 @@ public: return __s < __c ? 0 : __s - __c; } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { return __size(*this); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _View> { return __size(*this); diff --git a/lib/libcxx/include/__ranges/drop_while_view.h b/lib/libcxx/include/__ranges/drop_while_view.h @@ -57,17 +57,17 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr _LIBCPP_EXPLICIT_SINCE_CXX23 drop_while_view(_View __base, _Pred __pred) : __base_(std::move(__base)), __pred_(std::in_place, std::move(__pred)) {} - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { // Note: this duplicates a check in `optional` but provides a better error message. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), @@ -83,7 +83,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() { return ranges::end(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() { return ranges::end(__base_); } private: _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View(); diff --git a/lib/libcxx/include/__ranges/elements_of.h b/lib/libcxx/include/__ranges/elements_of.h @@ -0,0 +1,49 @@ +// -*- 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_ELEMENTS_OF_H +#define _LIBCPP___RANGES_ELEMENTS_OF_H + +#include <__config> +#include <__cstddef/byte.h> +#include <__memory/allocator.h> +#include <__ranges/concepts.h> +#include <__utility/forward.h> + +#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 <range _Range, class _Allocator = allocator<byte>> +struct elements_of { + _LIBCPP_NO_UNIQUE_ADDRESS _Range range; + _LIBCPP_NO_UNIQUE_ADDRESS _Allocator allocator = _Allocator(); +}; + +template <class _Range, class _Allocator = allocator<byte>> +elements_of(_Range&&, _Allocator = _Allocator()) -> elements_of<_Range&&, _Allocator>; + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_ELEMENTS_OF_H diff --git a/lib/libcxx/include/__ranges/empty_view.h b/lib/libcxx/include/__ranges/empty_view.h @@ -29,11 +29,11 @@ template <class _Tp> requires is_object_v<_Tp> class empty_view : public view_interface<empty_view<_Tp>> { public: - _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* begin() noexcept { return nullptr; } - _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* end() noexcept { return nullptr; } - _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* data() noexcept { return nullptr; } - _LIBCPP_HIDE_FROM_ABI static constexpr size_t size() noexcept { return 0; } - _LIBCPP_HIDE_FROM_ABI static constexpr bool empty() noexcept { return true; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* begin() noexcept { return nullptr; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* end() noexcept { return nullptr; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr _Tp* data() noexcept { return nullptr; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t size() noexcept { return 0; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool empty() noexcept { return true; } }; template <class _Tp> diff --git a/lib/libcxx/include/__ranges/filter_view.h b/lib/libcxx/include/__ranges/filter_view.h @@ -76,16 +76,16 @@ public: : __base_(std::move(__base)), __pred_(in_place, std::move(__pred)) {} template <class _Vp = _View> - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_Vp> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr _Pred const& pred() const { return *__pred_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Pred const& pred() const { return *__pred_; } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { // Note: this duplicates a check in `optional` but provides a better error message. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate."); @@ -99,7 +99,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() { if constexpr (common_range<_View>) return __iterator{*this, ranges::end(__base_)}; else @@ -148,10 +148,10 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr __iterator(filter_view& __parent, iterator_t<_View> __current) : __current_(std::move(__current)), __parent_(std::addressof(__parent)) {} - _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; } - _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> const& base() const& noexcept { return __current_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); } - _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View> operator*() const { return *__current_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View> operator*() const { return *__current_; } _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> operator->() const requires __has_arrow<iterator_t<_View>> && copyable<iterator_t<_View>> { @@ -194,7 +194,7 @@ public: return __x.__current_ == __y.__current_; } - _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View> iter_move(__iterator const& __it) noexcept(noexcept(ranges::iter_move(__it.__current_))) { return ranges::iter_move(__it.__current_); } @@ -218,7 +218,7 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(filter_view& __parent) : __end_(ranges::end(__parent.__base_)) {} - _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(__iterator const& __x, __sentinel const& __y) { return __x.__current_ == __y.__end_; diff --git a/lib/libcxx/include/__ranges/iota_view.h b/lib/libcxx/include/__ranges/iota_view.h @@ -30,6 +30,7 @@ #include <__ranges/movable_box.h> #include <__ranges/view_interface.h> #include <__type_traits/conditional.h> +#include <__type_traits/decay.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/make_unsigned.h> #include <__type_traits/type_identity.h> @@ -57,11 +58,17 @@ struct __get_wider_signed { return type_identity<int>{}; else if constexpr (sizeof(_Int) < sizeof(long)) return type_identity<long>{}; - else + else if constexpr (sizeof(_Int) < sizeof(long long)) return type_identity<long long>{}; - - static_assert( - sizeof(_Int) <= sizeof(long long), "Found integer-like type that is bigger than largest integer like type."); +# if _LIBCPP_HAS_INT128 + else if constexpr (sizeof(_Int) <= sizeof(__int128)) + return type_identity<__int128>{}; +# else + else if constexpr (sizeof(_Int) <= sizeof(long long)) + return type_identity<long long>{}; +# endif + else + static_assert(false, "Found integer-like type that is bigger than the largest integer like type."); } using type = typename decltype(__call())::type; @@ -125,7 +132,8 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> { _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(_Start __value) : __value_(std::move(__value)) {} - _LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const noexcept(is_nothrow_copy_constructible_v<_Start>) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator*() const + noexcept(is_nothrow_copy_constructible_v<_Start>) { return __value_; } @@ -189,7 +197,7 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> { return *this; } - _LIBCPP_HIDE_FROM_ABI constexpr _Start operator[](difference_type __n) const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Start operator[](difference_type __n) const requires __advanceable<_Start> { return _Start(__value_ + __n); @@ -231,27 +239,28 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> { return __x.__value_ <=> __y.__value_; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) requires __advanceable<_Start> { __i += __n; return __i; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) requires __advanceable<_Start> { return __i + __n; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) requires __advanceable<_Start> { __i -= __n; return __i; } - _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __iterator& __x, const __iterator& __y) requires __advanceable<_Start> { if constexpr (__integer_like<_Start>) { @@ -282,14 +291,14 @@ class iota_view : public view_interface<iota_view<_Start, _BoundSentinel>> { return __x.__value_ == __y.__bound_sentinel_; } - _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start> operator-(const __iterator& __x, const __sentinel& __y) requires sized_sentinel_for<_BoundSentinel, _Start> { return __x.__value_ - __y.__bound_sentinel_; } - _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr iter_difference_t<_Start> operator-(const __sentinel& __x, const __iterator& __y) requires sized_sentinel_for<_BoundSentinel, _Start> { @@ -329,24 +338,24 @@ public: requires(!same_as<_Start, _BoundSentinel> && !same_as<_BoundSentinel, unreachable_sentinel_t>) : iota_view(std::move(__first.__value_), std::move(__last.__bound_sentinel_)) {} - _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator{__value_}; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator{__value_}; } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const { if constexpr (same_as<_BoundSentinel, unreachable_sentinel_t>) return unreachable_sentinel; else return __sentinel{__bound_sentinel_}; } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const requires same_as<_Start, _BoundSentinel> { return __iterator{__bound_sentinel_}; } - _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __value_ == __bound_sentinel_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const { return __value_ == __bound_sentinel_; } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires(same_as<_Start, _BoundSentinel> && __advanceable<_Start>) || (integral<_Start> && integral<_BoundSentinel>) || sized_sentinel_for<_BoundSentinel, _Start> { @@ -374,14 +383,15 @@ namespace views { namespace __iota { struct __fn { template <class _Start> - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const - noexcept(noexcept(ranges::iota_view(std::forward<_Start>(__start)))) - -> decltype(ranges::iota_view(std::forward<_Start>(__start))) { - return ranges::iota_view(std::forward<_Start>(__start)); + requires(requires(_Start __s) { ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__s)); }) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start) const + noexcept(noexcept(ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__start)))) { + return ranges::iota_view<decay_t<_Start>>(std::forward<_Start>(__start)); } template <class _Start, class _BoundSentinel> - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Start&& __start, _BoundSentinel&& __bound_sentinel) const noexcept( + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto + operator()(_Start&& __start, _BoundSentinel&& __bound_sentinel) const noexcept( noexcept(ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel)))) -> decltype(ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel))) { return ranges::iota_view(std::forward<_Start>(__start), std::forward<_BoundSentinel>(__bound_sentinel)); @@ -392,6 +402,15 @@ struct __fn { inline namespace __cpo { inline constexpr auto iota = __iota::__fn{}; } // namespace __cpo + +# if _LIBCPP_STD_VER >= 26 + +inline constexpr auto indices = [] [[nodiscard]] (__integer_like auto __size) static { + return ranges::views::iota(decltype(__size){}, __size); +}; + +# endif + } // namespace views } // namespace ranges diff --git a/lib/libcxx/include/__ranges/owning_view.h b/lib/libcxx/include/__ranges/owning_view.h @@ -49,52 +49,52 @@ public: _LIBCPP_HIDE_FROM_ABI owning_view(owning_view&&) = default; _LIBCPP_HIDE_FROM_ABI owning_view& operator=(owning_view&&) = default; - _LIBCPP_HIDE_FROM_ABI constexpr _Rp& base() & noexcept { return __r_; } - _LIBCPP_HIDE_FROM_ABI constexpr const _Rp& base() const& noexcept { return __r_; } - _LIBCPP_HIDE_FROM_ABI constexpr _Rp&& base() && noexcept { return std::move(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Rp&& base() const&& noexcept { return std::move(__r_); } - - _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Rp> begin() { return ranges::begin(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Rp> end() { return ranges::end(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Rp& base() & noexcept { return __r_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Rp& base() const& noexcept { return __r_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Rp&& base() && noexcept { return std::move(__r_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Rp&& base() const&& noexcept { return std::move(__r_); } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Rp> begin() { return ranges::begin(__r_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Rp> end() { return ranges::end(__r_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _Rp> { return ranges::begin(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _Rp> { return ranges::end(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr bool empty() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() requires requires { ranges::empty(__r_); } { return ranges::empty(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const requires requires { ranges::empty(__r_); } { return ranges::empty(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_Rp> { return ranges::size(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _Rp> { return ranges::size(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto data() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() requires contiguous_range<_Rp> { return ranges::data(__r_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto data() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires contiguous_range<const _Rp> { return ranges::data(__r_); diff --git a/lib/libcxx/include/__ranges/ref_view.h b/lib/libcxx/include/__ranges/ref_view.h @@ -51,24 +51,24 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr ref_view(_Tp&& __t) : __range_(std::addressof(static_cast<_Range&>(std::forward<_Tp>(__t)))) {} - _LIBCPP_HIDE_FROM_ABI constexpr _Range& base() const { return *__range_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Range& base() const { return *__range_; } - _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Range> begin() const { return ranges::begin(*__range_); } - _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Range> end() const { return ranges::end(*__range_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Range> begin() const { return ranges::begin(*__range_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Range> end() const { return ranges::end(*__range_); } - _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const requires requires { ranges::empty(*__range_); } { return ranges::empty(*__range_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<_Range> { return ranges::size(*__range_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto data() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires contiguous_range<_Range> { return ranges::data(*__range_); diff --git a/lib/libcxx/include/__ranges/repeat_view.h b/lib/libcxx/include/__ranges/repeat_view.h @@ -108,17 +108,21 @@ public: __bound_ >= 0, "The behavior is undefined if Bound is not unreachable_sentinel_t and bound is negative"); } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { return __iterator(std::addressof(*__value_)); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() const { + return __iterator(std::addressof(*__value_)); + } - _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __iterator end() const requires(!same_as<_Bound, unreachable_sentinel_t>) { return __iterator(std::addressof(*__value_), __bound_); } - _LIBCPP_HIDE_FROM_ABI constexpr unreachable_sentinel_t end() const noexcept { return unreachable_sentinel; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr unreachable_sentinel_t end() const noexcept { + return unreachable_sentinel; + } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires(!same_as<_Bound, unreachable_sentinel_t>) { return std::__to_unsigned_like(__bound_); @@ -152,7 +156,7 @@ public: _LIBCPP_HIDE_FROM_ABI __iterator() = default; - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const noexcept { return *__value_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const noexcept { return *__value_; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { ++__current_; @@ -192,7 +196,9 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](difference_type __n) const noexcept { return *(*this + __n); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator[](difference_type __n) const noexcept { + return *(*this + __n); + } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) { return __x.__current_ == __y.__current_; @@ -202,22 +208,23 @@ public: return __x.__current_ <=> __y.__current_; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(__iterator __i, difference_type __n) { __i += __n; return __i; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, __iterator __i) { __i += __n; return __i; } - _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(__iterator __i, difference_type __n) { __i -= __n; return __i; } - _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr difference_type + operator-(const __iterator& __x, const __iterator& __y) { return static_cast<difference_type>(__x.__current_) - static_cast<difference_type>(__y.__current_); } diff --git a/lib/libcxx/include/__ranges/single_view.h b/lib/libcxx/include/__ranges/single_view.h @@ -63,21 +63,21 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr explicit single_view(in_place_t, _Args&&... __args) : __value_{in_place, std::forward<_Args>(__args)...} {} - _LIBCPP_HIDE_FROM_ABI constexpr _Tp* begin() noexcept { return data(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* begin() noexcept { return data(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* begin() const noexcept { return data(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* begin() const noexcept { return data(); } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp* end() noexcept { return data() + 1; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* end() noexcept { return data() + 1; } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* end() const noexcept { return data() + 1; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* end() const noexcept { return data() + 1; } - _LIBCPP_HIDE_FROM_ABI static constexpr bool empty() noexcept { return false; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr bool empty() noexcept { return false; } - _LIBCPP_HIDE_FROM_ABI static constexpr size_t size() noexcept { return 1; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr size_t size() noexcept { return 1; } - _LIBCPP_HIDE_FROM_ABI constexpr _Tp* data() noexcept { return __value_.operator->(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp* data() noexcept { return __value_.operator->(); } - _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* data() const noexcept { return __value_.operator->(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp* data() const noexcept { return __value_.operator->(); } }; template <class _Tp> diff --git a/lib/libcxx/include/__ranges/take_view.h b/lib/libcxx/include/__ranges/take_view.h @@ -75,15 +75,15 @@ public: _LIBCPP_ASSERT_UNCATEGORIZED(__count >= 0, "count has to be greater than or equal to zero"); } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& requires copy_constructible<_View> { return __base_; } - _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!__simple_view<_View>) { if constexpr (sized_range<_View>) { @@ -99,7 +99,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range<const _View> { if constexpr (sized_range<const _View>) { @@ -115,7 +115,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!__simple_view<_View>) { if constexpr (sized_range<_View>) { @@ -129,7 +129,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto end() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range<const _View> { if constexpr (sized_range<const _View>) { @@ -143,14 +143,14 @@ public: } } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_View> { auto __n = ranges::size(__base_); return ranges::min(__n, static_cast<decltype(__n)>(__count_)); } - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range<const _View> { auto __n = ranges::size(__base_); @@ -178,7 +178,7 @@ public: requires _Const && convertible_to<sentinel_t<_View>, sentinel_t<_Base>> : __end_(std::move(__s.__end_)) {} - _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Base> base() const { return __end_; } _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const _Iter<_Const>& __lhs, const __sentinel& __rhs) { return __lhs.count() == 0 || __lhs.base() == __rhs.__end_; diff --git a/lib/libcxx/include/__ranges/transform_view.h b/lib/libcxx/include/__ranges/transform_view.h @@ -13,7 +13,6 @@ #include <__compare/three_way_comparable.h> #include <__concepts/constructible.h> #include <__concepts/convertible_to.h> -#include <__concepts/copyable.h> #include <__concepts/derived_from.h> #include <__concepts/equality_comparable.h> #include <__concepts/invocable.h> @@ -64,7 +63,7 @@ concept __regular_invocable_with_range_ref = regular_invocable<_Fn, range_refere template <class _View, class _Fn> concept __transform_view_constraints = view<_View> && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_View>> && - __is_referenceable_v<invoke_result_t<_Fn&, range_reference_t<_View>>>; + __referenceable<invoke_result_t<_Fn&, range_reference_t<_View>>>; # if _LIBCPP_STD_VER >= 23 template <input_range _View, move_constructible _Fn> diff --git a/lib/libcxx/include/__ranges/view_interface.h b/lib/libcxx/include/__ranges/view_interface.h @@ -87,35 +87,35 @@ public: } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr auto data() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() requires contiguous_iterator<iterator_t<_D2>> { return std::to_address(ranges::begin(__derived())); } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr auto data() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires range<const _D2> && contiguous_iterator<iterator_t<const _D2>> { return std::to_address(ranges::begin(__derived())); } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr auto size() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires forward_range<_D2> && sized_sentinel_for<sentinel_t<_D2>, iterator_t<_D2>> { return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived())); } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires forward_range<const _D2> && sized_sentinel_for<sentinel_t<const _D2>, iterator_t<const _D2>> { return std::__to_unsigned_like(ranges::end(__derived()) - ranges::begin(__derived())); } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() requires forward_range<_D2> { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( @@ -124,7 +124,7 @@ public: } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) front() const requires forward_range<const _D2> { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( @@ -133,7 +133,7 @@ public: } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() requires bidirectional_range<_D2> && common_range<_D2> { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( @@ -142,7 +142,7 @@ public: } template <class _D2 = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() const + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) back() const requires bidirectional_range<const _D2> && common_range<const _D2> { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( @@ -151,12 +151,12 @@ public: } template <random_access_range _RARange = _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) { return ranges::begin(__derived())[__index]; } template <random_access_range _RARange = const _Derived> - _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const { return ranges::begin(__derived())[__index]; } }; diff --git a/lib/libcxx/include/__ranges/zip_transform_view.h b/lib/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/lib/libcxx/include/__ranges/zip_view.h b/lib/libcxx/include/__ranges/zip_view.h @@ -31,6 +31,7 @@ #include <__ranges/enable_borrowed_range.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> +#include <__tuple/tuple_transform.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/make_unsigned.h> #include <__utility/declval.h> @@ -59,15 +60,6 @@ concept __zip_is_common = ((random_access_range<_Ranges> && ...) && (sized_range<_Ranges> && ...)); template <class _Fun, class _Tuple> -_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_transform(_Fun&& __f, _Tuple&& __tuple) { - return std::apply( - [&]<class... _Types>(_Types&&... __elements) { - return tuple<invoke_result_t<_Fun&, _Types>...>(std::invoke(__f, std::forward<_Types>(__elements))...); - }, - std::forward<_Tuple>(__tuple)); -} - -template <class _Fun, class _Tuple> _LIBCPP_HIDE_FROM_ABI constexpr void __tuple_for_each(_Fun&& __f, _Tuple&& __tuple) { std::apply( [&]<class... _Types>(_Types&&... __elements) { @@ -145,24 +137,24 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr auto begin() requires(!(__simple_view<_Views> && ...)) { - return __iterator<false>(ranges::__tuple_transform(ranges::begin, __views_)); + return __iterator<false>(std::__tuple_transform(ranges::begin, __views_)); } _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires(range<const _Views> && ...) { - return __iterator<true>(ranges::__tuple_transform(ranges::begin, __views_)); + return __iterator<true>(std::__tuple_transform(ranges::begin, __views_)); } _LIBCPP_HIDE_FROM_ABI constexpr auto end() requires(!(__simple_view<_Views> && ...)) { if constexpr (!__zip_is_common<_Views...>) { - return __sentinel<false>(ranges::__tuple_transform(ranges::end, __views_)); + return __sentinel<false>(std::__tuple_transform(ranges::end, __views_)); } else if constexpr ((random_access_range<_Views> && ...)) { return begin() + iter_difference_t<__iterator<false>>(size()); } else { - return __iterator<false>(ranges::__tuple_transform(ranges::end, __views_)); + return __iterator<false>(std::__tuple_transform(ranges::end, __views_)); } } @@ -170,11 +162,11 @@ public: requires(range<const _Views> && ...) { if constexpr (!__zip_is_common<const _Views...>) { - return __sentinel<true>(ranges::__tuple_transform(ranges::end, __views_)); + return __sentinel<true>(std::__tuple_transform(ranges::end, __views_)); } else if constexpr ((random_access_range<const _Views> && ...)) { return begin() + iter_difference_t<__iterator<true>>(size()); } else { - return __iterator<true>(ranges::__tuple_transform(ranges::end, __views_)); + return __iterator<true>(std::__tuple_transform(ranges::end, __views_)); } } @@ -186,7 +178,7 @@ public: using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>; return ranges::min({_CT(__sizes)...}); }, - ranges::__tuple_transform(ranges::size, __views_)); + std::__tuple_transform(ranges::size, __views_)); } _LIBCPP_HIDE_FROM_ABI constexpr auto size() const @@ -197,7 +189,7 @@ public: using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>; return ranges::min({_CT(__sizes)...}); }, - ranges::__tuple_transform(ranges::size, __views_)); + std::__tuple_transform(ranges::size, __views_)); } }; @@ -235,6 +227,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 +254,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...>()); @@ -268,7 +268,7 @@ public: : __current_(std::move(__i.__current_)) {} _LIBCPP_HIDE_FROM_ABI constexpr auto operator*() const { - return ranges::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_); + return std::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_); } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { @@ -318,7 +318,7 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr auto operator[](difference_type __n) const requires __zip_all_random_access<_Const, _Views...> { - return ranges::__tuple_transform( + return std::__tuple_transform( [&]<class _Iter>(_Iter& __i) -> decltype(auto) { return __i[iter_difference_t<_Iter>(__n)]; }, __current_); } @@ -377,7 +377,7 @@ public: _LIBCPP_HIDE_FROM_ABI friend constexpr auto iter_move(const __iterator& __i) noexcept( (noexcept(ranges::iter_move(std::declval<const iterator_t<__maybe_const<_Const, _Views>>&>())) && ...) && (is_nothrow_move_constructible_v<range_rvalue_reference_t<__maybe_const<_Const, _Views>>> && ...)) { - return ranges::__tuple_transform(ranges::iter_move, __i.__current_); + return std::__tuple_transform(ranges::iter_move, __i.__current_); } _LIBCPP_HIDE_FROM_ABI friend constexpr void iter_swap(const __iterator& __l, const __iterator& __r) noexcept( diff --git a/lib/libcxx/include/__split_buffer b/lib/libcxx/include/__split_buffer @@ -13,10 +13,12 @@ #include <__algorithm/max.h> #include <__algorithm/move.h> #include <__algorithm/move_backward.h> +#include <__assert> #include <__config> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> +#include <__memory/addressof.h> #include <__memory/allocate_at_least.h> #include <__memory/allocator.h> #include <__memory/allocator_traits.h> @@ -28,11 +30,9 @@ #include <__type_traits/integral_constant.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> -#include <__type_traits/is_replaceable.h> #include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_destructible.h> #include <__type_traits/is_trivially_relocatable.h> -#include <__type_traits/remove_reference.h> #include <__utility/forward.h> #include <__utility/move.h> @@ -45,25 +45,430 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -// __split_buffer allocates a contiguous chunk of memory and stores objects in the range [__begin_, __end_). -// It has uninitialized memory in the ranges [__first_, __begin_) and [__end_, __cap_). That allows -// it to grow both in the front and back without having to move the data. +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +class __split_buffer; + +template <class _SplitBuffer, class _Tp, class _Allocator> +class __split_buffer_pointer_layout { +protected: + using value_type = _Tp; + using allocator_type = _Allocator; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename __alloc_traits::size_type; + using difference_type = typename __alloc_traits::difference_type; + using pointer = typename __alloc_traits::pointer; + using const_pointer = typename __alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; + using __sentinel_type _LIBCPP_NODEBUG = pointer; -template <class _Tp, class _Allocator = allocator<_Tp> > -struct __split_buffer { public: - using value_type = _Tp; - using allocator_type = _Allocator; - using __alloc_rr _LIBCPP_NODEBUG = __libcpp_remove_reference_t<allocator_type>; - using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_rr>; - using reference = value_type&; - using const_reference = const value_type&; - using size_type = typename __alloc_traits::size_type; - using difference_type = typename __alloc_traits::difference_type; - using pointer = typename __alloc_traits::pointer; - using const_pointer = typename __alloc_traits::const_pointer; - using iterator = pointer; - using const_iterator = const_pointer; + // Can't be defaulted due to _LIBCPP_COMPRESSED_PAIR not being an aggregate in C++03 and C++11. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer_pointer_layout() : __back_cap_(nullptr) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 + _LIBCPP_HIDE_FROM_ABI explicit __split_buffer_pointer_layout(const allocator_type& __alloc) + : __back_cap_(nullptr), __alloc_(__alloc) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __front_cap() _NOEXCEPT { return __front_cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __front_cap() const _NOEXCEPT { + return __front_cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT { return __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT { return __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + return static_cast<size_type>(__end_ - __begin_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __begin_ == __end_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { + return static_cast<size_type>(__back_cap_ - __front_cap_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __get_allocator() _NOEXCEPT { return __alloc_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __get_allocator() const _NOEXCEPT { + return __alloc_; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type deduction, + // not explicit types. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_sentinel() const _NOEXCEPT { + return __end_; + } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_capacity() const _NOEXCEPT { + return __back_cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_data(pointer __new_first) _NOEXCEPT { + __front_cap_ = __new_first; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, pointer __new_end) _NOEXCEPT { + __begin_ = __new_begin; + __end_ = __new_end; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, size_type __new_size) _NOEXCEPT { + __begin_ = __new_begin; + __end_ = __begin_ + __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __new_end) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__front_cap_ <= __new_end, "__new_end cannot precede __front_cap_"); + __end_ = __new_end; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __new_size) _NOEXCEPT { + __end_ = __begin_ + __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __new_capacity) _NOEXCEPT { + __back_cap_ = __front_cap_ + __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __new_capacity) _NOEXCEPT { + __back_cap_ = __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const _NOEXCEPT { + return static_cast<size_type>(__begin_ - __front_cap_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT { + return static_cast<size_type>(__back_cap_ - __end_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { return *(__end_ - 1); } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return *(__end_ - 1); } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator( + __split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>, + value_type, + allocator_type>& __other) _NOEXCEPT { + std::swap(__front_cap_, __other.__front_cap_); + std::swap(__begin_, __other.__begin_); + std::swap(__back_cap_, __other.__back_cap_); + std::swap(__end_, __other.__end_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer_pointer_layout& __other) _NOEXCEPT { + std::swap(__front_cap_, __other.__front_cap_); + std::swap(__begin_, __other.__begin_); + std::swap(__back_cap_, __other.__back_cap_); + std::swap(__end_, __other.__end_); + std::__swap_allocator(__alloc_, __other.__alloc_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT { + __front_cap_ = nullptr; + __begin_ = nullptr; + __end_ = nullptr; + __back_cap_ = nullptr; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __copy_without_alloc(__split_buffer_pointer_layout const& __other) + _NOEXCEPT_(is_nothrow_copy_assignable<pointer>::value) { + __front_cap_ = __other.__front_cap_; + __begin_ = __other.__begin_; + __end_ = __other.__end_; + __back_cap_ = __other.__back_cap_; + } + +private: + pointer __front_cap_ = nullptr; + pointer __begin_ = nullptr; + pointer __end_ = nullptr; + _LIBCPP_COMPRESSED_PAIR(pointer, __back_cap_, allocator_type, __alloc_); + + template <class, class, class> + friend class __split_buffer_pointer_layout; +}; + +template <class _SplitBuffer, class _Tp, class _Allocator> +class __split_buffer_size_layout { +protected: + using value_type = _Tp; + using allocator_type = _Allocator; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = typename __alloc_traits::size_type; + using difference_type = typename __alloc_traits::difference_type; + using pointer = typename __alloc_traits::pointer; + using const_pointer = typename __alloc_traits::const_pointer; + using iterator = pointer; + using const_iterator = const_pointer; + using __sentinel_type _LIBCPP_NODEBUG = size_type; + +public: + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer_size_layout() = default; + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer_size_layout(const allocator_type& __alloc) + : __alloc_(__alloc) {} + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer __front_cap() _NOEXCEPT { return __front_cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer __front_cap() const _NOEXCEPT { + return __front_cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer begin() _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_pointer begin() const _NOEXCEPT { return __begin_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() _NOEXCEPT { return __begin_ + __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer end() const _NOEXCEPT { return __begin_ + __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __size_ == 0; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const _NOEXCEPT { return __cap_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type& __get_allocator() _NOEXCEPT { return __alloc_; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI allocator_type const& __get_allocator() const _NOEXCEPT { + return __alloc_; + } + + // Returns the sentinel object directly. Should be used in conjunction with automatic type deduction, + // not explicit types. + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_sentinel() const _NOEXCEPT { + return __size_; + } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __sentinel_type __raw_capacity() const _NOEXCEPT { + return __cap_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_data(pointer __new_first) _NOEXCEPT { + __front_cap_ = __new_first; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, pointer __new_end) _NOEXCEPT { + // Size-based __split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + __size_ -= __new_begin - __begin_; + __begin_ = __new_begin; + __set_sentinel(__new_end); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __set_valid_range(pointer __new_begin, size_type __new_size) _NOEXCEPT { + // Size-based __split_buffers track their size directly: we need to explicitly update the size + // when the front is adjusted. + __size_ -= __new_begin - __begin_; + __begin_ = __new_begin; + __set_sentinel(__new_size); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(pointer __new_end) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL(__front_cap_ <= __new_end, "__new_end cannot precede __front_cap_"); + __size_ += __new_end - end(); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_sentinel(size_type __new_size) _NOEXCEPT { + __size_ = __new_size; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(size_type __new_capacity) _NOEXCEPT { + __cap_ = __new_capacity; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __set_capacity(pointer __new_capacity) _NOEXCEPT { + __cap_ = __new_capacity - __begin_; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const _NOEXCEPT { + return static_cast<size_type>(__begin_ - __front_cap_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const _NOEXCEPT { + // `__cap_ - __end_` tells us the total number of spares when in size-mode. We need to remove + // the __front_spare from the count. + return __cap_ - __size_ - __front_spare(); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { return __begin_[__size_ - 1]; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + return __begin_[__size_ - 1]; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator( + __split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>, + value_type, + allocator_type>& __other) _NOEXCEPT { + std::swap(__front_cap_, __other.__front_cap_); + std::swap(__begin_, __other.__begin_); + std::swap(__cap_, __other.__cap_); + std::swap(__size_, __other.__size_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer_size_layout& __other) _NOEXCEPT { + std::swap(__front_cap_, __other.__front_cap_); + std::swap(__begin_, __other.__begin_); + std::swap(__cap_, __other.__cap_); + std::swap(__size_, __other.__size_); + std::__swap_allocator(__alloc_, __other.__alloc_); + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __reset() _NOEXCEPT { + __front_cap_ = nullptr; + __begin_ = nullptr; + __size_ = 0; + __cap_ = 0; + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __copy_without_alloc(__split_buffer_size_layout const& __other) + _NOEXCEPT_(is_nothrow_copy_assignable<pointer>::value) { + __front_cap_ = __other.__front_cap_; + __begin_ = __other.__begin_; + __cap_ = __other.__cap_; + __size_ = __other.__size_; + } + +private: + pointer __front_cap_ = nullptr; + pointer __begin_ = nullptr; + size_type __size_ = 0; + size_type __cap_ = 0; + _LIBCPP_NO_UNIQUE_ADDRESS allocator_type __alloc_; + + template <class, class, class> + friend class __split_buffer_size_layout; +}; + +// `__split_buffer` is a contiguous array data structure. It may hold spare capacity at both ends of +// the sequence. This allows for a `__split_buffer` to grow from both the front and the back without +// relocating its contents until it runs out of room. This characteristic sets it apart from +// `std::vector`, which only holds spare capacity at its end. As such, `__split_buffer` is useful +// for implementing both `std::vector` and `std::deque`. +// +// The sequence is stored as a contiguous chunk of memory delimited by the following "pointers" (`o` denotes +// uninitialized memory and `x` denotes a valid object): +// +// |oooooooooooooooooooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxoooooooooooooooooooooooo| +// ^ ^ ^ ^ +// __front_cap_ __begin_ __end_ __back_cap_ +// +// The range [__front_cap_, __begin_) contains uninitialized memory. It is referred to as the "front spare capacity". +// The range [__begin_, __end_) contains valid objects. It is referred to as the "valid range". +// The range [__end_, __back_cap_) contains uninitialized memory. It is referred to as the "back spare capacity". +// +// The layout of `__split_buffer` is determined by the `_Layout` template template parameter. This +// `_Layout` allows the above pointers to be stored as different representations, such as integer +// offsets. A layout class template must provide the following interface: +// +// template<class _Tp, class _Allocator, class _Layout> +// class __layout { +// protected: +// using value_type = _Tp; +// using allocator_type = _Allocator; +// using __alloc_traits = allocator_traits<allocator_type>; +// using reference = value_type&; +// using const_reference = const value_type&; +// using size_type = typename __alloc_traits::size_type; +// using difference_type = typename __alloc_traits::difference_type; +// using pointer = typename __alloc_traits::pointer; +// using const_pointer = typename __alloc_traits::const_pointer; +// using iterator = pointer; +// using const_iterator = const_pointer; +// using __sentinel_type = /* type that represents the layout's sentinel */; +// +// public: +// __layout() = default; +// explicit __layout(const allocator_type&); +// +// pointer __front_cap(); +// const_pointer __front_cap() const; +// +// pointer begin(); +// const_pointer begin() const; +// +// pointer end(); +// pointer end() const; +// +// size_type size() const; +// bool empty() const; +// size_type capacity() const; +// +// allocator_type& __get_allocator(); +// allocator_type const& __get_allocator() const; +// +// __sentinel_type __raw_sentinel() const; +// __sentinel_type __raw_capacity() const; +// +// void __set_data(pointer); +// void __set_valid_range(pointer __begin, pointer __end); +// void __set_valid_range(pointer __begin, size_type __size); +// void __set_sentinel(pointer __end); +// void __set_sentinel(size_type __size); +// +// void __set_capacity(size_type __capacity); +// void __set_capacity(pointer __capacity); +// +// size_type __front_spare() const; +// size_type __back_spare() const; +// +// reference back(); +// const_reference back() const; +// +// template<class _OtherLayout> +// void __swap_without_allocator(_OtherLayout&); +// void swap(__layout&); +// +// void __reset(); +// void __copy_without_alloc(__layout const&); +// }; +// +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +class __split_buffer : _Layout<__split_buffer<_Tp, _Allocator, _Layout>, _Tp, _Allocator> { + using __base_type _LIBCPP_NODEBUG = _Layout<__split_buffer<_Tp, _Allocator, _Layout>, _Tp, _Allocator>; + +public: + using __base_type::__back_spare; + using __base_type::__copy_without_alloc; + using __base_type::__front_cap; + using __base_type::__front_spare; + using __base_type::__get_allocator; + using __base_type::__raw_capacity; + using __base_type::__raw_sentinel; + using __base_type::__reset; + using __base_type::__set_capacity; + using __base_type::__set_data; + using __base_type::__set_sentinel; + using __base_type::__set_valid_range; + + using typename __base_type::__alloc_traits; + using typename __base_type::allocator_type; + using typename __base_type::const_iterator; + using typename __base_type::const_pointer; + using typename __base_type::const_reference; + using typename __base_type::difference_type; + using typename __base_type::iterator; + using typename __base_type::pointer; + using typename __base_type::reference; + using typename __base_type::size_type; + using typename __base_type::value_type; // A __split_buffer contains the following members which may be trivially relocatable: // - pointer: may be trivially relocatable, so it's checked @@ -73,36 +478,24 @@ public: __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value, __split_buffer, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value, - __split_buffer, - void>; - - pointer __first_; - pointer __begin_; - pointer __end_; - _LIBCPP_COMPRESSED_PAIR(pointer, __cap_, allocator_type, __alloc_); __split_buffer(const __split_buffer&) = delete; __split_buffer& operator=(const __split_buffer&) = delete; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer() - _NOEXCEPT_(is_nothrow_default_constructible<allocator_type>::value) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI __split_buffer() = default; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {} + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(allocator_type& __a) : __base_type(__a) {} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a) - : __first_(nullptr), __begin_(nullptr), __end_(nullptr), __cap_(nullptr), __alloc_(__a) {} + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const allocator_type& __a) + : __base_type(__a) {} _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI - __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a); + __split_buffer(size_type __cap, size_type __start, allocator_type& __a); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const allocator_type& __a); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c) _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value && @@ -111,36 +504,16 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~__split_buffer(); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __begin_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __end_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __end_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(__begin_); } + using __base_type::back; + using __base_type::begin; + using __base_type::capacity; + using __base_type::empty; + using __base_type::end; + using __base_type::size; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type size() const { - return static_cast<size_type>(__end_ - __begin_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool empty() const { return __end_ == __begin_; } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type capacity() const { - return static_cast<size_type>(__cap_ - __first_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __front_spare() const { - return static_cast<size_type>(__begin_ - __first_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI size_type __back_spare() const { - return static_cast<size_type>(__cap_ - __end_); - } - - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() { return *(__end_ - 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const { return *(__end_ - 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void clear() _NOEXCEPT { __destruct_at_end(begin()); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() { return *begin(); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const { return *begin(); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void shrink_to_fit() _NOEXCEPT; @@ -149,8 +522,8 @@ public: template <class... _Args> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(__begin_ + 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(__end_ - 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_front() { __destruct_at_begin(begin() + 1); } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { __destruct_at_end(end() - 1); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(size_type __n, const_reference __x); @@ -182,244 +555,242 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT; _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>); + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>); + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const { + if (__front_cap() == nullptr) { + if (begin() != nullptr) + return false; + + if (!empty()) + return false; + + if (capacity() != 0) + return false; + + return true; + } else { + if (begin() < __front_cap()) + return false; - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const; + if (capacity() < size()) + return false; + + if (end() < begin()) + return false; + + return true; + } + } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __swap_without_allocator(__split_buffer<value_type, allocator_type, _Layout>& __other) _NOEXCEPT { + __base_type::__swap_without_allocator(__other); + } private: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer& __c, true_type) _NOEXCEPT_(is_nothrow_move_assignable<allocator_type>::value) { - __alloc_ = std::move(__c.__alloc_); + __get_allocator() = std::move(__c.__get_allocator()); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__split_buffer&, false_type) _NOEXCEPT {} struct _ConstructTransaction { _LIBCPP_CONSTEXPR_SINCE_CXX20 - _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(pointer* __p, size_type __n) _NOEXCEPT - : __pos_(*__p), - __end_(*__p + __n), - __dest_(__p) {} + _LIBCPP_HIDE_FROM_ABI explicit _ConstructTransaction(__split_buffer* __parent, pointer __p, size_type __n) _NOEXCEPT + : __pos_(__p), + __end_(__p + __n), + __parent_(__parent) {} - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { *__dest_ = __pos_; } + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI ~_ConstructTransaction() { __parent_->__set_sentinel(__pos_); } pointer __pos_; const pointer __end_; private: - pointer* __dest_; + __split_buffer* __parent_; }; -}; -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 bool __split_buffer<_Tp, _Allocator>::__invariants() const { - if (__first_ == nullptr) { - if (__begin_ != nullptr) - return false; - if (__end_ != nullptr) - return false; - if (__cap_ != nullptr) - return false; - } else { - if (__begin_ < __first_) - return false; - if (__end_ < __begin_) - return false; - if (__cap_ < __end_) - return false; - } - return true; -} + template <class _T2, class _A2, template <class, class, class> class _L2> + friend class __split_buffer; +}; -// Default constructs __n objects starting at __end_ +// Default constructs __n objects starting at `end()` // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == size() + __n -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(size_type __n) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_)); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_)); } } -// Copy constructs __n objects starting at __end_ from __x +// Copy constructs __n objects starting at `end()` from __x // throws if construction throws // Precondition: __n > 0 // Precondition: size() + __n <= capacity() // Postcondition: size() == old size() + __n // Postcondition: [i] == __x for all i in [size() - __n, __n) -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end(size_type __n, const_reference __x) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(size_type __n, const_reference __x) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), __x); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_), __x); } } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> template <class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { - __alloc_rr& __a = __alloc_; +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) { + allocator_type& __a = __get_allocator(); for (; __first != __last; ++__first) { - if (__end_ == __cap_) { - size_type __old_cap = __cap_ - __first_; + if (__back_spare() == 0) { + size_type __old_cap = capacity(); size_type __new_cap = std::max<size_type>(2 * __old_cap, 8); __split_buffer __buf(__new_cap, 0, __a); - for (pointer __p = __begin_; __p != __end_; ++__p, (void)++__buf.__end_) - __alloc_traits::construct(__buf.__alloc_, std::__to_address(__buf.__end_), std::move(*__p)); + pointer __buf_end = __buf.end(); + pointer __end = end(); + for (pointer __p = begin(); __p != __end; ++__p) { + __alloc_traits::construct(__buf.__get_allocator(), std::__to_address(__buf_end), std::move(*__p)); + __buf.__set_sentinel(++__buf_end); + } swap(__buf); } - __alloc_traits::construct(__a, std::__to_address(this->__end_), *__first); - ++this->__end_; + + __alloc_traits::construct(__a, std::__to_address(end()), *__first); + __set_sentinel(size() + 1); } } -template <class _Tp, class _Allocator> + +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> > _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end(_ForwardIterator __first, _ForwardIterator __last) { __construct_at_end_with_size(__first, std::distance(__first, __last)); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> template <class _ForwardIterator> _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__split_buffer<_Tp, _Allocator>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { - _ConstructTransaction __tx(std::addressof(this->__end_), __n); +__split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_size(_ForwardIterator __first, size_type __n) { + _ConstructTransaction __tx(this, end(), __n); for (; __tx.__pos_ != __tx.__end_; ++__tx.__pos_, (void)++__first) { - __alloc_traits::construct(__alloc_, std::__to_address(__tx.__pos_), *__first); + __alloc_traits::construct(__get_allocator(), std::__to_address(__tx.__pos_), *__first); } } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, false_type) { - while (__begin_ != __new_begin) - __alloc_traits::destroy(__alloc_, std::__to_address(__begin_++)); +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_begin(pointer __new_begin, false_type) { + pointer __begin = begin(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (__begin != __new_begin) + __alloc_traits::destroy(__get_allocator(), std::__to_address(__begin++)); + __set_valid_range(__begin, end()); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -__split_buffer<_Tp, _Allocator>::__destruct_at_begin(pointer __new_begin, true_type) { - __begin_ = __new_begin; -} - -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void -__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT { - while (__new_last != __end_) - __alloc_traits::destroy(__alloc_, std::__to_address(--__end_)); +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_begin(pointer __new_begin, true_type) { + __set_valid_range(__new_begin, end()); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void -__split_buffer<_Tp, _Allocator>::__destruct_at_end(pointer __new_last, true_type) _NOEXCEPT { - __end_ = __new_last; +__split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_end(pointer __new_last, false_type) _NOEXCEPT { + pointer __end = end(); + // Updating begin at every iteration is unnecessary because destruction can't throw. + while (__new_last != __end) + __alloc_traits::destroy(__get_allocator(), std::__to_address(--__end)); + __set_sentinel(__end); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 -__split_buffer<_Tp, _Allocator>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a) - : __cap_(nullptr), __alloc_(__a) { - if (__cap == 0) { - __first_ = nullptr; - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __cap); - __first_ = __allocation.ptr; - __cap = __allocation.count; +__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, allocator_type& __a) + : __base_type(__a) { + _LIBCPP_ASSERT_INTERNAL(__cap >= __start, "can't have a start point outside the capacity"); + if (__cap > 0) { + auto __allocation = std::__allocate_at_least(__get_allocator(), __cap); + __set_data(__allocation.ptr); + __cap = __allocation.count; } - __begin_ = __end_ = __first_ + __start; - __cap_ = __first_ + __cap; + + pointer __begin = __front_cap() + __start; + __set_valid_range(__begin, __begin); + __set_capacity(__cap); } -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::~__split_buffer() { +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::~__split_buffer() { clear(); - if (__first_) - __alloc_traits::deallocate(__alloc_, __first_, capacity()); + if (__front_cap()) + __alloc_traits::deallocate(__get_allocator(), __front_cap(), capacity()); } -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c) +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c) _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value) - : __first_(std::move(__c.__first_)), - __begin_(std::move(__c.__begin_)), - __end_(std::move(__c.__end_)), - __cap_(std::move(__c.__cap_)), - __alloc_(std::move(__c.__alloc_)) { - __c.__first_ = nullptr; - __c.__begin_ = nullptr; - __c.__end_ = nullptr; - __c.__cap_ = nullptr; + : __base_type(std::move(__c)) { + __c.__reset(); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 -__split_buffer<_Tp, _Allocator>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a) - : __cap_(nullptr), __alloc_(__a) { - if (__a == __c.__alloc_) { - __first_ = __c.__first_; - __begin_ = __c.__begin_; - __end_ = __c.__end_; - __cap_ = __c.__cap_; - __c.__first_ = nullptr; - __c.__begin_ = nullptr; - __c.__end_ = nullptr; - __c.__cap_ = nullptr; +__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const allocator_type& __a) + : __base_type(__a) { + if (__a == __c.__get_allocator()) { + __set_data(__c.__front_cap()); + __set_valid_range(__c.begin(), __c.end()); + __set_capacity(__c.capacity()); + __c.__reset(); } else { - auto __allocation = std::__allocate_at_least(__alloc_, __c.size()); - __first_ = __allocation.ptr; - __begin_ = __end_ = __first_; - __cap_ = __first_ + __allocation.count; + auto __allocation = std::__allocate_at_least(__get_allocator(), __c.size()); + __set_data(__allocation.ptr); + __set_valid_range(__front_cap(), __front_cap()); + __set_capacity(__allocation.count); typedef move_iterator<iterator> _Ip; __construct_at_end(_Ip(__c.begin()), _Ip(__c.end())); } } -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator>& -__split_buffer<_Tp, _Allocator>::operator=(__split_buffer&& __c) +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>& +__split_buffer<_Tp, _Allocator, _Layout>::operator=(__split_buffer&& __c) _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<allocator_type>::value) || !__alloc_traits::propagate_on_container_move_assignment::value) { clear(); shrink_to_fit(); - __first_ = __c.__first_; - __begin_ = __c.__begin_; - __end_ = __c.__end_; - __cap_ = __c.__cap_; + __copy_without_alloc(__c); __move_assign_alloc(__c, integral_constant<bool, __alloc_traits::propagate_on_container_move_assignment::value>()); - __c.__first_ = __c.__begin_ = __c.__end_ = __c.__cap_ = nullptr; + __c.__reset(); return *this; } -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::swap(__split_buffer& __x) - _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) { - std::swap(__first_, __x.__first_); - std::swap(__begin_, __x.__begin_); - std::swap(__end_, __x.__end_); - std::swap(__cap_, __x.__cap_); - std::__swap_allocator(__alloc_, __x.__alloc_); +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::swap(__split_buffer& __x) + _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>) { + __base_type::swap(__x); } -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT { +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::shrink_to_fit() _NOEXCEPT { if (capacity() > size()) { #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS - __split_buffer<value_type, __alloc_rr&> __t(size(), 0, __alloc_); + __split_buffer<value_type, allocator_type, _Layout> __t(size(), 0, __get_allocator()); if (__t.capacity() < capacity()) { - __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); - __t.__end_ = __t.__begin_ + (__end_ - __begin_); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(end())); + __t.__set_sentinel(size()); + __swap_without_allocator(__t); } #if _LIBCPP_HAS_EXCEPTIONS } catch (...) { @@ -428,55 +799,56 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::shrink_to_fi } } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> template <class... _Args> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_front(_Args&&... __args) { - if (__begin_ == __first_) { - if (__end_ < __cap_) { - difference_type __d = __cap_ - __end_; +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emplace_front(_Args&&... __args) { + if (__front_spare() == 0) { + pointer __end = end(); + if (__back_spare() > 0) { + // The elements are pressed up against the front of the buffer: we need to move them back a + // little bit to make `emplace_front` have amortised O(1) complexity. + difference_type __d = __back_spare(); __d = (__d + 1) / 2; - __begin_ = std::move_backward(__begin_, __end_, __end_ + __d); - __end_ += __d; + auto __new_end = __end + __d; + __set_valid_range(std::move_backward(begin(), __end, __new_end), __new_end); } else { - size_type __c = std::max<size_type>(2 * static_cast<size_type>(__cap_ - __first_), 1); - __split_buffer<value_type, __alloc_rr&> __t(__c, (__c + 3) / 4, __alloc_); - __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + size_type __c = std::max<size_type>(2 * capacity(), 1); + __split_buffer<value_type, allocator_type, _Layout> __t(__c, (__c + 3) / 4, __get_allocator()); + __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end)); + __base_type::__swap_without_allocator(__t); } } - __alloc_traits::construct(__alloc_, std::__to_address(__begin_ - 1), std::forward<_Args>(__args)...); - --__begin_; + + __alloc_traits::construct(__get_allocator(), std::__to_address(begin() - 1), std::forward<_Args>(__args)...); + __set_valid_range(begin() - 1, size() + 1); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> template <class... _Args> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator>::emplace_back(_Args&&... __args) { - if (__end_ == __cap_) { - if (__begin_ > __first_) { - difference_type __d = __begin_ - __first_; +_LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emplace_back(_Args&&... __args) { + pointer __end = end(); + if (__back_spare() == 0) { + if (__front_spare() > 0) { + difference_type __d = __front_spare(); __d = (__d + 1) / 2; - __end_ = std::move(__begin_, __end_, __begin_ - __d); - __begin_ -= __d; + __end = std::move(begin(), __end, begin() - __d); + __set_valid_range(begin() - __d, __end); } else { - size_type __c = std::max<size_type>(2 * static_cast<size_type>(__cap_ - __first_), 1); - __split_buffer<value_type, __alloc_rr&> __t(__c, __c / 4, __alloc_); - __t.__construct_at_end(move_iterator<pointer>(__begin_), move_iterator<pointer>(__end_)); - std::swap(__first_, __t.__first_); - std::swap(__begin_, __t.__begin_); - std::swap(__end_, __t.__end_); - std::swap(__cap_, __t.__cap_); + size_type __c = std::max<size_type>(2 * capacity(), 1); + __split_buffer<value_type, allocator_type, _Layout> __t(__c, __c / 4, __get_allocator()); + __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end)); + __base_type::__swap_without_allocator(__t); } } - __alloc_traits::construct(__alloc_, std::__to_address(__end_), std::forward<_Args>(__args)...); - ++__end_; + + __alloc_traits::construct(__get_allocator(), std::__to_address(__end), std::forward<_Args>(__args)...); + __set_sentinel(++__end); } -template <class _Tp, class _Allocator> +template <class _Tp, class _Allocator, template <class, class, class> class _Layout> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI void -swap(__split_buffer<_Tp, _Allocator>& __x, __split_buffer<_Tp, _Allocator>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { +swap(__split_buffer<_Tp, _Allocator, _Layout>& __x, __split_buffer<_Tp, _Allocator, _Layout>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } diff --git a/lib/libcxx/include/__stop_token/atomic_unique_lock.h b/lib/libcxx/include/__stop_token/atomic_unique_lock.h @@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD // where State contains a lock bit and might contain other data, // and LockedBit is the value of State when the lock bit is set, e.g 1 << 2 template <class _State, _State _LockedBit> -class _LIBCPP_AVAILABILITY_SYNC __atomic_unique_lock { +class __atomic_unique_lock { static_assert(std::__popcount(static_cast<unsigned long long>(_LockedBit)) == 1, "LockedBit must be an integer where only one bit is set"); diff --git a/lib/libcxx/include/__stop_token/stop_callback.h b/lib/libcxx/include/__stop_token/stop_callback.h @@ -34,7 +34,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS template <class _Callback> -class _LIBCPP_AVAILABILITY_SYNC stop_callback : private __stop_callback_base { +class stop_callback : private __stop_callback_base { static_assert(invocable<_Callback>, "Mandates: stop_callback is instantiated with an argument for the template parameter Callback that " "satisfies invocable."); @@ -91,7 +91,7 @@ private: }; template <class _Callback> -_LIBCPP_AVAILABILITY_SYNC stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; +stop_callback(stop_token, _Callback) -> stop_callback<_Callback>; #endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS diff --git a/lib/libcxx/include/__stop_token/stop_source.h b/lib/libcxx/include/__stop_token/stop_source.h @@ -30,7 +30,7 @@ struct nostopstate_t { inline constexpr nostopstate_t nostopstate{}; -class _LIBCPP_AVAILABILITY_SYNC stop_source { +class stop_source { public: _LIBCPP_HIDE_FROM_ABI stop_source() : __state_(new __stop_state()) { __state_->__increment_stop_source_counter(); } diff --git a/lib/libcxx/include/__stop_token/stop_state.h b/lib/libcxx/include/__stop_token/stop_state.h @@ -100,7 +100,7 @@ public: return ((__curent_state & __stop_requested_bit) != 0) || ((__curent_state >> __stop_source_counter_shift) != 0); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __request_stop() noexcept { + _LIBCPP_HIDE_FROM_ABI bool __request_stop() noexcept { auto __cb_list_lock = __try_lock_for_request_stop(); if (!__cb_list_lock.__owns_lock()) { return false; @@ -137,7 +137,7 @@ public: return true; } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __add_callback(__stop_callback_base* __cb) noexcept { + _LIBCPP_HIDE_FROM_ABI bool __add_callback(__stop_callback_base* __cb) noexcept { // If it is already stop_requested. Do not try to request it again. const auto __give_up_trying_to_lock_condition = [__cb](__state_t __state) { if ((__state & __stop_requested_bit) != 0) { @@ -164,7 +164,7 @@ public: } // called by the destructor of stop_callback - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void __remove_callback(__stop_callback_base* __cb) noexcept { + _LIBCPP_HIDE_FROM_ABI void __remove_callback(__stop_callback_base* __cb) noexcept { __callback_list_lock __cb_list_lock(__state_); // under below condition, the request_stop call just popped __cb from the list and could execute it now @@ -192,7 +192,7 @@ public: } private: - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI __callback_list_lock __try_lock_for_request_stop() noexcept { + _LIBCPP_HIDE_FROM_ABI __callback_list_lock __try_lock_for_request_stop() noexcept { // If it is already stop_requested, do not try to request stop or lock the list again. const auto __lock_fail_condition = [](__state_t __state) { return (__state & __stop_requested_bit) != 0; }; diff --git a/lib/libcxx/include/__stop_token/stop_token.h b/lib/libcxx/include/__stop_token/stop_token.h @@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_THREADS -class _LIBCPP_AVAILABILITY_SYNC stop_token { +class stop_token { public: _LIBCPP_HIDE_FROM_ABI stop_token() noexcept = default; diff --git a/lib/libcxx/include/__string/char_traits.h b/lib/libcxx/include/__string/char_traits.h @@ -94,16 +94,17 @@ struct char_traits<char> { } // TODO: Make this _LIBCPP_HIDE_FROM_ABI - static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR bool eq(char_type __c1, char_type __c2) _NOEXCEPT { return __c1 == __c2; } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool lt(char_type __c1, char_type __c2) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool + lt(char_type __c1, char_type __c2) _NOEXCEPT { return (unsigned char)__c1 < (unsigned char)__c2; } // __constexpr_memcmp requires a trivially lexicographically comparable type, but char is not when char is a signed // type - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int + [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __lhs, const char_type* __rhs, size_t __count) _NOEXCEPT { if (__libcpp_is_constant_evaluated()) { #ifdef _LIBCPP_COMPILER_CLANG_BASED @@ -126,11 +127,12 @@ struct char_traits<char> { } } - static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 length(const char_type* __s) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI size_t _LIBCPP_CONSTEXPR_SINCE_CXX17 + length(const char_type* __s) _NOEXCEPT { return std::__constexpr_strlen(__s); } - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* + [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { return std::__constexpr_memchr(__s, __a, __n); } @@ -154,19 +156,24 @@ struct char_traits<char> { return __s; } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { return eq_int_type(__c, eof()) ? ~eof() : __c; } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR char_type + to_char_type(int_type __c) _NOEXCEPT { return char_type(__c); } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type + to_int_type(char_type __c) _NOEXCEPT { return int_type((unsigned char)__c); } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT { + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool + eq_int_type(int_type __c1, int_type __c2) _NOEXCEPT { return __c1 == __c2; } - static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return int_type(EOF); } + [[__nodiscard__]] static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { + return int_type(EOF); + } }; template <class _CharT, class _IntT, _IntT _EOFVal> @@ -187,11 +194,11 @@ struct __char_traits_base { __lhs = __rhs; } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq(char_type __lhs, char_type __rhs) _NOEXCEPT { return __lhs == __rhs; } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool lt(char_type __lhs, char_type __rhs) _NOEXCEPT { return __lhs < __rhs; } @@ -213,19 +220,22 @@ struct __char_traits_base { return __str; } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR char_type to_char_type(int_type __c) _NOEXCEPT { return char_type(__c); } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { return int_type(__c); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type to_int_type(char_type __c) _NOEXCEPT { + return int_type(__c); + } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR bool + eq_int_type(int_type __lhs, int_type __rhs) _NOEXCEPT { return __lhs == __rhs; } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type eof() _NOEXCEPT { return _EOFVal; } - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR int_type not_eof(int_type __c) _NOEXCEPT { return eq_int_type(__c, eof()) ? static_cast<int_type>(~eof()) : __c; } }; @@ -235,18 +245,19 @@ struct __char_traits_base { #if _LIBCPP_HAS_WIDE_CHARACTERS template <> struct char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wint_t>(WEOF)> { - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int + [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { if (__n == 0) return 0; return std::__constexpr_wmemcmp(__s1, __s2, __n); } - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT { + [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t + length(const char_type* __s) _NOEXCEPT { return std::__constexpr_wcslen(__s); } - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* + [[__nodiscard__]] static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { return std::__constexpr_wmemchr(__s, __a, __n); } @@ -257,16 +268,16 @@ struct char_traits<wchar_t> : __char_traits_base<wchar_t, wint_t, static_cast<wi template <> struct char_traits<char8_t> : __char_traits_base<char8_t, unsigned int, static_cast<unsigned int>(EOF)> { - static _LIBCPP_HIDE_FROM_ABI constexpr int + [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr int compare(const char_type* __s1, const char_type* __s2, size_t __n) noexcept { return std::__constexpr_memcmp(__s1, __s2, __element_count(__n)); } - static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept { + [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr size_t length(const char_type* __str) noexcept { return std::__constexpr_strlen(__str); } - _LIBCPP_HIDE_FROM_ABI static constexpr const char_type* + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr const char_type* find(const char_type* __s, size_t __n, const char_type& __a) noexcept { return std::__constexpr_memchr(__s, __a, __n); } @@ -276,11 +287,11 @@ struct char_traits<char8_t> : __char_traits_base<char8_t, unsigned int, static_c template <> struct char_traits<char16_t> : __char_traits_base<char16_t, uint_least16_t, static_cast<uint_least16_t>(0xFFFF)> { - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { __identity __proj; const char_type* __match = std::__find(__s, __s + __n, __a, __proj); @@ -290,7 +301,7 @@ struct char_traits<char16_t> : __char_traits_base<char16_t, uint_least16_t, stat } }; -inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { for (; __n; --__n, ++__s1, ++__s2) { if (lt(*__s1, *__s2)) @@ -301,7 +312,8 @@ char_traits<char16_t>::compare(const char_type* __s1, const char_type* __s2, siz return 0; } -inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t +char_traits<char16_t>::length(const char_type* __s) _NOEXCEPT { size_t __len = 0; for (; !eq(*__s, char_type(0)); ++__s) ++__len; @@ -310,11 +322,11 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char16_t>::length(const template <> struct char_traits<char32_t> : __char_traits_base<char32_t, uint_least32_t, static_cast<uint_least32_t>(0xFFFFFFFF)> { - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 int compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t length(const char_type* __s) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX17 const char_type* find(const char_type* __s, size_t __n, const char_type& __a) _NOEXCEPT { __identity __proj; const char_type* __match = std::__find(__s, __s + __n, __a, __proj); @@ -324,7 +336,7 @@ struct char_traits<char32_t> : __char_traits_base<char32_t, uint_least32_t, stat } }; -inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 int char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT { for (; __n; --__n, ++__s1, ++__s2) { if (lt(*__s1, *__s2)) @@ -335,7 +347,8 @@ char_traits<char32_t>::compare(const char_type* __s1, const char_type* __s2, siz return 0; } -inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_CONSTEXPR_SINCE_CXX17 size_t +char_traits<char32_t>::length(const char_type* __s) _NOEXCEPT { size_t __len = 0; for (; !eq(*__s, char_type(0)); ++__s) ++__len; @@ -369,6 +382,13 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 const _CharT* __searc if (__len1 < __len2) return __last1; + if (__builtin_constant_p(__len2 == 1) && __len2 == 1) { + auto __res = _Traits::find(__first1, __len1, *__first2); + if (__res == nullptr) + return __last1; + return __res; + } + // First element of __first2 is loop invariant. _CharT __f2 = *__first2; while (true) { diff --git a/lib/libcxx/include/__string/constexpr_c_functions.h b/lib/libcxx/include/__string/constexpr_c_functions.h @@ -22,7 +22,6 @@ #include <__type_traits/is_equality_comparable.h> #include <__type_traits/is_integral.h> #include <__type_traits/is_same.h> -#include <__type_traits/is_trivially_copyable.h> #include <__type_traits/is_trivially_lexicographically_comparable.h> #include <__type_traits/remove_cv.h> #include <__utility/element_count.h> @@ -96,14 +95,13 @@ __constexpr_memcmp(const _Tp* __lhs, const _Up* __rhs, __element_count __n) { } } -// Because of __libcpp_is_trivially_equality_comparable we know that comparing the object representations is equivalent +// Because of __is_trivially_equality_comparable_v we know that comparing the object representations is equivalent // to a std::memcmp(...) == 0. Since we have multiple objects contiguously in memory, we can call memcmp once instead // of invoking it on every object individually. template <class _Tp, class _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __constexpr_memcmp_equal(const _Tp* __lhs, const _Up* __rhs, __element_count __n) { - static_assert(__libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, - "_Tp and _Up have to be trivially equality comparable"); + static_assert(__is_trivially_equality_comparable_v<_Tp, _Up>, "_Tp and _Up have to be trivially equality comparable"); auto __count = static_cast<size_t>(__n); @@ -128,7 +126,7 @@ __constexpr_memcmp_equal(const _Tp* __lhs, const _Up* __rhs, __element_count __n template <class _Tp, class _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __constexpr_memchr(_Tp* __str, _Up __value, size_t __count) { - static_assert(sizeof(_Tp) == 1 && __libcpp_is_trivially_equality_comparable<_Tp, _Up>::value, + static_assert(sizeof(_Tp) == 1 && __is_trivially_equality_comparable_v<_Tp, _Up>, "Calling memchr on non-trivially equality comparable types is unsafe."); if (__libcpp_is_constant_evaluated()) { @@ -225,6 +223,8 @@ __constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n) { std::__assign_trivially_copyable(__dest[__i], __src[__i]); } } + } else if _LIBCPP_CONSTEXPR (sizeof(_Tp) == __datasizeof_v<_Tp>) { + ::__builtin_memmove(__dest, __src, __count * sizeof(_Tp)); } else if (__count > 0) { ::__builtin_memmove(__dest, __src, (__count - 1) * sizeof(_Tp) + __datasizeof_v<_Tp>); } diff --git a/lib/libcxx/include/__support/xlocale/__strtonum_fallback.h b/lib/libcxx/include/__support/xlocale/__strtonum_fallback.h @@ -34,12 +34,4 @@ inline _LIBCPP_HIDE_FROM_ABI long double strtold_l(const char* __nptr, char** __ return ::strtold(__nptr, __endptr); } -inline _LIBCPP_HIDE_FROM_ABI long long strtoll_l(const char* __nptr, char** __endptr, int __base, locale_t) { - return ::strtoll(__nptr, __endptr, __base); -} - -inline _LIBCPP_HIDE_FROM_ABI unsigned long long strtoull_l(const char* __nptr, char** __endptr, int __base, locale_t) { - return ::strtoull(__nptr, __endptr, __base); -} - #endif // _LIBCPP___SUPPORT_XLOCALE_STRTONUM_FALLBACK_H diff --git a/lib/libcxx/include/__system_error/error_category.h b/lib/libcxx/include/__system_error/error_category.h @@ -20,7 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -class _LIBCPP_EXPORTED_FROM_ABI error_condition; +class error_condition; class _LIBCPP_EXPORTED_FROM_ABI error_code; class _LIBCPP_HIDDEN __do_message; @@ -37,11 +37,11 @@ public: error_category(const error_category&) = delete; error_category& operator=(const error_category&) = delete; - virtual const char* name() const _NOEXCEPT = 0; - virtual error_condition default_error_condition(int __ev) const _NOEXCEPT; - virtual bool equivalent(int __code, const error_condition& __condition) const _NOEXCEPT; - virtual bool equivalent(const error_code& __code, int __condition) const _NOEXCEPT; - virtual string message(int __ev) const = 0; + [[__nodiscard__]] virtual const char* name() const _NOEXCEPT = 0; + [[__nodiscard__]] virtual error_condition default_error_condition(int __ev) const _NOEXCEPT; + [[__nodiscard__]] virtual bool equivalent(int __code, const error_condition& __condition) const _NOEXCEPT; + [[__nodiscard__]] virtual bool equivalent(const error_code& __code, int __condition) const _NOEXCEPT; + [[__nodiscard__]] virtual string message(int __ev) const = 0; _LIBCPP_HIDE_FROM_ABI bool operator==(const error_category& __rhs) const _NOEXCEPT { return this == &__rhs; } @@ -67,8 +67,8 @@ public: string message(int __ev) const override; }; -[[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& generic_category() _NOEXCEPT; -[[__gnu__::__const__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& system_category() _NOEXCEPT; +[[__gnu__::__const__]] [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& generic_category() _NOEXCEPT; +[[__gnu__::__const__]] [[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& system_category() _NOEXCEPT; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__system_error/error_code.h b/lib/libcxx/include/__system_error/error_code.h @@ -71,20 +71,20 @@ public: __cat_ = &system_category(); } - _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; } - _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; } - _LIBCPP_HIDE_FROM_ABI error_condition default_error_condition() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI error_condition default_error_condition() const _NOEXCEPT { return __cat_->default_error_condition(__val_); } - string message() const; + [[__nodiscard__]] string message() const; _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __val_ != 0; } }; -inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(errc __e) _NOEXCEPT { return error_code(static_cast<int>(__e), generic_category()); } diff --git a/lib/libcxx/include/__system_error/error_condition.h b/lib/libcxx/include/__system_error/error_condition.h @@ -80,15 +80,15 @@ public: __cat_ = &generic_category(); } - _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int value() const _NOEXCEPT { return __val_; } - _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; } - string message() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_category& category() const _NOEXCEPT { return *__cat_; } + [[__nodiscard__]] string message() const; _LIBCPP_HIDE_FROM_ABI explicit operator bool() const _NOEXCEPT { return __val_ != 0; } }; -inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(errc __e) _NOEXCEPT { return error_condition(static_cast<int>(__e), generic_category()); } diff --git a/lib/libcxx/include/__system_error/system_error.h b/lib/libcxx/include/__system_error/system_error.h @@ -36,7 +36,7 @@ public: _LIBCPP_HIDE_FROM_ABI system_error(const system_error&) _NOEXCEPT = default; ~system_error() _NOEXCEPT override; - _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; } }; // __ev is expected to be an error in the generic_category domain (e.g. from diff --git a/lib/libcxx/include/__thread/id.h b/lib/libcxx/include/__thread/id.h @@ -23,7 +23,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_HAS_THREADS -class _LIBCPP_EXPORTED_FROM_ABI __thread_id; +class __thread_id; namespace this_thread { diff --git a/lib/libcxx/include/__thread/jthread.h b/lib/libcxx/include/__thread/jthread.h @@ -36,7 +36,7 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -class _LIBCPP_AVAILABILITY_SYNC jthread { +class jthread { public: // types using id = thread::id; diff --git a/lib/libcxx/include/__thread/poll_with_backoff.h b/lib/libcxx/include/__thread/poll_with_backoff.h @@ -22,33 +22,50 @@ _LIBCPP_BEGIN_NAMESPACE_STD static _LIBCPP_CONSTEXPR const int __libcpp_polling_count = 64; +enum class __backoff_results : unsigned char { + __continue_poll = 1, + __poll_success = 2, + __timeout = 3, + __backoff_failure = 4, +}; + +enum class __poll_with_backoff_results : unsigned char { + __poll_success = static_cast<unsigned char>(__backoff_results::__poll_success), + __timeout = static_cast<unsigned char>(__backoff_results::__timeout), + __backoff_failure = static_cast<unsigned char>(__backoff_results::__backoff_failure), +}; + // Polls a thread for a condition given by a predicate, and backs off based on a backoff policy // before polling again. // // - __poll is the "test function" that should return true if polling succeeded, and false if it failed. // // - __backoff is the "backoff policy", which is called with the duration since we started polling. It should -// return false in order to resume polling, and true if polling should stop entirely for some reason. +// return __backoff_results::__continue_poll in order to resume polling, and other appropriate __backoff_results +// if polling should stop entirely for some reason. // In general, backoff policies sleep for some time before returning control to the polling loop. // // - __max_elapsed is the maximum duration to try polling for. If the maximum duration is exceeded, -// the polling loop will return false to report a timeout. +// the polling loop will return __poll_with_backoff_results::__timeout to report a timeout. + template <class _Poll, class _Backoff> -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_poll_with_backoff( +_LIBCPP_HIDE_FROM_ABI __poll_with_backoff_results __libcpp_thread_poll_with_backoff( _Poll&& __poll, _Backoff&& __backoff, chrono::nanoseconds __max_elapsed = chrono::nanoseconds::zero()) { auto const __start = chrono::high_resolution_clock::now(); for (int __count = 0;;) { if (__poll()) - return true; // __poll completion means success + return __poll_with_backoff_results::__poll_success; if (__count < __libcpp_polling_count) { __count += 1; continue; } chrono::nanoseconds const __elapsed = chrono::high_resolution_clock::now() - __start; if (__max_elapsed != chrono::nanoseconds::zero() && __max_elapsed < __elapsed) - return false; // timeout failure - if (__backoff(__elapsed)) - return false; // __backoff completion means failure + return __poll_with_backoff_results::__timeout; + if (auto __backoff_res = __backoff(__elapsed); __backoff_res == __backoff_results::__continue_poll) + continue; + else + return static_cast<__poll_with_backoff_results>(__backoff_res); } } @@ -59,7 +76,9 @@ _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __libcpp_thread_poll_with_b // so this should most likely only be used on single-threaded systems where there // are no other threads to compete with. struct __spinning_backoff_policy { - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(chrono::nanoseconds const&) const { return false; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __backoff_results operator()(chrono::nanoseconds const&) const { + return __backoff_results::__continue_poll; + } }; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__thread/support/c11.h b/lib/libcxx/include/__thread/support/c11.h @@ -39,17 +39,17 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursiv return mtx_init(__m, mtx_plain | mtx_recursive) == thrd_success ? 0 : EINVAL; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) { return mtx_lock(__m) == thrd_success ? 0 : EINVAL; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) { return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; } @@ -59,15 +59,15 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_destroy(__libcpp_recur return 0; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return mtx_lock(__m) == thrd_success ? 0 : EINVAL; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return mtx_trylock(__m) == thrd_success; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return mtx_unlock(__m) == thrd_success ? 0 : EINVAL; } @@ -92,12 +92,12 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_broadcast(__libcpp_condvar_t* return cnd_broadcast(__cv) == thrd_success ? 0 : EINVAL; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) { return cnd_wait(__cv, __m) == thrd_success ? 0 : EINVAL; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, timespec* __ts) { int __ec = cnd_timedwait(__cv, __m, __ts); return __ec == thrd_timedout ? ETIMEDOUT : __ec; diff --git a/lib/libcxx/include/__thread/support/pthread.h b/lib/libcxx/include/__thread/support/pthread.h @@ -72,17 +72,17 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursiv return 0; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_lock(__m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m) { return pthread_mutex_unlock(__m); } @@ -91,15 +91,15 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_recursive_mutex_destroy(__libcpp_recur return pthread_mutex_destroy(__m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_lock(__libcpp_mutex_t* __m) { return pthread_mutex_lock(__m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m) { return pthread_mutex_trylock(__m) == 0; } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_mutex_unlock(__libcpp_mutex_t* __m) { return pthread_mutex_unlock(__m); } @@ -117,12 +117,12 @@ inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_broadcast(__libcpp_condvar_t* return pthread_cond_broadcast(__cv); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m) { return pthread_cond_wait(__cv, __m); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts) { return pthread_cond_timedwait(__cv, __m, __ts); } diff --git a/lib/libcxx/include/__thread/support/windows.h b/lib/libcxx/include/__thread/support/windows.h @@ -36,22 +36,22 @@ typedef void* __libcpp_recursive_mutex_t[6]; _LIBCPP_EXPORTED_FROM_ABI int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_recursive_mutex_lock(__libcpp_recursive_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI bool __libcpp_recursive_mutex_trylock(__libcpp_recursive_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_recursive_mutex_unlock(__libcpp_recursive_mutex_t* __m); _LIBCPP_EXPORTED_FROM_ABI int __libcpp_recursive_mutex_destroy(__libcpp_recursive_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_lock(__libcpp_mutex_t* __m); +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_mutex_lock(__libcpp_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m); +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI bool __libcpp_mutex_trylock(__libcpp_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int __libcpp_mutex_unlock(__libcpp_mutex_t* __m); +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_mutex_unlock(__libcpp_mutex_t* __m); _LIBCPP_EXPORTED_FROM_ABI int __libcpp_mutex_destroy(__libcpp_mutex_t* __m); @@ -65,10 +65,10 @@ _LIBCPP_EXPORTED_FROM_ABI int __libcpp_condvar_signal(__libcpp_condvar_t* __cv); _LIBCPP_EXPORTED_FROM_ABI int __libcpp_condvar_broadcast(__libcpp_condvar_t* __cv); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_condvar_wait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m); -_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_NO_THREAD_SAFETY_ANALYSIS int +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_EXPORTED_FROM_ABI int __libcpp_condvar_timedwait(__libcpp_condvar_t* __cv, __libcpp_mutex_t* __m, __libcpp_timespec_t* __ts); _LIBCPP_EXPORTED_FROM_ABI int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv); diff --git a/lib/libcxx/include/__thread/thread.h b/lib/libcxx/include/__thread/thread.h @@ -25,6 +25,8 @@ #include <__thread/support.h> #include <__type_traits/decay.h> #include <__type_traits/enable_if.h> +#include <__type_traits/invoke.h> +#include <__type_traits/is_constructible.h> #include <__type_traits/is_same.h> #include <__type_traits/remove_cvref.h> #include <__utility/forward.h> @@ -155,8 +157,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 +166,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; } @@ -206,6 +207,10 @@ public: # ifndef _LIBCPP_CXX03_LANG template <class _Fp, class... _Args, __enable_if_t<!is_same<__remove_cvref_t<_Fp>, thread>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI explicit thread(_Fp&& __f, _Args&&... __args) { + static_assert(is_constructible<__decay_t<_Fp>, _Fp>::value, ""); + static_assert(_And<is_constructible<__decay_t<_Args>, _Args>...>::value, ""); + static_assert(__is_invocable_v<__decay_t<_Fp>, __decay_t<_Args>...>, ""); + typedef unique_ptr<__thread_struct> _TSPtr; _TSPtr __tsp(new __thread_struct); typedef tuple<_TSPtr, __decay_t<_Fp>, __decay_t<_Args>...> _Gp; @@ -243,13 +248,13 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(thread& __t) _NOEXCEPT { std::swap(__t_, __t.__t_); } - _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool joinable() const _NOEXCEPT { return !__libcpp_thread_isnull(&__t_); } void join(); void detach(); - _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); } - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI id get_id() const _NOEXCEPT { return __libcpp_thread_get_id(&__t_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() _NOEXCEPT { return __t_; } - static unsigned hardware_concurrency() _NOEXCEPT; + [[__nodiscard__]] static unsigned hardware_concurrency() _NOEXCEPT; }; inline _LIBCPP_HIDE_FROM_ABI void swap(thread& __x, thread& __y) _NOEXCEPT { __x.swap(__y); } diff --git a/lib/libcxx/include/__thread/timed_backoff_policy.h b/lib/libcxx/include/__thread/timed_backoff_policy.h @@ -11,6 +11,7 @@ #define _LIBCPP___THREAD_TIMED_BACKOFF_POLICY_H #include <__config> +#include <__thread/poll_with_backoff.h> #if _LIBCPP_HAS_THREADS @@ -24,7 +25,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD struct __libcpp_timed_backoff_policy { - _LIBCPP_HIDE_FROM_ABI bool operator()(chrono::nanoseconds __elapsed) const { + _LIBCPP_HIDE_FROM_ABI __backoff_results operator()(chrono::nanoseconds __elapsed) const { if (__elapsed > chrono::milliseconds(128)) __libcpp_thread_sleep_for(chrono::milliseconds(8)); else if (__elapsed > chrono::microseconds(64)) @@ -33,7 +34,7 @@ struct __libcpp_timed_backoff_policy { __libcpp_thread_yield(); else { } // poll - return false; + return __backoff_results::__continue_poll; } }; diff --git a/lib/libcxx/include/__tree b/lib/libcxx/include/__tree @@ -11,37 +11,39 @@ #define _LIBCPP___TREE #include <__algorithm/min.h> +#include <__algorithm/specialized_algorithms.h> #include <__assert> #include <__config> -#include <__fwd/map.h> #include <__fwd/pair.h> -#include <__fwd/set.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/next.h> #include <__memory/addressof.h> #include <__memory/allocator_traits.h> #include <__memory/compressed_pair.h> +#include <__memory/construct_at.h> #include <__memory/pointer_traits.h> #include <__memory/swap_allocator.h> #include <__memory/unique_ptr.h> -#include <__type_traits/can_extract_key.h> +#include <__new/launder.h> #include <__type_traits/copy_cvref.h> #include <__type_traits/enable_if.h> #include <__type_traits/invoke.h> -#include <__type_traits/is_const.h> #include <__type_traits/is_constructible.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_same.h> +#include <__type_traits/is_specialization.h> #include <__type_traits/is_swappable.h> +#include <__type_traits/make_transparent.h> #include <__type_traits/remove_const.h> -#include <__type_traits/remove_const_ref.h> #include <__type_traits/remove_cvref.h> #include <__utility/forward.h> +#include <__utility/lazy_synth_three_way_comparator.h> #include <__utility/move.h> #include <__utility/pair.h> #include <__utility/swap.h> +#include <__utility/try_key_extraction.h> #include <limits> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -51,14 +53,31 @@ _LIBCPP_PUSH_MACROS #include <__undef_macros> -_LIBCPP_BEGIN_NAMESPACE_STD +_LIBCPP_DIAGNOSTIC_PUSH +// GCC complains about the backslashes at the end, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121528 +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wcomment") +// __tree is a red-black-tree implementation used for the associative containers (i.e. (multi)map/set). It stores +// - (1) a pointer to the node with the smallest (i.e. leftmost) element, namely __begin_node_ +// - (2) the number of nodes in the tree, namely __size_ +// - (3) a pointer to the root of the tree, namely __end_node_ +// +// Storing (1) and (2) is required to allow for constant time lookups. A tree looks like this in memory: +// +// __end_node_ +// | +// root +// / \ +// l1 r1 +// / \ / \ +// ... ... ... ... +// +// All nodes except __end_node_ have a __left_ and __right_ pointer as well as a __parent_ pointer. +// __end_node_ only contains a __left_ pointer, which points to the root of the tree. +// This layout allows for iteration through the tree without a need for special handling of the end node. See +// __tree_next_iter and __tree_prev_iter for more details. +_LIBCPP_DIAGNOSTIC_POP -template <class _Tp, class _Compare, class _Allocator> -class __tree; -template <class _Tp, class _NodePtr, class _DiffType> -class __tree_iterator; -template <class _Tp, class _ConstNodePtr, class _DiffType> -class __tree_const_iterator; +_LIBCPP_BEGIN_NAMESPACE_STD template <class _Pointer> class __tree_end_node; @@ -70,13 +89,6 @@ class __tree_node; template <class _Key, class _Value> struct __value_type; -template <class _Allocator> -class __map_node_destructor; -template <class _TreeIterator> -class __map_iterator; -template <class _TreeIterator> -class __map_const_iterator; - /* _NodePtr algorithms @@ -185,6 +197,11 @@ _LIBCPP_HIDE_FROM_ABI _NodePtr __tree_next(_NodePtr __x) _NOEXCEPT { return __x->__parent_unsafe(); } +// __tree_next_iter and __tree_prev_iter implement iteration through the tree. The order is as follows: +// left sub-tree -> node -> right sub-tree. When the right-most node of a sub-tree is reached, we walk up the tree until +// we find a node where we were in the left sub-tree. We are _always_ in a left sub-tree, since the __end_node_ points +// to the actual root of the tree through a __left_ pointer. Incrementing the end() pointer is UB, so we can assume that +// never happens. template <class _EndNodePtr, class _NodePtr> inline _LIBCPP_HIDE_FROM_ABI _EndNodePtr __tree_next_iter(_NodePtr __x) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__x != nullptr, "node shouldn't be null"); @@ -494,16 +511,7 @@ _LIBCPP_HIDE_FROM_ABI void __tree_remove(_NodePtr __root, _NodePtr __z) _NOEXCEP // node traits template <class _Tp> -struct __is_tree_value_type_imp : false_type {}; - -template <class _Key, class _Value> -struct __is_tree_value_type_imp<__value_type<_Key, _Value> > : true_type {}; - -template <class... _Args> -struct __is_tree_value_type : false_type {}; - -template <class _One> -struct __is_tree_value_type<_One> : __is_tree_value_type_imp<__remove_cvref_t<_One> > {}; +inline const bool __is_tree_value_type_v = __is_specialization_v<_Tp, __value_type>; template <class _Tp> struct __get_tree_key_type { @@ -549,15 +557,14 @@ private: template <class _Pointer> class __tree_end_node { public: - typedef _Pointer pointer; + using pointer = _Pointer; pointer __left_; _LIBCPP_HIDE_FROM_ABI __tree_end_node() _NOEXCEPT : __left_() {} }; template <class _VoidPtr> -class _LIBCPP_STANDALONE_DEBUG -__tree_node_base : public __tree_end_node<__rebind_pointer_t<_VoidPtr, __tree_node_base<_VoidPtr> > > { +class __tree_node_base : public __tree_end_node<__rebind_pointer_t<_VoidPtr, __tree_node_base<_VoidPtr> > > { public: using pointer = __rebind_pointer_t<_VoidPtr, __tree_node_base>; using __end_node_pointer _LIBCPP_NODEBUG = __rebind_pointer_t<_VoidPtr, __tree_end_node<pointer> >; @@ -570,20 +577,41 @@ public: _LIBCPP_HIDE_FROM_ABI void __set_parent(pointer __p) { __parent_ = static_cast<__end_node_pointer>(__p); } - ~__tree_node_base() = delete; + _LIBCPP_HIDE_FROM_ABI __tree_node_base() = default; __tree_node_base(__tree_node_base const&) = delete; __tree_node_base& operator=(__tree_node_base const&) = delete; }; template <class _Tp, class _VoidPtr> -class _LIBCPP_STANDALONE_DEBUG __tree_node : public __tree_node_base<_VoidPtr> { +class __tree_node : public __tree_node_base<_VoidPtr> { public: using __node_value_type _LIBCPP_NODEBUG = __get_node_value_type_t<_Tp>; - __node_value_type __value_; +// We use a union to avoid initialization during member initialization, which allows us +// to use the allocator from the container to construct the `__node_value_type` in the +// memory provided by the union member +#ifndef _LIBCPP_CXX03_LANG + +private: + union { + __node_value_type __value_; + }; +public: _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return __value_; } +#else + +private: + _ALIGNAS_TYPE(__node_value_type) unsigned char __buffer_[sizeof(__node_value_type)]; + +public: + _LIBCPP_HIDE_FROM_ABI __node_value_type& __get_value() { return *reinterpret_cast<__node_value_type*>(__buffer_); } +#endif + template <class _Alloc, class... _Args> + _LIBCPP_HIDE_FROM_ABI explicit __tree_node(_Alloc& __na, _Args&&... __args) { + allocator_traits<_Alloc>::construct(__na, std::addressof(__get_value()), std::forward<_Args>(__args)...); + } ~__tree_node() = delete; __tree_node(__tree_node const&) = delete; __tree_node& operator=(__tree_node const&) = delete; @@ -591,11 +619,11 @@ public: template <class _Allocator> class __tree_node_destructor { - typedef _Allocator allocator_type; - typedef allocator_traits<allocator_type> __alloc_traits; + using allocator_type = _Allocator; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>; public: - typedef typename __alloc_traits::pointer pointer; + using pointer = typename __alloc_traits::pointer; private: allocator_type& __na_; @@ -612,7 +640,7 @@ public: _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { if (__value_constructed) - __alloc_traits::destroy(__na_, std::addressof(__p->__value_)); + __alloc_traits::destroy(__na_, std::addressof(__p->__get_value())); if (__p) __alloc_traits::deallocate(__na_, __p, 1); } @@ -630,12 +658,60 @@ struct __generic_container_node_destructor<__tree_node<_Tp, _VoidPtr>, _Alloc> : }; #endif +// Do an in-order traversal of the tree until `__break` returns true. Takes the root node of the tree. +template <class _Reference, class _Break, class _NodePtr, class _Func, class _Proj> +#ifndef _LIBCPP_COMPILER_GCC // This function is recursive, so GCC complains about always_inline. +_LIBCPP_HIDE_FROM_ABI +#endif +bool __tree_iterate_from_root(_Break __break, _NodePtr __root, _Func& __func, _Proj& __proj) { + if (__root->__left_) { + if (std::__tree_iterate_from_root<_Reference>(__break, static_cast<_NodePtr>(__root->__left_), __func, __proj)) + return true; + } + if (__break(__root)) + return true; + std::__invoke(__func, std::__invoke(__proj, static_cast<_Reference>(__root->__get_value()))); + if (__root->__right_) + return std::__tree_iterate_from_root<_Reference>(__break, static_cast<_NodePtr>(__root->__right_), __func, __proj); + return false; +} + +// Do an in-order traversal of the tree from __first to __last. +template <class _NodeIter, class _Func, class _Proj> +_LIBCPP_HIDE_FROM_ABI void +__tree_iterate_subrange(_NodeIter __first_it, _NodeIter __last_it, _Func& __func, _Proj& __proj) { + using _NodePtr = typename _NodeIter::__node_pointer; + using _Reference = typename _NodeIter::reference; + + auto __first = __first_it.__ptr_; + auto __last = __last_it.__ptr_; + + while (true) { + if (__first == __last) + return; + const auto __nfirst = static_cast<_NodePtr>(__first); + std::__invoke(__func, std::__invoke(__proj, static_cast<_Reference>(__nfirst->__get_value()))); + if (__nfirst->__right_) { + if (std::__tree_iterate_from_root<_Reference>( + [&](_NodePtr __node) -> bool { return __node == __last; }, + static_cast<_NodePtr>(__nfirst->__right_), + __func, + __proj)) + return; + } + while (!std::__tree_is_left_child(static_cast<_NodePtr>(__first))) + __first = static_cast<_NodePtr>(__first)->__parent_; + __first = static_cast<_NodePtr>(__first)->__parent_; + } +} + template <class _Tp, class _NodePtr, class _DiffType> class __tree_iterator { - typedef __tree_node_types<_NodePtr> _NodeTypes; - typedef _NodePtr __node_pointer; - typedef typename _NodeTypes::__node_base_pointer __node_base_pointer; - typedef typename _NodeTypes::__end_node_pointer __end_node_pointer; + using _NodeTypes _LIBCPP_NODEBUG = __tree_node_types<_NodePtr>; + // NOLINTNEXTLINE(libcpp-nodebug-on-aliases) lldb relies on this alias for pretty printing + using __node_pointer = _NodePtr; + using __node_base_pointer _LIBCPP_NODEBUG = typename _NodeTypes::__node_base_pointer; + using __end_node_pointer _LIBCPP_NODEBUG = typename _NodeTypes::__end_node_pointer; __end_node_pointer __ptr_; @@ -646,15 +722,12 @@ public: using reference = value_type&; using pointer = __rebind_pointer_t<_NodePtr, value_type>; - _LIBCPP_HIDE_FROM_ABI __tree_iterator() _NOEXCEPT -#if _LIBCPP_STD_VER >= 14 - : __ptr_(nullptr) -#endif - { - } + _LIBCPP_HIDE_FROM_ABI __tree_iterator() _NOEXCEPT : __ptr_(nullptr) {} - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_np()->__value_; } - _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__get_np()->__value_); } + _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_np()->__get_value(); } + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + return pointer_traits<pointer>::pointer_to(__get_np()->__get_value()); + } _LIBCPP_HIDE_FROM_ABI __tree_iterator& operator++() { __ptr_ = std::__tree_next_iter<__end_node_pointer>(static_cast<__node_base_pointer>(__ptr_)); @@ -691,50 +764,54 @@ private: friend class __tree; template <class, class, class> friend class __tree_const_iterator; - template <class> - friend class __map_iterator; - template <class, class, class, class> - friend class map; - template <class, class, class, class> - friend class multimap; - template <class, class, class> - friend class set; - template <class, class, class> - friend class multiset; + + template <class _NodeIter, class _Func, class _Proj> + friend void __tree_iterate_subrange(_NodeIter, _NodeIter, _Func&, _Proj&); +}; + +#ifndef _LIBCPP_CXX03_LANG +// This also handles {multi,}set::iterator, since they're just aliases to __tree::iterator +template <class _Tp, class _NodePtr, class _DiffType> +struct __specialized_algorithm< + _Algorithm::__for_each, + __iterator_pair<__tree_iterator<_Tp, _NodePtr, _DiffType>, __tree_iterator<_Tp, _NodePtr, _DiffType>>> { + static const bool __has_algorithm = true; + + using __iterator _LIBCPP_NODEBUG = __tree_iterator<_Tp, _NodePtr, _DiffType>; + + template <class _Func, class _Proj> + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Func& __func, _Proj& __proj) { + std::__tree_iterate_subrange(__first, __last, __func, __proj); + } }; +#endif template <class _Tp, class _NodePtr, class _DiffType> class __tree_const_iterator { - typedef __tree_node_types<_NodePtr> _NodeTypes; + using _NodeTypes _LIBCPP_NODEBUG = __tree_node_types<_NodePtr>; // NOLINTNEXTLINE(libcpp-nodebug-on-aliases) lldb relies on this alias for pretty printing - using __node_pointer = _NodePtr; - typedef typename _NodeTypes::__node_base_pointer __node_base_pointer; - typedef typename _NodeTypes::__end_node_pointer __end_node_pointer; + using __node_pointer = _NodePtr; + using __node_base_pointer _LIBCPP_NODEBUG = typename _NodeTypes::__node_base_pointer; + using __end_node_pointer _LIBCPP_NODEBUG = typename _NodeTypes::__end_node_pointer; __end_node_pointer __ptr_; public: - using iterator_category = bidirectional_iterator_tag; - using value_type = __get_node_value_type_t<_Tp>; - using difference_type = _DiffType; - using reference = const value_type&; - using pointer = __rebind_pointer_t<_NodePtr, const value_type>; + using iterator_category = bidirectional_iterator_tag; + using value_type = __get_node_value_type_t<_Tp>; + using difference_type = _DiffType; + using reference = const value_type&; + using pointer = __rebind_pointer_t<_NodePtr, const value_type>; + using __non_const_iterator _LIBCPP_NODEBUG = __tree_iterator<_Tp, __node_pointer, difference_type>; - _LIBCPP_HIDE_FROM_ABI __tree_const_iterator() _NOEXCEPT -#if _LIBCPP_STD_VER >= 14 - : __ptr_(nullptr) -#endif - { - } - -private: - typedef __tree_iterator<_Tp, __node_pointer, difference_type> __non_const_iterator; + _LIBCPP_HIDE_FROM_ABI __tree_const_iterator() _NOEXCEPT : __ptr_(nullptr) {} -public: _LIBCPP_HIDE_FROM_ABI __tree_const_iterator(__non_const_iterator __p) _NOEXCEPT : __ptr_(__p.__ptr_) {} - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_np()->__value_; } - _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return pointer_traits<pointer>::pointer_to(__get_np()->__value_); } + _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __get_np()->__get_value(); } + _LIBCPP_HIDE_FROM_ABI pointer operator->() const { + return pointer_traits<pointer>::pointer_to(__get_np()->__get_value()); + } _LIBCPP_HIDE_FROM_ABI __tree_const_iterator& operator++() { __ptr_ = std::__tree_next_iter<__end_node_pointer>(static_cast<__node_base_pointer>(__ptr_)); @@ -772,18 +849,28 @@ private: template <class, class, class> friend class __tree; - template <class, class, class, class> - friend class map; - template <class, class, class, class> - friend class multimap; - template <class, class, class> - friend class set; - template <class, class, class> - friend class multiset; - template <class> - friend class __map_const_iterator; + + template <class _NodeIter, class _Func, class _Proj> + friend void __tree_iterate_subrange(_NodeIter, _NodeIter, _Func&, _Proj&); }; +#ifndef _LIBCPP_CXX03_LANG +// This also handles {multi,}set::const_iterator, since they're just aliases to __tree::iterator +template <class _Tp, class _NodePtr, class _DiffType> +struct __specialized_algorithm< + _Algorithm::__for_each, + __iterator_pair<__tree_const_iterator<_Tp, _NodePtr, _DiffType>, __tree_const_iterator<_Tp, _NodePtr, _DiffType>>> { + static const bool __has_algorithm = true; + + using __iterator _LIBCPP_NODEBUG = __tree_const_iterator<_Tp, _NodePtr, _DiffType>; + + template <class _Func, class _Proj> + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Func& __func, _Proj& __proj) { + std::__tree_iterate_subrange(__first, __last, __func, __proj); + } +}; +#endif + template <class _Tp, class _Compare> #ifndef _LIBCPP_CXX03_LANG _LIBCPP_DIAGNOSE_WARNING(!__is_invocable_v<_Compare const&, _Tp const&, _Tp const&>, @@ -794,21 +881,20 @@ int __diagnose_non_const_comparator(); template <class _Tp, class _Compare, class _Allocator> class __tree { public: - using value_type = __get_node_value_type_t<_Tp>; - typedef _Compare value_compare; - typedef _Allocator allocator_type; + using value_type = __get_node_value_type_t<_Tp>; + using value_compare = _Compare; + using allocator_type = _Allocator; private: - typedef allocator_traits<allocator_type> __alloc_traits; - using key_type = __get_tree_key_type_t<_Tp>; + using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<allocator_type>; + using key_type = __get_tree_key_type_t<_Tp>; public: - typedef typename __alloc_traits::pointer pointer; - typedef typename __alloc_traits::const_pointer const_pointer; - typedef typename __alloc_traits::size_type size_type; - typedef typename __alloc_traits::difference_type difference_type; + using pointer = typename __alloc_traits::pointer; + using const_pointer = typename __alloc_traits::const_pointer; + using size_type = typename __alloc_traits::size_type; + using difference_type = typename __alloc_traits::difference_type; -public: using __void_pointer _LIBCPP_NODEBUG = typename __alloc_traits::void_pointer; using __node _LIBCPP_NODEBUG = __tree_node<_Tp, __void_pointer>; @@ -821,22 +907,8 @@ public: using __end_node_t _LIBCPP_NODEBUG = __tree_end_node<__node_base_pointer>; using __end_node_pointer _LIBCPP_NODEBUG = __rebind_pointer_t<__void_pointer, __end_node_t>; - using __parent_pointer _LIBCPP_NODEBUG = __end_node_pointer; // TODO: Remove this once the uses in <map> are removed - - typedef __rebind_alloc<__alloc_traits, __node> __node_allocator; - typedef allocator_traits<__node_allocator> __node_traits; - -// TODO(LLVM 22): Remove this check -#ifndef _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB - static_assert(sizeof(__node_base_pointer) == sizeof(__end_node_pointer) && _LIBCPP_ALIGNOF(__node_base_pointer) == - _LIBCPP_ALIGNOF(__end_node_pointer), - "It looks like you are using std::__tree (an implementation detail for (multi)map/set) with a fancy " - "pointer type that thas a different representation depending on whether it points to a __tree base " - "pointer or a __tree node pointer (both of which are implementation details of the standard library). " - "This means that your ABI is being broken between LLVM 19 and LLVM 20. If you don't care about your " - "ABI being broken, define the _LIBCPP_ABI_TREE_REMOVE_NODE_POINTER_UB macro to silence this " - "diagnostic."); -#endif + using __node_allocator _LIBCPP_NODEBUG = __rebind_alloc<__alloc_traits, __node>; + using __node_traits _LIBCPP_NODEBUG = allocator_traits<__node_allocator>; private: // check for sane allocator pointer rebinding semantics. Rebinding the @@ -844,8 +916,8 @@ private: // the pointer using 'pointer_traits'. static_assert(is_same<__node_pointer, typename __node_traits::pointer>::value, "Allocator does not rebind pointers in a sane manner."); - typedef __rebind_alloc<__node_traits, __node_base> __node_base_allocator; - typedef allocator_traits<__node_base_allocator> __node_base_traits; + using __node_base_allocator _LIBCPP_NODEBUG = __rebind_alloc<__node_traits, __node_base>; + using __node_base_traits _LIBCPP_NODEBUG = allocator_traits<__node_base_allocator>; static_assert(is_same<__node_base_pointer, typename __node_base_traits::pointer>::value, "Allocator does not rebind pointers in a sane manner."); @@ -865,17 +937,11 @@ public: private: _LIBCPP_HIDE_FROM_ABI const __node_allocator& __node_alloc() const _NOEXCEPT { return __node_alloc_; } - _LIBCPP_HIDE_FROM_ABI __end_node_pointer& __begin_node() _NOEXCEPT { return __begin_node_; } - _LIBCPP_HIDE_FROM_ABI const __end_node_pointer& __begin_node() const _NOEXCEPT { return __begin_node_; } public: _LIBCPP_HIDE_FROM_ABI allocator_type __alloc() const _NOEXCEPT { return allocator_type(__node_alloc()); } -private: - _LIBCPP_HIDE_FROM_ABI size_type& size() _NOEXCEPT { return __size_; } - -public: - _LIBCPP_HIDE_FROM_ABI const size_type& size() const _NOEXCEPT { return __size_; } + _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } _LIBCPP_HIDE_FROM_ABI value_compare& value_comp() _NOEXCEPT { return __value_comp_; } _LIBCPP_HIDE_FROM_ABI const value_compare& value_comp() const _NOEXCEPT { return __value_comp_; } @@ -888,32 +954,61 @@ public: return std::addressof(__end_node()->__left_); } - typedef __tree_iterator<_Tp, __node_pointer, difference_type> iterator; - typedef __tree_const_iterator<_Tp, __node_pointer, difference_type> const_iterator; + using iterator = __tree_iterator<_Tp, __node_pointer, difference_type>; + using const_iterator = __tree_const_iterator<_Tp, __node_pointer, difference_type>; _LIBCPP_HIDE_FROM_ABI explicit __tree(const value_compare& __comp) _NOEXCEPT_( - is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible<value_compare>::value); - _LIBCPP_HIDE_FROM_ABI explicit __tree(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI __tree(const value_compare& __comp, const allocator_type& __a); + is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible<value_compare>::value) + : __size_(0), __value_comp_(__comp) { + __begin_node_ = __end_node(); + } + + _LIBCPP_HIDE_FROM_ABI explicit __tree(const allocator_type& __a) + : __begin_node_(), __node_alloc_(__node_allocator(__a)), __size_(0) { + __begin_node_ = __end_node(); + } + + _LIBCPP_HIDE_FROM_ABI __tree(const value_compare& __comp, const allocator_type& __a) + : __begin_node_(), __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(__comp) { + __begin_node_ = __end_node(); + } + _LIBCPP_HIDE_FROM_ABI __tree(const __tree& __t); + + _LIBCPP_HIDE_FROM_ABI __tree(const __tree& __other, const allocator_type& __alloc) + : __begin_node_(__end_node()), __node_alloc_(__alloc), __size_(0), __value_comp_(__other.value_comp()) { + if (__other.size() == 0) + return; + + *__root_ptr() = static_cast<__node_base_pointer>(__copy_construct_tree(__other.__root())); + __root()->__parent_ = __end_node(); + __begin_node_ = static_cast<__end_node_pointer>(std::__tree_min(__end_node()->__left_)); + __size_ = __other.size(); + } + _LIBCPP_HIDE_FROM_ABI __tree& operator=(const __tree& __t); template <class _ForwardIterator> _LIBCPP_HIDE_FROM_ABI void __assign_unique(_ForwardIterator __first, _ForwardIterator __last); - template <class _InputIterator> - _LIBCPP_HIDE_FROM_ABI void __assign_multi(_InputIterator __first, _InputIterator __last); _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_( is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible<value_compare>::value); _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value && ((__node_traits::propagate_on_container_move_assignment::value && is_nothrow_move_assignable<__node_allocator>::value) || - allocator_traits<__node_allocator>::is_always_equal::value)); + allocator_traits<__node_allocator>::is_always_equal::value)) { + __move_assign(__t, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>()); + return *this; + } - _LIBCPP_HIDE_FROM_ABI ~__tree(); + _LIBCPP_HIDE_FROM_ABI ~__tree() { + static_assert(is_copy_constructible<value_compare>::value, "Comparator must be copy-constructible."); + destroy(__root()); + } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node()); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return const_iterator(__begin_node()); } + _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node_); } + _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return const_iterator(__begin_node_); } _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return iterator(__end_node()); } _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return const_iterator(__end_node()); } @@ -931,116 +1026,151 @@ public: _NOEXCEPT_(__is_nothrow_swappable_v<value_compare>); #endif - template <class _Key, class... _Args> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_key_args(_Key const&, _Args&&... __args); - template <class _Key, class... _Args> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_hint_unique_key_args(const_iterator, _Key const&, _Args&&...); - - template <class... _Args> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_impl(_Args&&... __args); - - template <class... _Args> - _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_unique_impl(const_iterator __p, _Args&&... __args); - template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator __emplace_multi(_Args&&... __args); template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_multi(const_iterator __p, _Args&&... __args); - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Pp&& __x) { - return __emplace_unique_extract_key(std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>()); - } - - template <class _First, - class _Second, - __enable_if_t<__can_extract_map_key<_First, key_type, value_type>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_First&& __f, _Second&& __s) { - return __emplace_unique_key_args(__f, std::forward<_First>(__f), std::forward<_Second>(__s)); - } - template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique(_Args&&... __args) { - return __emplace_unique_impl(std::forward<_Args>(__args)...); - } - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_fail_tag) { - return __emplace_unique_impl(std::forward<_Pp>(__x)); - } - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_self_tag) { - return __emplace_unique_key_args(__x, std::forward<_Pp>(__x)); - } - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_unique_extract_key(_Pp&& __x, __extract_key_first_tag) { - return __emplace_unique_key_args(__x.first, std::forward<_Pp>(__x)); - } - - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_unique(const_iterator __p, _Pp&& __x) { - return __emplace_hint_unique_extract_key(__p, std::forward<_Pp>(__x), __can_extract_key<_Pp, key_type>()); - } - - template <class _First, - class _Second, - __enable_if_t<__can_extract_map_key<_First, key_type, value_type>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_unique(const_iterator __p, _First&& __f, _Second&& __s) { - return __emplace_hint_unique_key_args(__p, __f, std::forward<_First>(__f), std::forward<_Second>(__s)).first; + return std::__try_key_extraction<key_type>( + [this](const key_type& __key, _Args&&... __args2) { + auto [__parent, __child] = __find_equal(__key); + __node_pointer __r = static_cast<__node_pointer>(__child); + bool __inserted = false; + if (__child == nullptr) { + __node_holder __h = __construct_node(std::forward<_Args>(__args2)...); + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); + __r = __h.release(); + __inserted = true; + } + return pair<iterator, bool>(iterator(__r), __inserted); + }, + [this](_Args&&... __args2) { + __node_holder __h = __construct_node(std::forward<_Args>(__args2)...); + auto [__parent, __child] = __find_equal(__h->__get_value()); + __node_pointer __r = static_cast<__node_pointer>(__child); + bool __inserted = false; + if (__child == nullptr) { + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); + __r = __h.release(); + __inserted = true; + } + return pair<iterator, bool>(iterator(__r), __inserted); + }, + std::forward<_Args>(__args)...); } template <class... _Args> - _LIBCPP_HIDE_FROM_ABI iterator __emplace_hint_unique(const_iterator __p, _Args&&... __args) { - return __emplace_hint_unique_impl(__p, std::forward<_Args>(__args)...); + _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace_hint_unique(const_iterator __p, _Args&&... __args) { + return std::__try_key_extraction<key_type>( + [this, __p](const key_type& __key, _Args&&... __args2) { + __node_base_pointer __dummy; + auto [__parent, __child] = __find_equal(__p, __dummy, __key); + __node_pointer __r = static_cast<__node_pointer>(__child); + bool __inserted = false; + if (__child == nullptr) { + __node_holder __h = __construct_node(std::forward<_Args>(__args2)...); + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); + __r = __h.release(); + __inserted = true; + } + return pair<iterator, bool>(iterator(__r), __inserted); + }, + [this, __p](_Args&&... __args2) { + __node_holder __h = __construct_node(std::forward<_Args>(__args2)...); + __node_base_pointer __dummy; + auto [__parent, __child] = __find_equal(__p, __dummy, __h->__get_value()); + __node_pointer __r = static_cast<__node_pointer>(__child); + if (__child == nullptr) { + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); + __r = __h.release(); + } + return pair<iterator, bool>(iterator(__r), __child == nullptr); + }, + std::forward<_Args>(__args)...); } - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI iterator - __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_fail_tag) { - return __emplace_hint_unique_impl(__p, std::forward<_Pp>(__x)); - } + template <class _InIter, class _Sent> + _LIBCPP_HIDE_FROM_ABI void __insert_range_multi(_InIter __first, _Sent __last) { + if (__first == __last) + return; - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI iterator - __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_self_tag) { - return __emplace_hint_unique_key_args(__p, __x, std::forward<_Pp>(__x)).first; - } + if (__root() == nullptr) { // Make sure we always have a root node + __insert_node_at( + __end_node(), __end_node()->__left_, static_cast<__node_base_pointer>(__construct_node(*__first).release())); + ++__first; + } - template <class _Pp> - _LIBCPP_HIDE_FROM_ABI iterator - __emplace_hint_unique_extract_key(const_iterator __p, _Pp&& __x, __extract_key_first_tag) { - return __emplace_hint_unique_key_args(__p, __x.first, std::forward<_Pp>(__x)).first; - } + auto __max_node = static_cast<__node_pointer>(std::__tree_max(static_cast<__node_base_pointer>(__root()))); - template <class _ValueT = _Tp, __enable_if_t<__is_tree_value_type<_ValueT>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI void - __insert_unique_from_orphaned_node(const_iterator __p, __get_node_value_type_t<_Tp>&& __value) { - __emplace_hint_unique(__p, const_cast<key_type&&>(__value.first), std::move(__value.second)); + for (; __first != __last; ++__first) { + __node_holder __nd = __construct_node(*__first); + // Always check the max node first. This optimizes for sorted ranges inserted at the end. + if (!value_comp()(__nd->__get_value(), __max_node->__get_value())) { // __node >= __max_val + __insert_node_at(static_cast<__end_node_pointer>(__max_node), + __max_node->__right_, + static_cast<__node_base_pointer>(__nd.get())); + __max_node = __nd.release(); + } else { + __end_node_pointer __parent; + __node_base_pointer& __child = __find_leaf_high(__parent, __nd->__get_value()); + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release())); + } + } } - template <class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type<_ValueT>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI void __insert_unique_from_orphaned_node(const_iterator __p, _Tp&& __value) { - __emplace_hint_unique(__p, std::move(__value)); - } + template <class _InIter, class _Sent> + _LIBCPP_HIDE_FROM_ABI void __insert_range_unique(_InIter __first, _Sent __last) { + if (__first == __last) + return; - template <class _ValueT = _Tp, __enable_if_t<__is_tree_value_type<_ValueT>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(const_iterator __p, value_type&& __value) { - __emplace_hint_multi(__p, const_cast<key_type&&>(__value.first), std::move(__value.second)); - } + if (__root() == nullptr) { + __insert_node_at( + __end_node(), __end_node()->__left_, static_cast<__node_base_pointer>(__construct_node(*__first).release())); + ++__first; + } - template <class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type<_ValueT>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI void __insert_multi_from_orphaned_node(const_iterator __p, _Tp&& __value) { - __emplace_hint_multi(__p, std::move(__value)); + auto __max_node = static_cast<__node_pointer>(std::__tree_max(static_cast<__node_base_pointer>(__root()))); + + using __reference = decltype(*__first); + + for (; __first != __last; ++__first) { + std::__try_key_extraction<key_type>( + [this, &__max_node](const key_type& __key, __reference&& __val) { + if (value_comp()(__max_node->__get_value(), __key)) { // __key > __max_node + __node_holder __nd = __construct_node(std::forward<__reference>(__val)); + __insert_node_at(static_cast<__end_node_pointer>(__max_node), + __max_node->__right_, + static_cast<__node_base_pointer>(__nd.get())); + __max_node = __nd.release(); + } else { + auto [__parent, __child] = __find_equal(__key); + if (__child == nullptr) { + __node_holder __nd = __construct_node(std::forward<__reference>(__val)); + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release())); + } + } + }, + [this, &__max_node](__reference&& __val) { + __node_holder __nd = __construct_node(std::forward<__reference>(__val)); + if (value_comp()(__max_node->__get_value(), __nd->__get_value())) { // __node > __max_node + __insert_node_at(static_cast<__end_node_pointer>(__max_node), + __max_node->__right_, + static_cast<__node_base_pointer>(__nd.get())); + __max_node = __nd.release(); + } else { + auto [__parent, __child] = __find_equal(__nd->__get_value()); + if (__child == nullptr) { + __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd.release())); + } + } + }, + *__first); + } } - _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __node_assign_unique(const value_type& __v, __node_pointer __dest); - - _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(__node_pointer __nd); - _LIBCPP_HIDE_FROM_ABI iterator __node_insert_multi(const_iterator __p, __node_pointer __nd); - _LIBCPP_HIDE_FROM_ABI iterator __remove_node_pointer(__node_pointer) _NOEXCEPT; #if _LIBCPP_STD_VER >= 17 @@ -1048,15 +1178,15 @@ public: _LIBCPP_HIDE_FROM_ABI _InsertReturnType __node_handle_insert_unique(_NodeHandle&&); template <class _NodeHandle> _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_unique(const_iterator, _NodeHandle&&); - template <class _Tree> - _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_unique(_Tree& __source); + template <class _Comp2> + _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_unique(__tree<_Tp, _Comp2, _Allocator>& __source); template <class _NodeHandle> _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(_NodeHandle&&); template <class _NodeHandle> _LIBCPP_HIDE_FROM_ABI iterator __node_handle_insert_multi(const_iterator, _NodeHandle&&); - template <class _Tree> - _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(_Tree& __source); + template <class _Comp2> + _LIBCPP_HIDE_FROM_ABI void __node_handle_merge_multi(__tree<_Tp, _Comp2, _Allocator>& __source); template <class _NodeHandle> _LIBCPP_HIDE_FROM_ABI _NodeHandle __node_handle_extract(key_type const&); @@ -1075,41 +1205,157 @@ public: __insert_node_at(__end_node_pointer __parent, __node_base_pointer& __child, __node_base_pointer __new_node) _NOEXCEPT; template <class _Key> - _LIBCPP_HIDE_FROM_ABI iterator find(const _Key& __v); + _LIBCPP_HIDE_FROM_ABI iterator find(const _Key& __key) { + auto [__, __match] = __find_equal(__key); + if (__match == nullptr) + return end(); + return iterator(static_cast<__node_pointer>(__match)); + } + template <class _Key> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Key& __v) const; + _LIBCPP_HIDE_FROM_ABI const_iterator find(const _Key& __key) const { + auto [__, __match] = __find_equal(__key); + if (__match == nullptr) + return end(); + return const_iterator(static_cast<__node_pointer>(__match)); + } template <class _Key> _LIBCPP_HIDE_FROM_ABI size_type __count_unique(const _Key& __k) const; template <class _Key> _LIBCPP_HIDE_FROM_ABI size_type __count_multi(const _Key& __k) const; + template <bool _LowerBound, class _Key> + _LIBCPP_HIDE_FROM_ABI __end_node_pointer __lower_upper_bound_unique_impl(const _Key& __v) const { + auto __rt = __root(); + auto __result = __end_node(); + auto __comp = __lazy_synth_three_way_comparator<_Compare, _Key, value_type>(value_comp()); + while (__rt != nullptr) { + auto __comp_res = __comp(__v, __rt->__get_value()); + + if (__comp_res.__less()) { + __result = static_cast<__end_node_pointer>(__rt); + __rt = static_cast<__node_pointer>(__rt->__left_); + } else if (__comp_res.__greater()) { + __rt = static_cast<__node_pointer>(__rt->__right_); + } else if _LIBCPP_CONSTEXPR (_LowerBound) { + return static_cast<__end_node_pointer>(__rt); + } else { + return __rt->__right_ ? static_cast<__end_node_pointer>(std::__tree_min(__rt->__right_)) : __result; + } + } + return __result; + } + + // Compatibility escape hatch for comparators that are not strict weak orderings. This + // can be removed for the LLVM 23 release. +#if defined(_LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND) template <class _Key> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Key& __v) { - return __lower_bound(__v, __root(), __end_node()); + _LIBCPP_HIDE_FROM_ABI __end_node_pointer __lower_bound_unique_compat_impl(const _Key& __v) const { + auto __rt = __root(); + auto __result = __end_node(); + while (__rt != nullptr) { + if (!value_comp()(__rt->__get_value(), __v)) { + __result = std::__static_fancy_pointer_cast<__end_node_pointer>(__rt); + __rt = std::__static_fancy_pointer_cast<__node_pointer>(__rt->__left_); + } else { + __rt = std::__static_fancy_pointer_cast<__node_pointer>(__rt->__right_); + } + } + return __result; } + template <class _Key> - _LIBCPP_HIDE_FROM_ABI iterator __lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result); + _LIBCPP_HIDE_FROM_ABI __end_node_pointer __upper_bound_unique_compat_impl(const _Key& __v) const { + auto __rt = __root(); + auto __result = __end_node(); + while (__rt != nullptr) { + if (value_comp()(__v, __rt->__get_value())) { + __result = std::__static_fancy_pointer_cast<__end_node_pointer>(__rt); + __rt = std::__static_fancy_pointer_cast<__node_pointer>(__rt->__left_); + } else { + __rt = std::__static_fancy_pointer_cast<__node_pointer>(__rt->__right_); + } + } + return __result; + } +#endif // _LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND + template <class _Key> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Key& __v) const { - return __lower_bound(__v, __root(), __end_node()); + _LIBCPP_HIDE_FROM_ABI iterator __lower_bound_unique(const _Key& __v) { +#if defined(_LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND) + return iterator(__lower_bound_unique_compat_impl(__v)); +#else + return iterator(__lower_upper_bound_unique_impl<true>(__v)); +#endif } + + template <class _Key> + _LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_unique(const _Key& __v) const { +#if defined(_LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND) + return const_iterator(__lower_bound_unique_compat_impl(__v)); +#else + return const_iterator(__lower_upper_bound_unique_impl<true>(__v)); +#endif + } + + template <class _Key> + _LIBCPP_HIDE_FROM_ABI iterator __upper_bound_unique(const _Key& __v) { +#if defined(_LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND) + return iterator(__upper_bound_unique_compat_impl(__v)); +#else + return iterator(__lower_upper_bound_unique_impl<false>(__v)); +#endif + } + + template <class _Key> + _LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_unique(const _Key& __v) const { +#if defined(_LIBCPP_ENABLE_LEGACY_TREE_LOWER_UPPER_BOUND) + return iterator(__upper_bound_unique_compat_impl(__v)); +#else + return iterator(__lower_upper_bound_unique_impl<false>(__v)); +#endif + } + +private: + template <class _Key> + _LIBCPP_HIDE_FROM_ABI iterator + __lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result); + template <class _Key> _LIBCPP_HIDE_FROM_ABI const_iterator - __lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const; + __lower_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const; + +public: template <class _Key> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Key& __v) { - return __upper_bound(__v, __root(), __end_node()); + _LIBCPP_HIDE_FROM_ABI iterator __lower_bound_multi(const _Key& __v) { + return __lower_bound_multi(__v, __root(), __end_node()); } template <class _Key> - _LIBCPP_HIDE_FROM_ABI iterator __upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result); + _LIBCPP_HIDE_FROM_ABI const_iterator __lower_bound_multi(const _Key& __v) const { + return __lower_bound_multi(__v, __root(), __end_node()); + } + + template <class _Key> + _LIBCPP_HIDE_FROM_ABI iterator __upper_bound_multi(const _Key& __v) { + return __upper_bound_multi(__v, __root(), __end_node()); + } + template <class _Key> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Key& __v) const { - return __upper_bound(__v, __root(), __end_node()); + _LIBCPP_HIDE_FROM_ABI const_iterator __upper_bound_multi(const _Key& __v) const { + return __upper_bound_multi(__v, __root(), __end_node()); } + +private: + template <class _Key> + _LIBCPP_HIDE_FROM_ABI iterator + __upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result); + template <class _Key> _LIBCPP_HIDE_FROM_ABI const_iterator - __upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const; + __upper_bound_multi(const _Key& __v, __node_pointer __root, __end_node_pointer __result) const; + +public: template <class _Key> _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> __equal_range_unique(const _Key& __k); template <class _Key> @@ -1120,22 +1366,24 @@ public: template <class _Key> _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> __equal_range_multi(const _Key& __k) const; - typedef __tree_node_destructor<__node_allocator> _Dp; - typedef unique_ptr<__node, _Dp> __node_holder; + using _Dp _LIBCPP_NODEBUG = __tree_node_destructor<__node_allocator>; + using __node_holder _LIBCPP_NODEBUG = unique_ptr<__node, _Dp>; _LIBCPP_HIDE_FROM_ABI __node_holder remove(const_iterator __p) _NOEXCEPT; // FIXME: Make this function const qualified. Unfortunately doing so // breaks existing code which uses non-const callable comparators. template <class _Key> - _LIBCPP_HIDE_FROM_ABI __node_base_pointer& __find_equal(__end_node_pointer& __parent, const _Key& __v); + _LIBCPP_HIDE_FROM_ABI pair<__end_node_pointer, __node_base_pointer&> __find_equal(const _Key& __v); + template <class _Key> - _LIBCPP_HIDE_FROM_ABI __node_base_pointer& __find_equal(__end_node_pointer& __parent, const _Key& __v) const { - return const_cast<__tree*>(this)->__find_equal(__parent, __v); + _LIBCPP_HIDE_FROM_ABI pair<__end_node_pointer, __node_base_pointer&> __find_equal(const _Key& __v) const { + return const_cast<__tree*>(this)->__find_equal(__v); } + template <class _Key> - _LIBCPP_HIDE_FROM_ABI __node_base_pointer& - __find_equal(const_iterator __hint, __end_node_pointer& __parent, __node_base_pointer& __dummy, const _Key& __v); + _LIBCPP_HIDE_FROM_ABI pair<__end_node_pointer, __node_base_pointer&> + __find_equal(const_iterator __hint, __node_base_pointer& __dummy, const _Key& __v); _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const __tree& __t) { __copy_assign_alloc(__t, integral_constant<bool, __node_traits::propagate_on_container_copy_assignment::value>()); @@ -1160,7 +1408,7 @@ private: _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node(_Args&&... __args); // TODO: Make this _LIBCPP_HIDE_FROM_ABI - _LIBCPP_HIDDEN void destroy(__node_pointer __nd) _NOEXCEPT; + _LIBCPP_HIDDEN void destroy(__node_pointer __nd) _NOEXCEPT { (__tree_deleter(__node_alloc_))(__nd); } _LIBCPP_HIDE_FROM_ABI void __move_assign(__tree& __t, false_type); _LIBCPP_HIDE_FROM_ABI void __move_assign(__tree& __t, true_type) _NOEXCEPT_( @@ -1178,7 +1426,7 @@ private: } _LIBCPP_HIDE_FROM_ABI void __move_assign_alloc(__tree&, false_type) _NOEXCEPT {} - template <class _From, class _ValueT = _Tp, __enable_if_t<__is_tree_value_type<_ValueT>::value, int> = 0> + template <class _From, class _ValueT = _Tp, __enable_if_t<__is_tree_value_type_v<_ValueT>, int> = 0> _LIBCPP_HIDE_FROM_ABI static void __assign_value(__get_node_value_type_t<value_type>& __lhs, _From&& __rhs) { using __key_type = __remove_const_t<typename value_type::first_type>; @@ -1188,166 +1436,203 @@ private: __lhs.second = std::forward<_From>(__rhs).second; } - template <class _To, class _From, class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type<_ValueT>::value, int> = 0> + template <class _To, class _From, class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type_v<_ValueT>, int> = 0> _LIBCPP_HIDE_FROM_ABI static void __assign_value(_To& __lhs, _From&& __rhs) { __lhs = std::forward<_From>(__rhs); } - struct _DetachedTreeCache { - _LIBCPP_HIDE_FROM_ABI explicit _DetachedTreeCache(__tree* __t) _NOEXCEPT - : __t_(__t), - __cache_root_(__detach_from_tree(__t)) { - __advance(); + class __tree_deleter { + __node_allocator& __alloc_; + + public: + using pointer = __node_pointer; + + _LIBCPP_HIDE_FROM_ABI __tree_deleter(__node_allocator& __alloc) : __alloc_(__alloc) {} + +#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function + _LIBCPP_HIDE_FROM_ABI +#endif + void + operator()(__node_pointer __ptr) { + if (!__ptr) + return; + + (*this)(static_cast<__node_pointer>(__ptr->__left_)); + + auto __right = __ptr->__right_; + + __node_traits::destroy(__alloc_, std::addressof(__ptr->__get_value())); + __node_traits::deallocate(__alloc_, __ptr, 1); + + (*this)(static_cast<__node_pointer>(__right)); } + }; + + // This copy construction will always produce a correct red-black-tree assuming the incoming tree is correct, since we + // copy the exact structure 1:1. Since this is for copy construction _only_ we know that we get a correct tree. If we + // didn't get a correct tree, the invariants of __tree are broken and we have a much bigger problem than an improperly + // balanced tree. + template <class _NodeConstructor> +#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function + _LIBCPP_HIDE_FROM_ABI +#endif + __node_pointer __construct_from_tree(__node_pointer __src, _NodeConstructor __construct) { + if (!__src) + return nullptr; - _LIBCPP_HIDE_FROM_ABI __node_pointer __get() const _NOEXCEPT { return __cache_elem_; } + __node_holder __new_node = __construct(__src->__get_value()); - _LIBCPP_HIDE_FROM_ABI void __advance() _NOEXCEPT { - __cache_elem_ = __cache_root_; - if (__cache_root_) { - __cache_root_ = __detach_next(__cache_root_); - } + unique_ptr<__node, __tree_deleter> __left( + __construct_from_tree(static_cast<__node_pointer>(__src->__left_), __construct), __node_alloc_); + __node_pointer __right = __construct_from_tree(static_cast<__node_pointer>(__src->__right_), __construct); + + __node_pointer __new_node_ptr = __new_node.release(); + + __new_node_ptr->__is_black_ = __src->__is_black_; + __new_node_ptr->__left_ = static_cast<__node_base_pointer>(__left.release()); + __new_node_ptr->__right_ = static_cast<__node_base_pointer>(__right); + if (__new_node_ptr->__left_) + __new_node_ptr->__left_->__parent_ = static_cast<__end_node_pointer>(__new_node_ptr); + if (__new_node_ptr->__right_) + __new_node_ptr->__right_->__parent_ = static_cast<__end_node_pointer>(__new_node_ptr); + return __new_node_ptr; + } + + _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_construct_tree(__node_pointer __src) { + return __construct_from_tree(__src, [this](const value_type& __val) { return __construct_node(__val); }); + } + + template <class _ValueT = _Tp, __enable_if_t<__is_tree_value_type_v<_ValueT>, int> = 0> + _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree(__node_pointer __src) { + return __construct_from_tree(__src, [this](value_type& __val) { + return __construct_node(const_cast<key_type&&>(__val.first), std::move(__val.second)); + }); + } + + template <class _ValueT = _Tp, __enable_if_t<!__is_tree_value_type_v<_ValueT>, int> = 0> + _LIBCPP_HIDE_FROM_ABI __node_pointer __move_construct_tree(__node_pointer __src) { + return __construct_from_tree(__src, [this](value_type& __val) { return __construct_node(std::move(__val)); }); + } + + template <class _Assignment, class _ConstructionAlg> + // This copy assignment will always produce a correct red-black-tree assuming the incoming tree is correct, since our + // own tree is a red-black-tree and the incoming tree is a red-black-tree. The invariants of a red-black-tree are + // temporarily not met until all of the incoming red-black tree is copied. +#ifdef _LIBCPP_COMPILER_CLANG_BASED // FIXME: GCC complains about not being able to always_inline a recursive function + _LIBCPP_HIDE_FROM_ABI +#endif + __node_pointer __assign_from_tree( + __node_pointer __dest, __node_pointer __src, _Assignment __assign, _ConstructionAlg __construct_subtree) { + if (!__src) { + destroy(__dest); + return nullptr; } - _LIBCPP_HIDE_FROM_ABI ~_DetachedTreeCache() { - __t_->destroy(__cache_elem_); - if (__cache_root_) { - while (__cache_root_->__parent_ != nullptr) - __cache_root_ = static_cast<__node_pointer>(__cache_root_->__parent_); - __t_->destroy(__cache_root_); - } + __assign(__dest->__get_value(), __src->__get_value()); + __dest->__is_black_ = __src->__is_black_; + + // If we already have a left node in the destination tree, reuse it and copy-assign recursively + if (__dest->__left_) { + __dest->__left_ = static_cast<__node_base_pointer>(__assign_from_tree( + static_cast<__node_pointer>(__dest->__left_), + static_cast<__node_pointer>(__src->__left_), + __assign, + __construct_subtree)); + + // Otherwise, we must create new nodes; copy-construct from here on + } else if (__src->__left_) { + auto __new_left = __construct_subtree(static_cast<__node_pointer>(__src->__left_)); + __dest->__left_ = static_cast<__node_base_pointer>(__new_left); + __new_left->__parent_ = static_cast<__end_node_pointer>(__dest); } - _DetachedTreeCache(_DetachedTreeCache const&) = delete; - _DetachedTreeCache& operator=(_DetachedTreeCache const&) = delete; + // Identical to the left case above, just for the right nodes + if (__dest->__right_) { + __dest->__right_ = static_cast<__node_base_pointer>(__assign_from_tree( + static_cast<__node_pointer>(__dest->__right_), + static_cast<__node_pointer>(__src->__right_), + __assign, + __construct_subtree)); + } else if (__src->__right_) { + auto __new_right = __construct_subtree(static_cast<__node_pointer>(__src->__right_)); + __dest->__right_ = static_cast<__node_base_pointer>(__new_right); + __new_right->__parent_ = static_cast<__end_node_pointer>(__dest); + } - private: - _LIBCPP_HIDE_FROM_ABI static __node_pointer __detach_from_tree(__tree* __t) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI static __node_pointer __detach_next(__node_pointer) _NOEXCEPT; + return __dest; + } - __tree* __t_; - __node_pointer __cache_root_; - __node_pointer __cache_elem_; - }; -}; + _LIBCPP_HIDE_FROM_ABI __node_pointer __copy_assign_tree(__node_pointer __dest, __node_pointer __src) { + return __assign_from_tree( + __dest, + __src, + [](value_type& __lhs, const value_type& __rhs) { __assign_value(__lhs, __rhs); }, + [this](__node_pointer __nd) { return __copy_construct_tree(__nd); }); + } -template <class _Tp, class _Compare, class _Allocator> -__tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp) _NOEXCEPT_( - is_nothrow_default_constructible<__node_allocator>::value&& is_nothrow_copy_constructible<value_compare>::value) - : __size_(0), __value_comp_(__comp) { - __begin_node() = __end_node(); -} + _LIBCPP_HIDE_FROM_ABI __node_pointer __move_assign_tree(__node_pointer __dest, __node_pointer __src) { + return __assign_from_tree( + __dest, + __src, + [](value_type& __lhs, value_type& __rhs) { __assign_value(__lhs, std::move(__rhs)); }, + [this](__node_pointer __nd) { return __move_construct_tree(__nd); }); + } -template <class _Tp, class _Compare, class _Allocator> -__tree<_Tp, _Compare, _Allocator>::__tree(const allocator_type& __a) - : __begin_node_(), __node_alloc_(__node_allocator(__a)), __size_(0) { - __begin_node() = __end_node(); -} + friend struct __specialized_algorithm<_Algorithm::__for_each, __single_range<__tree> >; +}; +#if _LIBCPP_STD_VER >= 14 template <class _Tp, class _Compare, class _Allocator> -__tree<_Tp, _Compare, _Allocator>::__tree(const value_compare& __comp, const allocator_type& __a) - : __begin_node_(), __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(__comp) { - __begin_node() = __end_node(); -} +struct __specialized_algorithm<_Algorithm::__for_each, __single_range<__tree<_Tp, _Compare, _Allocator> > > { + static const bool __has_algorithm = true; -// Precondition: size() != 0 -template <class _Tp, class _Compare, class _Allocator> -typename __tree<_Tp, _Compare, _Allocator>::__node_pointer -__tree<_Tp, _Compare, _Allocator>::_DetachedTreeCache::__detach_from_tree(__tree* __t) _NOEXCEPT { - __node_pointer __cache = static_cast<__node_pointer>(__t->__begin_node()); - __t->__begin_node() = __t->__end_node(); - __t->__end_node()->__left_->__parent_ = nullptr; - __t->__end_node()->__left_ = nullptr; - __t->size() = 0; - // __cache->__left_ == nullptr - if (__cache->__right_ != nullptr) - __cache = static_cast<__node_pointer>(__cache->__right_); - // __cache->__left_ == nullptr - // __cache->__right_ == nullptr - return __cache; -} + using __node_pointer _LIBCPP_NODEBUG = typename __tree<_Tp, _Compare, _Allocator>::__node_pointer; -// Precondition: __cache != nullptr -// __cache->left_ == nullptr -// __cache->right_ == nullptr -// This is no longer a red-black tree -template <class _Tp, class _Compare, class _Allocator> -typename __tree<_Tp, _Compare, _Allocator>::__node_pointer -__tree<_Tp, _Compare, _Allocator>::_DetachedTreeCache::__detach_next(__node_pointer __cache) _NOEXCEPT { - if (__cache->__parent_ == nullptr) - return nullptr; - if (std::__tree_is_left_child(static_cast<__node_base_pointer>(__cache))) { - __cache->__parent_->__left_ = nullptr; - __cache = static_cast<__node_pointer>(__cache->__parent_); - if (__cache->__right_ == nullptr) - return __cache; - return static_cast<__node_pointer>(std::__tree_leaf(__cache->__right_)); - } - // __cache is right child - __cache->__parent_unsafe()->__right_ = nullptr; - __cache = static_cast<__node_pointer>(__cache->__parent_); - if (__cache->__left_ == nullptr) - return __cache; - return static_cast<__node_pointer>(std::__tree_leaf(__cache->__left_)); -} + template <class _Tree, class _Func, class _Proj> + _LIBCPP_HIDE_FROM_ABI static auto operator()(_Tree&& __range, _Func __func, _Proj __proj) { + if (__range.size() != 0) + std::__tree_iterate_from_root<__copy_cvref_t<_Tree, typename __remove_cvref_t<_Tree>::value_type>>( + [](__node_pointer) { return false; }, __range.__root(), __func, __proj); + return std::make_pair(__range.end(), std::move(__func)); + } +}; +#endif template <class _Tp, class _Compare, class _Allocator> __tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(const __tree& __t) { - if (this != std::addressof(__t)) { - value_comp() = __t.value_comp(); - __copy_assign_alloc(__t); - __assign_multi(__t.begin(), __t.end()); - } - return *this; -} + if (this == std::addressof(__t)) + return *this; -template <class _Tp, class _Compare, class _Allocator> -template <class _ForwardIterator> -void __tree<_Tp, _Compare, _Allocator>::__assign_unique(_ForwardIterator __first, _ForwardIterator __last) { - typedef iterator_traits<_ForwardIterator> _ITraits; - typedef typename _ITraits::value_type _ItValueType; - static_assert( - is_same<_ItValueType, value_type>::value, "__assign_unique may only be called with the containers value type"); - static_assert( - __has_forward_iterator_category<_ForwardIterator>::value, "__assign_unique requires a forward iterator"); - if (size() != 0) { - _DetachedTreeCache __cache(this); - for (; __cache.__get() != nullptr && __first != __last; ++__first) { - if (__node_assign_unique(*__first, __cache.__get()).second) - __cache.__advance(); - } - } - for (; __first != __last; ++__first) - __emplace_unique(*__first); -} + value_comp() = __t.value_comp(); + __copy_assign_alloc(__t); -template <class _Tp, class _Compare, class _Allocator> -template <class _InputIterator> -void __tree<_Tp, _Compare, _Allocator>::__assign_multi(_InputIterator __first, _InputIterator __last) { - typedef iterator_traits<_InputIterator> _ITraits; - typedef typename _ITraits::value_type _ItValueType; - static_assert( - is_same<_ItValueType, value_type>::value, "__assign_multi may only be called with the containers value_type"); - if (size() != 0) { - _DetachedTreeCache __cache(this); - for (; __cache.__get() && __first != __last; ++__first) { - __assign_value(__cache.__get()->__value_, *__first); - __node_insert_multi(__cache.__get()); - __cache.__advance(); - } + if (__size_ != 0) { + *__root_ptr() = static_cast<__node_base_pointer>(__copy_assign_tree(__root(), __t.__root())); + } else { + *__root_ptr() = static_cast<__node_base_pointer>(__copy_construct_tree(__t.__root())); + if (__root()) + __root()->__parent_ = __end_node(); } - const_iterator __e = end(); - for (; __first != __last; ++__first) - __emplace_hint_multi(__e, *__first); + __begin_node_ = + __end_node()->__left_ ? static_cast<__end_node_pointer>(std::__tree_min(__end_node()->__left_)) : __end_node(); + __size_ = __t.size(); + + return *this; } template <class _Tp, class _Compare, class _Allocator> __tree<_Tp, _Compare, _Allocator>::__tree(const __tree& __t) - : __begin_node_(), + : __begin_node_(__end_node()), __node_alloc_(__node_traits::select_on_container_copy_construction(__t.__node_alloc())), __size_(0), __value_comp_(__t.value_comp()) { - __begin_node() = __end_node(); + if (__t.size() == 0) + return; + + *__root_ptr() = static_cast<__node_base_pointer>(__copy_construct_tree(__t.__root())); + __root()->__parent_ = __end_node(); + __begin_node_ = static_cast<__end_node_pointer>(std::__tree_min(__end_node()->__left_)); + __size_ = __t.size(); } template <class _Tp, class _Compare, class _Allocator> @@ -1358,33 +1643,38 @@ __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t) _NOEXCEPT_( __node_alloc_(std::move(__t.__node_alloc_)), __size_(__t.__size_), __value_comp_(std::move(__t.__value_comp_)) { - if (size() == 0) - __begin_node() = __end_node(); + if (__size_ == 0) + __begin_node_ = __end_node(); else { __end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node()); - __t.__begin_node() = __t.__end_node(); + __t.__begin_node_ = __t.__end_node(); __t.__end_node()->__left_ = nullptr; - __t.size() = 0; + __t.__size_ = 0; } } template <class _Tp, class _Compare, class _Allocator> __tree<_Tp, _Compare, _Allocator>::__tree(__tree&& __t, const allocator_type& __a) - : __node_alloc_(__node_allocator(__a)), __size_(0), __value_comp_(std::move(__t.value_comp())) { + : __begin_node_(__end_node()), + __node_alloc_(__node_allocator(__a)), + __size_(0), + __value_comp_(std::move(__t.value_comp())) { + if (__t.size() == 0) + return; if (__a == __t.__alloc()) { - if (__t.size() == 0) - __begin_node() = __end_node(); - else { - __begin_node() = __t.__begin_node(); - __end_node()->__left_ = __t.__end_node()->__left_; - __end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node()); - size() = __t.size(); - __t.__begin_node() = __t.__end_node(); - __t.__end_node()->__left_ = nullptr; - __t.size() = 0; - } + __begin_node_ = __t.__begin_node_; + __end_node()->__left_ = __t.__end_node()->__left_; + __end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node()); + __size_ = __t.__size_; + __t.__begin_node_ = __t.__end_node(); + __t.__end_node()->__left_ = nullptr; + __t.__size_ = 0; } else { - __begin_node() = __end_node(); + *__root_ptr() = static_cast<__node_base_pointer>(__move_construct_tree(__t.__root())); + __root()->__parent_ = __end_node(); + __begin_node_ = static_cast<__end_node_pointer>(std::__tree_min(__end_node()->__left_)); + __size_ = __t.size(); + __t.clear(); // Ensure that __t is in a valid state after moving out the keys } } @@ -1397,61 +1687,33 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, true_type) __move_assign_alloc(__t); __size_ = __t.__size_; __value_comp_ = std::move(__t.__value_comp_); - if (size() == 0) - __begin_node() = __end_node(); + if (__size_ == 0) + __begin_node_ = __end_node(); else { __end_node()->__left_->__parent_ = static_cast<__end_node_pointer>(__end_node()); - __t.__begin_node() = __t.__end_node(); + __t.__begin_node_ = __t.__end_node(); __t.__end_node()->__left_ = nullptr; - __t.size() = 0; + __t.__size_ = 0; } } template <class _Tp, class _Compare, class _Allocator> void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) { - if (__node_alloc() == __t.__node_alloc()) + if (__node_alloc() == __t.__node_alloc()) { __move_assign(__t, true_type()); - else { - value_comp() = std::move(__t.value_comp()); - const_iterator __e = end(); - if (size() != 0) { - _DetachedTreeCache __cache(this); - while (__cache.__get() != nullptr && __t.size() != 0) { - __assign_value(__cache.__get()->__value_, std::move(__t.remove(__t.begin())->__value_)); - __node_insert_multi(__cache.__get()); - __cache.__advance(); - } - } - while (__t.size() != 0) { - __insert_multi_from_orphaned_node(__e, std::move(__t.remove(__t.begin())->__value_)); + } else { + value_comp() = std::move(__t.value_comp()); + if (__size_ != 0) { + *__root_ptr() = static_cast<__node_base_pointer>(__move_assign_tree(__root(), __t.__root())); + } else { + *__root_ptr() = static_cast<__node_base_pointer>(__move_construct_tree(__t.__root())); + if (__root()) + __root()->__parent_ = __end_node(); } - } -} - -template <class _Tp, class _Compare, class _Allocator> -__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) - _NOEXCEPT_(is_nothrow_move_assignable<value_compare>::value && - ((__node_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<__node_allocator>::value) || - allocator_traits<__node_allocator>::is_always_equal::value)) { - __move_assign(__t, integral_constant<bool, __node_traits::propagate_on_container_move_assignment::value>()); - return *this; -} - -template <class _Tp, class _Compare, class _Allocator> -__tree<_Tp, _Compare, _Allocator>::~__tree() { - static_assert(is_copy_constructible<value_compare>::value, "Comparator must be copy-constructible."); - destroy(__root()); -} - -template <class _Tp, class _Compare, class _Allocator> -void __tree<_Tp, _Compare, _Allocator>::destroy(__node_pointer __nd) _NOEXCEPT { - if (__nd != nullptr) { - destroy(static_cast<__node_pointer>(__nd->__left_)); - destroy(static_cast<__node_pointer>(__nd->__right_)); - __node_allocator& __na = __node_alloc(); - __node_traits::destroy(__na, std::addressof(__nd->__value_)); - __node_traits::deallocate(__na, __nd, 1); + __begin_node_ = + __end_node()->__left_ ? static_cast<__end_node_pointer>(std::__tree_min(__end_node()->__left_)) : __end_node(); + __size_ = __t.size(); + __t.clear(); // Ensure that __t is in a valid state after moving out the keys } } @@ -1470,12 +1732,12 @@ void __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t) std::__swap_allocator(__node_alloc(), __t.__node_alloc()); swap(__size_, __t.__size_); swap(__value_comp_, __t.__value_comp_); - if (size() == 0) - __begin_node() = __end_node(); + if (__size_ == 0) + __begin_node_ = __end_node(); else __end_node()->__left_->__parent_ = __end_node(); - if (__t.size() == 0) - __t.__begin_node() = __t.__end_node(); + if (__t.__size_ == 0) + __t.__begin_node_ = __t.__end_node(); else __t.__end_node()->__left_->__parent_ = __t.__end_node(); } @@ -1483,8 +1745,8 @@ void __tree<_Tp, _Compare, _Allocator>::swap(__tree& __t) template <class _Tp, class _Compare, class _Allocator> void __tree<_Tp, _Compare, _Allocator>::clear() _NOEXCEPT { destroy(__root()); - size() = 0; - __begin_node() = __end_node(); + __size_ = 0; + __begin_node_ = __end_node(); __end_node()->__left_ = nullptr; } @@ -1497,7 +1759,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_low(__end_node_pointer& __parent, __node_pointer __nd = __root(); if (__nd != nullptr) { while (true) { - if (value_comp()(__nd->__value_, __v)) { + if (value_comp()(__nd->__get_value(), __v)) { if (__nd->__right_ != nullptr) __nd = static_cast<__node_pointer>(__nd->__right_); else { @@ -1527,7 +1789,7 @@ __tree<_Tp, _Compare, _Allocator>::__find_leaf_high(__end_node_pointer& __parent __node_pointer __nd = __root(); if (__nd != nullptr) { while (true) { - if (value_comp()(__v, __nd->__value_)) { + if (value_comp()(__v, __nd->__get_value())) { if (__nd->__left_ != nullptr) __nd = static_cast<__node_pointer>(__nd->__left_); else { @@ -1578,92 +1840,91 @@ typename __tree<_Tp, _Compare, _Allocator>::__node_base_pointer& __tree<_Tp, _Co return __find_leaf_low(__parent, __v); } -// Find place to insert if __v doesn't exist -// Set __parent to parent of null leaf -// Return reference to null leaf -// If __v exists, set parent to node of __v and return reference to node of __v +// Find __v +// If __v exists, return the parent of the node of __v and a reference to the pointer to the node of __v. +// If __v doesn't exist, return the parent of the null leaf and a reference to the pointer to the null leaf. template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::__node_base_pointer& -__tree<_Tp, _Compare, _Allocator>::__find_equal(__end_node_pointer& __parent, const _Key& __v) { - __node_pointer __nd = __root(); - __node_base_pointer* __nd_ptr = __root_ptr(); - if (__nd != nullptr) { - while (true) { - if (value_comp()(__v, __nd->__value_)) { - if (__nd->__left_ != nullptr) { - __nd_ptr = std::addressof(__nd->__left_); - __nd = static_cast<__node_pointer>(__nd->__left_); - } else { - __parent = static_cast<__end_node_pointer>(__nd); - return __parent->__left_; - } - } else if (value_comp()(__nd->__value_, __v)) { - if (__nd->__right_ != nullptr) { - __nd_ptr = std::addressof(__nd->__right_); - __nd = static_cast<__node_pointer>(__nd->__right_); - } else { - __parent = static_cast<__end_node_pointer>(__nd); - return __nd->__right_; - } - } else { - __parent = static_cast<__end_node_pointer>(__nd); - return *__nd_ptr; - } +_LIBCPP_HIDE_FROM_ABI pair<typename __tree<_Tp, _Compare, _Allocator>::__end_node_pointer, + typename __tree<_Tp, _Compare, _Allocator>::__node_base_pointer&> +__tree<_Tp, _Compare, _Allocator>::__find_equal(const _Key& __v) { + using _Pair = pair<__end_node_pointer, __node_base_pointer&>; + + __node_pointer __nd = __root(); + + if (__nd == nullptr) { + auto __end = __end_node(); + return _Pair(__end, __end->__left_); + } + + __node_base_pointer* __node_ptr = __root_ptr(); + auto&& __transparent = std::__as_transparent<_Key>(value_comp()); + auto __comp = + __lazy_synth_three_way_comparator<__make_transparent_t<_Key, _Compare>, _Key, value_type>(__transparent); + + while (true) { + auto __comp_res = __comp(__v, __nd->__get_value()); + + if (__comp_res.__less()) { + if (__nd->__left_ == nullptr) + return _Pair(static_cast<__end_node_pointer>(__nd), __nd->__left_); + + __node_ptr = std::addressof(__nd->__left_); + __nd = static_cast<__node_pointer>(__nd->__left_); + } else if (__comp_res.__greater()) { + if (__nd->__right_ == nullptr) + return _Pair(static_cast<__end_node_pointer>(__nd), __nd->__right_); + + __node_ptr = std::addressof(__nd->__right_); + __nd = static_cast<__node_pointer>(__nd->__right_); + } else { + return _Pair(static_cast<__end_node_pointer>(__nd), *__node_ptr); } } - __parent = __end_node(); - return __parent->__left_; } -// Find place to insert if __v doesn't exist +// Find __v // First check prior to __hint. // Next check after __hint. // Next do O(log N) search. -// Set __parent to parent of null leaf -// Return reference to null leaf -// If __v exists, set parent to node of __v and return reference to node of __v +// If __v exists, return the parent of the node of __v and a reference to the pointer to the node of __v. +// If __v doesn't exist, return the parent of the null leaf and a reference to the pointer to the null leaf. template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::__node_base_pointer& __tree<_Tp, _Compare, _Allocator>::__find_equal( - const_iterator __hint, __end_node_pointer& __parent, __node_base_pointer& __dummy, const _Key& __v) { - if (__hint == end() || value_comp()(__v, *__hint)) // check before - { +_LIBCPP_HIDE_FROM_ABI pair<typename __tree<_Tp, _Compare, _Allocator>::__end_node_pointer, + typename __tree<_Tp, _Compare, _Allocator>::__node_base_pointer&> +__tree<_Tp, _Compare, _Allocator>::__find_equal(const_iterator __hint, __node_base_pointer& __dummy, const _Key& __v) { + using _Pair = pair<__end_node_pointer, __node_base_pointer&>; + + if (__hint == end() || value_comp()(__v, *__hint)) { // check before // __v < *__hint const_iterator __prior = __hint; if (__prior == begin() || value_comp()(*--__prior, __v)) { // *prev(__hint) < __v < *__hint - if (__hint.__ptr_->__left_ == nullptr) { - __parent = __hint.__ptr_; - return __parent->__left_; - } else { - __parent = __prior.__ptr_; - return static_cast<__node_base_pointer>(__prior.__ptr_)->__right_; - } + if (__hint.__ptr_->__left_ == nullptr) + return _Pair(__hint.__ptr_, __hint.__ptr_->__left_); + return _Pair(__prior.__ptr_, static_cast<__node_pointer>(__prior.__ptr_)->__right_); } // __v <= *prev(__hint) - return __find_equal(__parent, __v); - } else if (value_comp()(*__hint, __v)) // check after - { + return __find_equal(__v); + } + + if (value_comp()(*__hint, __v)) { // check after // *__hint < __v const_iterator __next = std::next(__hint); if (__next == end() || value_comp()(__v, *__next)) { // *__hint < __v < *std::next(__hint) - if (__hint.__get_np()->__right_ == nullptr) { - __parent = __hint.__ptr_; - return static_cast<__node_base_pointer>(__hint.__ptr_)->__right_; - } else { - __parent = __next.__ptr_; - return __parent->__left_; - } + if (__hint.__get_np()->__right_ == nullptr) + return _Pair(__hint.__ptr_, static_cast<__node_pointer>(__hint.__ptr_)->__right_); + return _Pair(__next.__ptr_, __next.__ptr_->__left_); } // *next(__hint) <= __v - return __find_equal(__parent, __v); + return __find_equal(__v); } + // else __v == *__hint - __parent = __hint.__ptr_; - __dummy = static_cast<__node_base_pointer>(__hint.__ptr_); - return __dummy; + __dummy = static_cast<__node_base_pointer>(__hint.__ptr_); + return _Pair(__hint.__ptr_, __dummy); } template <class _Tp, class _Compare, class _Allocator> @@ -1674,46 +1935,10 @@ void __tree<_Tp, _Compare, _Allocator>::__insert_node_at( __new_node->__parent_ = __parent; // __new_node->__is_black_ is initialized in __tree_balance_after_insert __child = __new_node; - if (__begin_node()->__left_ != nullptr) - __begin_node() = static_cast<__end_node_pointer>(__begin_node()->__left_); + if (__begin_node_->__left_ != nullptr) + __begin_node_ = static_cast<__end_node_pointer>(__begin_node_->__left_); std::__tree_balance_after_insert(__end_node()->__left_, __child); - ++size(); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class _Key, class... _Args> -pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool> -__tree<_Tp, _Compare, _Allocator>::__emplace_unique_key_args(_Key const& __k, _Args&&... __args) { - __end_node_pointer __parent; - __node_base_pointer& __child = __find_equal(__parent, __k); - __node_pointer __r = static_cast<__node_pointer>(__child); - bool __inserted = false; - if (__child == nullptr) { - __node_holder __h = __construct_node(std::forward<_Args>(__args)...); - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); - __r = __h.release(); - __inserted = true; - } - return pair<iterator, bool>(iterator(__r), __inserted); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class _Key, class... _Args> -pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool> -__tree<_Tp, _Compare, _Allocator>::__emplace_hint_unique_key_args( - const_iterator __p, _Key const& __k, _Args&&... __args) { - __end_node_pointer __parent; - __node_base_pointer __dummy; - __node_base_pointer& __child = __find_equal(__p, __parent, __dummy, __k); - __node_pointer __r = static_cast<__node_pointer>(__child); - bool __inserted = false; - if (__child == nullptr) { - __node_holder __h = __construct_node(std::forward<_Args>(__args)...); - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); - __r = __h.release(); - __inserted = true; - } - return pair<iterator, bool>(iterator(__r), __inserted); + ++__size_; } template <class _Tp, class _Compare, class _Allocator> @@ -1722,51 +1947,18 @@ typename __tree<_Tp, _Compare, _Allocator>::__node_holder __tree<_Tp, _Compare, _Allocator>::__construct_node(_Args&&... __args) { __node_allocator& __na = __node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - __node_traits::construct(__na, std::addressof(__h->__value_), std::forward<_Args>(__args)...); + std::__construct_at(std::addressof(*__h), __na, std::forward<_Args>(__args)...); __h.get_deleter().__value_constructed = true; return __h; } template <class _Tp, class _Compare, class _Allocator> template <class... _Args> -pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool> -__tree<_Tp, _Compare, _Allocator>::__emplace_unique_impl(_Args&&... __args) { - __node_holder __h = __construct_node(std::forward<_Args>(__args)...); - __end_node_pointer __parent; - __node_base_pointer& __child = __find_equal(__parent, __h->__value_); - __node_pointer __r = static_cast<__node_pointer>(__child); - bool __inserted = false; - if (__child == nullptr) { - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); - __r = __h.release(); - __inserted = true; - } - return pair<iterator, bool>(iterator(__r), __inserted); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class... _Args> -typename __tree<_Tp, _Compare, _Allocator>::iterator -__tree<_Tp, _Compare, _Allocator>::__emplace_hint_unique_impl(const_iterator __p, _Args&&... __args) { - __node_holder __h = __construct_node(std::forward<_Args>(__args)...); - __end_node_pointer __parent; - __node_base_pointer __dummy; - __node_base_pointer& __child = __find_equal(__p, __parent, __dummy, __h->__value_); - __node_pointer __r = static_cast<__node_pointer>(__child); - if (__child == nullptr) { - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); - __r = __h.release(); - } - return iterator(__r); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class... _Args> typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__emplace_multi(_Args&&... __args) { __node_holder __h = __construct_node(std::forward<_Args>(__args)...); __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf_high(__parent, __h->__value_); + __node_base_pointer& __child = __find_leaf_high(__parent, __h->__get_value()); __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); return iterator(static_cast<__node_pointer>(__h.release())); } @@ -1777,53 +1969,19 @@ typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__emplace_hint_multi(const_iterator __p, _Args&&... __args) { __node_holder __h = __construct_node(std::forward<_Args>(__args)...); __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf(__p, __parent, __h->__value_); + __node_base_pointer& __child = __find_leaf(__p, __parent, __h->__get_value()); __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); return iterator(static_cast<__node_pointer>(__h.release())); } template <class _Tp, class _Compare, class _Allocator> -pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool> -__tree<_Tp, _Compare, _Allocator>::__node_assign_unique(const value_type& __v, __node_pointer __nd) { - __end_node_pointer __parent; - __node_base_pointer& __child = __find_equal(__parent, __v); - __node_pointer __r = static_cast<__node_pointer>(__child); - bool __inserted = false; - if (__child == nullptr) { - __assign_value(__nd->__value_, __v); - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd)); - __r = __nd; - __inserted = true; - } - return pair<iterator, bool>(iterator(__r), __inserted); -} - -template <class _Tp, class _Compare, class _Allocator> -typename __tree<_Tp, _Compare, _Allocator>::iterator -__tree<_Tp, _Compare, _Allocator>::__node_insert_multi(__node_pointer __nd) { - __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf_high(__parent, __nd->__value_); - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd)); - return iterator(__nd); -} - -template <class _Tp, class _Compare, class _Allocator> -typename __tree<_Tp, _Compare, _Allocator>::iterator -__tree<_Tp, _Compare, _Allocator>::__node_insert_multi(const_iterator __p, __node_pointer __nd) { - __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf(__p, __parent, __nd->__value_); - __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__nd)); - return iterator(__nd); -} - -template <class _Tp, class _Compare, class _Allocator> typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__remove_node_pointer(__node_pointer __ptr) _NOEXCEPT { iterator __r(__ptr); ++__r; - if (__begin_node() == __ptr) - __begin_node() = __r.__ptr_; - --size(); + if (__begin_node_ == __ptr) + __begin_node_ = __r.__ptr_; + --__size_; std::__tree_remove(__end_node()->__left_, static_cast<__node_base_pointer>(__ptr)); return __r; } @@ -1837,8 +1995,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(_NodeHandle&& __n return _InsertReturnType{end(), false, _NodeHandle()}; __node_pointer __ptr = __nh.__ptr_; - __end_node_pointer __parent; - __node_base_pointer& __child = __find_equal(__parent, __ptr->__value_); + auto [__parent, __child] = __find_equal(__ptr->__get_value()); if (__child != nullptr) return _InsertReturnType{iterator(static_cast<__node_pointer>(__child)), false, std::move(__nh)}; @@ -1855,10 +2012,9 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __ return end(); __node_pointer __ptr = __nh.__ptr_; - __end_node_pointer __parent; __node_base_pointer __dummy; - __node_base_pointer& __child = __find_equal(__hint, __parent, __dummy, __ptr->__value_); - __node_pointer __r = static_cast<__node_pointer>(__child); + auto [__parent, __child] = __find_equal(__hint, __dummy, __ptr->__get_value()); + __node_pointer __r = static_cast<__node_pointer>(__child); if (__child == nullptr) { __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__ptr)); __r = __ptr; @@ -1885,14 +2041,12 @@ _LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_hand } template <class _Tp, class _Compare, class _Allocator> -template <class _Tree> -_LIBCPP_HIDE_FROM_ABI void __tree<_Tp, _Compare, _Allocator>::__node_handle_merge_unique(_Tree& __source) { - static_assert(is_same<typename _Tree::__node_pointer, __node_pointer>::value, ""); - - for (typename _Tree::iterator __i = __source.begin(); __i != __source.end();) { +template <class _Comp2> +_LIBCPP_HIDE_FROM_ABI void +__tree<_Tp, _Compare, _Allocator>::__node_handle_merge_unique(__tree<_Tp, _Comp2, _Allocator>& __source) { + for (iterator __i = __source.begin(); __i != __source.end();) { __node_pointer __src_ptr = __i.__get_np(); - __end_node_pointer __parent; - __node_base_pointer& __child = __find_equal(__parent, __src_ptr->__value_); + auto [__parent, __child] = __find_equal(__src_ptr->__get_value()); ++__i; if (__child != nullptr) continue; @@ -1909,7 +2063,7 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_multi(_NodeHandle&& __nh return end(); __node_pointer __ptr = __nh.__ptr_; __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf_high(__parent, __ptr->__value_); + __node_base_pointer& __child = __find_leaf_high(__parent, __ptr->__get_value()); __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__ptr)); __nh.__release_ptr(); return iterator(__ptr); @@ -1924,21 +2078,20 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_multi(const_iterator __h __node_pointer __ptr = __nh.__ptr_; __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf(__hint, __parent, __ptr->__value_); + __node_base_pointer& __child = __find_leaf(__hint, __parent, __ptr->__get_value()); __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__ptr)); __nh.__release_ptr(); return iterator(__ptr); } template <class _Tp, class _Compare, class _Allocator> -template <class _Tree> -_LIBCPP_HIDE_FROM_ABI void __tree<_Tp, _Compare, _Allocator>::__node_handle_merge_multi(_Tree& __source) { - static_assert(is_same<typename _Tree::__node_pointer, __node_pointer>::value, ""); - - for (typename _Tree::iterator __i = __source.begin(); __i != __source.end();) { +template <class _Comp2> +_LIBCPP_HIDE_FROM_ABI void +__tree<_Tp, _Compare, _Allocator>::__node_handle_merge_multi(__tree<_Tp, _Comp2, _Allocator>& __source) { + for (iterator __i = __source.begin(); __i != __source.end();) { __node_pointer __src_ptr = __i.__get_np(); __end_node_pointer __parent; - __node_base_pointer& __child = __find_leaf_high(__parent, __src_ptr->__value_); + __node_base_pointer& __child = __find_leaf_high(__parent, __src_ptr->__get_value()); ++__i; __source.__remove_node_pointer(__src_ptr); __insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__src_ptr)); @@ -1989,32 +2142,15 @@ __tree<_Tp, _Compare, _Allocator>::__erase_multi(const _Key& __k) { template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::find(const _Key& __v) { - iterator __p = __lower_bound(__v, __root(), __end_node()); - if (__p != end() && !value_comp()(__v, *__p)) - return __p; - return end(); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::const_iterator -__tree<_Tp, _Compare, _Allocator>::find(const _Key& __v) const { - const_iterator __p = __lower_bound(__v, __root(), __end_node()); - if (__p != end() && !value_comp()(__v, *__p)) - return __p; - return end(); -} - -template <class _Tp, class _Compare, class _Allocator> -template <class _Key> typename __tree<_Tp, _Compare, _Allocator>::size_type __tree<_Tp, _Compare, _Allocator>::__count_unique(const _Key& __k) const { __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else return 1; @@ -2028,26 +2164,28 @@ typename __tree<_Tp, _Compare, _Allocator>::size_type __tree<_Tp, _Compare, _Allocator>::__count_multi(const _Key& __k) const { __end_node_pointer __result = __end_node(); __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __result = static_cast<__end_node_pointer>(__rt); __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else return std::distance( - __lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), - __upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result)); + __lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), + __upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result)); } return 0; } template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::iterator -__tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) { +typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound_multi( + const _Key& __v, __node_pointer __root, __end_node_pointer __result) { while (__root != nullptr) { - if (!value_comp()(__root->__value_, __v)) { + if (!value_comp()(__root->__get_value(), __v)) { __result = static_cast<__end_node_pointer>(__root); __root = static_cast<__node_pointer>(__root->__left_); } else @@ -2058,10 +2196,10 @@ __tree<_Tp, _Compare, _Allocator>::__lower_bound(const _Key& __v, __node_pointer template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound( +typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__lower_bound_multi( const _Key& __v, __node_pointer __root, __end_node_pointer __result) const { while (__root != nullptr) { - if (!value_comp()(__root->__value_, __v)) { + if (!value_comp()(__root->__get_value(), __v)) { __result = static_cast<__end_node_pointer>(__root); __root = static_cast<__node_pointer>(__root->__left_); } else @@ -2072,10 +2210,10 @@ typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::iterator -__tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer __root, __end_node_pointer __result) { +typename __tree<_Tp, _Compare, _Allocator>::iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound_multi( + const _Key& __v, __node_pointer __root, __end_node_pointer __result) { while (__root != nullptr) { - if (value_comp()(__v, __root->__value_)) { + if (value_comp()(__v, __root->__get_value())) { __result = static_cast<__end_node_pointer>(__root); __root = static_cast<__node_pointer>(__root->__left_); } else @@ -2086,10 +2224,10 @@ __tree<_Tp, _Compare, _Allocator>::__upper_bound(const _Key& __v, __node_pointer template <class _Tp, class _Compare, class _Allocator> template <class _Key> -typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound( +typename __tree<_Tp, _Compare, _Allocator>::const_iterator __tree<_Tp, _Compare, _Allocator>::__upper_bound_multi( const _Key& __v, __node_pointer __root, __end_node_pointer __result) const { while (__root != nullptr) { - if (value_comp()(__v, __root->__value_)) { + if (value_comp()(__v, __root->__get_value())) { __result = static_cast<__end_node_pointer>(__root); __root = static_cast<__node_pointer>(__root->__left_); } else @@ -2102,14 +2240,16 @@ template <class _Tp, class _Compare, class _Allocator> template <class _Key> pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, typename __tree<_Tp, _Compare, _Allocator>::iterator> __tree<_Tp, _Compare, _Allocator>::__equal_range_unique(const _Key& __k) { - typedef pair<iterator, iterator> _Pp; + using _Pp = pair<iterator, iterator>; __end_node_pointer __result = __end_node(); __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __result = static_cast<__end_node_pointer>(__rt); __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else return _Pp(iterator(__rt), @@ -2124,14 +2264,16 @@ template <class _Key> pair<typename __tree<_Tp, _Compare, _Allocator>::const_iterator, typename __tree<_Tp, _Compare, _Allocator>::const_iterator> __tree<_Tp, _Compare, _Allocator>::__equal_range_unique(const _Key& __k) const { - typedef pair<const_iterator, const_iterator> _Pp; + using _Pp = pair<const_iterator, const_iterator>; __end_node_pointer __result = __end_node(); __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __result = static_cast<__end_node_pointer>(__rt); __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else return _Pp( @@ -2146,18 +2288,21 @@ template <class _Tp, class _Compare, class _Allocator> template <class _Key> pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, typename __tree<_Tp, _Compare, _Allocator>::iterator> __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) { - typedef pair<iterator, iterator> _Pp; + using _Pp = pair<iterator, iterator>; __end_node_pointer __result = __end_node(); - __node_pointer __rt = __root(); + __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __result = static_cast<__end_node_pointer>(__rt); __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else - return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), - __upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result)); + return _Pp( + __lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), + __upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result)); } return _Pp(iterator(__result), iterator(__result)); } @@ -2167,18 +2312,21 @@ template <class _Key> pair<typename __tree<_Tp, _Compare, _Allocator>::const_iterator, typename __tree<_Tp, _Compare, _Allocator>::const_iterator> __tree<_Tp, _Compare, _Allocator>::__equal_range_multi(const _Key& __k) const { - typedef pair<const_iterator, const_iterator> _Pp; + using _Pp = pair<const_iterator, const_iterator>; __end_node_pointer __result = __end_node(); - __node_pointer __rt = __root(); + __node_pointer __rt = __root(); + auto __comp = __lazy_synth_three_way_comparator<value_compare, _Key, value_type>(value_comp()); while (__rt != nullptr) { - if (value_comp()(__k, __rt->__value_)) { + auto __comp_res = __comp(__k, __rt->__get_value()); + if (__comp_res.__less()) { __result = static_cast<__end_node_pointer>(__rt); __rt = static_cast<__node_pointer>(__rt->__left_); - } else if (value_comp()(__rt->__value_, __k)) + } else if (__comp_res.__greater()) __rt = static_cast<__node_pointer>(__rt->__right_); else - return _Pp(__lower_bound(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), - __upper_bound(__k, static_cast<__node_pointer>(__rt->__right_), __result)); + return _Pp( + __lower_bound_multi(__k, static_cast<__node_pointer>(__rt->__left_), static_cast<__end_node_pointer>(__rt)), + __upper_bound_multi(__k, static_cast<__node_pointer>(__rt->__right_), __result)); } return _Pp(const_iterator(__result), const_iterator(__result)); } @@ -2187,13 +2335,13 @@ template <class _Tp, class _Compare, class _Allocator> typename __tree<_Tp, _Compare, _Allocator>::__node_holder __tree<_Tp, _Compare, _Allocator>::remove(const_iterator __p) _NOEXCEPT { __node_pointer __np = __p.__get_np(); - if (__begin_node() == __p.__ptr_) { + if (__begin_node_ == __p.__ptr_) { if (__np->__right_ != nullptr) - __begin_node() = static_cast<__end_node_pointer>(__np->__right_); + __begin_node_ = static_cast<__end_node_pointer>(__np->__right_); else - __begin_node() = static_cast<__end_node_pointer>(__np->__parent_); + __begin_node_ = static_cast<__end_node_pointer>(__np->__parent_); } - --size(); + --__size_; std::__tree_remove(__end_node()->__left_, static_cast<__node_base_pointer>(__np)); return __node_holder(__np, _Dp(__node_alloc(), true)); } diff --git a/lib/libcxx/include/__tuple/sfinae_helpers.h b/lib/libcxx/include/__tuple/sfinae_helpers.h @@ -10,20 +10,6 @@ #define _LIBCPP___TUPLE_SFINAE_HELPERS_H #include <__config> -#include <__cstddef/size_t.h> -#include <__fwd/tuple.h> -#include <__tuple/make_tuple_types.h> -#include <__tuple/tuple_element.h> -#include <__tuple/tuple_like_ext.h> -#include <__tuple/tuple_size.h> -#include <__tuple/tuple_types.h> -#include <__type_traits/conjunction.h> -#include <__type_traits/enable_if.h> -#include <__type_traits/integral_constant.h> -#include <__type_traits/is_constructible.h> -#include <__type_traits/is_same.h> -#include <__type_traits/remove_cvref.h> -#include <__type_traits/remove_reference.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -33,36 +19,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #ifndef _LIBCPP_CXX03_LANG -struct __tuple_sfinae_base { - template <template <class, class...> class _Trait, class... _LArgs, class... _RArgs> - static auto __do_test(__tuple_types<_LArgs...>, - __tuple_types<_RArgs...>) -> __all<__enable_if_t<_Trait<_LArgs, _RArgs>::value, bool>{true}...>; - template <template <class...> class> - static auto __do_test(...) -> false_type; - - template <class _FromArgs, class _ToArgs> - using __constructible _LIBCPP_NODEBUG = decltype(__do_test<is_constructible>(_ToArgs{}, _FromArgs{})); -}; - -// __tuple_constructible - -template <class _Tp, - class _Up, - bool = __tuple_like_ext<__libcpp_remove_reference_t<_Tp> >::value, - bool = __tuple_like_ext<_Up>::value> -struct __tuple_constructible : public false_type {}; - -template <class _Tp, class _Up> -struct __tuple_constructible<_Tp, _Up, true, true> - : public __tuple_sfinae_base::__constructible< typename __make_tuple_types<_Tp>::type, - typename __make_tuple_types<_Up>::type > {}; - -template <size_t _Ip, class... _Tp> -struct tuple_element<_Ip, tuple<_Tp...> > { - using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, __tuple_types<_Tp...> >::type; -}; - -struct _LIBCPP_EXPORTED_FROM_ABI __check_tuple_constructor_fail { +struct __check_tuple_constructor_fail { static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit_default() { return false; } static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() { return false; } template <class...> diff --git a/lib/libcxx/include/__tuple/tuple_element.h b/lib/libcxx/include/__tuple/tuple_element.h @@ -11,8 +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) # pragma GCC system_header @@ -38,21 +36,11 @@ struct tuple_element<_Ip, const volatile _Tp> { using type _LIBCPP_NODEBUG = const volatile typename tuple_element<_Ip, _Tp>::type; }; -#ifndef _LIBCPP_CXX03_LANG - -template <size_t _Ip, class... _Types> -struct tuple_element<_Ip, __tuple_types<_Types...> > { - static_assert(_Ip < sizeof...(_Types), "tuple_element index out of range"); - using type _LIBCPP_NODEBUG = __type_pack_element<_Ip, _Types...>; -}; - # if _LIBCPP_STD_VER >= 14 template <size_t _Ip, class... _Tp> using tuple_element_t _LIBCPP_NODEBUG = typename tuple_element<_Ip, _Tp...>::type; # endif -#endif // _LIBCPP_CXX03_LANG - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TUPLE_TUPLE_ELEMENT_H diff --git a/lib/libcxx/include/__tuple/tuple_size.h b/lib/libcxx/include/__tuple/tuple_size.h @@ -12,7 +12,6 @@ #include <__config> #include <__cstddef/size_t.h> #include <__fwd/tuple.h> -#include <__tuple/tuple_types.h> #include <__type_traits/enable_if.h> #include <__type_traits/integral_constant.h> #include <__type_traits/is_const.h> @@ -59,9 +58,6 @@ struct tuple_size<const volatile _Tp> : public tuple_size<_Tp> {}; template <class... _Tp> struct tuple_size<tuple<_Tp...> > : public integral_constant<size_t, sizeof...(_Tp)> {}; -template <class... _Tp> -struct tuple_size<__tuple_types<_Tp...> > : public integral_constant<size_t, sizeof...(_Tp)> {}; - # if _LIBCPP_STD_VER >= 17 template <class _Tp> inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value; diff --git a/lib/libcxx/include/__tuple/tuple_transform.h b/lib/libcxx/include/__tuple/tuple_transform.h @@ -0,0 +1,45 @@ +// -*- 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___TUPLE_TUPLE_TRANSFORM_H +#define _LIBCPP___TUPLE_TUPLE_TRANSFORM_H + +#include <__config> + +#include <__functional/invoke.h> +#include <__utility/forward.h> +#include <tuple> + +#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 + +template <class _Fun, class _Tuple> +_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_transform(_Fun&& __f, _Tuple&& __tuple) { + return std::apply( + [&]<class... _Types>(_Types&&... __elements) { + return tuple<invoke_result_t<_Fun&, _Types>...>(std::invoke(__f, std::forward<_Types>(__elements))...); + }, + std::forward<_Tuple>(__tuple)); +} + +#endif // _LIBCPP_STD_VER >= 23 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___TUPLE_TUPLE_TRANSFORM_H diff --git a/lib/libcxx/include/__type_traits/aligned_storage.h b/lib/libcxx/include/__type_traits/aligned_storage.h @@ -11,8 +11,6 @@ #include <__config> #include <__cstddef/size_t.h> -#include <__type_traits/integral_constant.h> -#include <__type_traits/type_list.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -21,10 +19,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> -struct __align_type { - static const size_t value = _LIBCPP_PREFERRED_ALIGNOF(_Tp); - typedef _Tp type; -}; +struct _ALIGNAS(_LIBCPP_PREFERRED_ALIGNOF(_Tp)) _AlignedAsT {}; + +template <class... _Args> +struct __max_align_impl : _AlignedAsT<_Args>... {}; struct __struct_double { long double __lx; @@ -33,41 +31,16 @@ struct __struct_double4 { double __lx[4]; }; -using __all_types _LIBCPP_NODEBUG = - __type_list<__align_type<unsigned char>, - __align_type<unsigned short>, - __align_type<unsigned int>, - __align_type<unsigned long>, - __align_type<unsigned long long>, - __align_type<double>, - __align_type<long double>, - __align_type<__struct_double>, - __align_type<__struct_double4>, - __align_type<int*> >; - -template <class _TL, size_t _Len> -struct __find_max_align; - -template <class _Head, size_t _Len> -struct __find_max_align<__type_list<_Head>, _Len> : public integral_constant<size_t, _Head::value> {}; - -template <size_t _Len, size_t _A1, size_t _A2> -struct __select_align { -private: - static const size_t __min = _A2 < _A1 ? _A2 : _A1; - static const size_t __max = _A1 < _A2 ? _A2 : _A1; - -public: - static const size_t value = _Len < __max ? __min : __max; -}; +inline const size_t __aligned_storage_max_align = + _LIBCPP_ALIGNOF(__max_align_impl<unsigned long long, double, long double, __struct_double, __struct_double4, int*>); -template <class _Head, class... _Tail, size_t _Len> -struct __find_max_align<__type_list<_Head, _Tail...>, _Len> - : public integral_constant< - size_t, - __select_align<_Len, _Head::value, __find_max_align<__type_list<_Tail...>, _Len>::value>::value> {}; +template <size_t _Len> +inline const size_t __aligned_storage_alignment = + _Len > __aligned_storage_max_align + ? __aligned_storage_max_align + : size_t(1) << ((sizeof(size_t) * __CHAR_BIT__) - __builtin_clzg(_Len) - 1); -template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value> +template <size_t _Len, size_t _Align = __aligned_storage_alignment<_Len> > struct _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_NO_SPECIALIZATIONS aligned_storage { union _ALIGNAS(_Align) type { unsigned char __data[(_Len + _Align - 1) / _Align * _Align]; @@ -77,7 +50,7 @@ struct _LIBCPP_DEPRECATED_IN_CXX23 _LIBCPP_NO_SPECIALIZATIONS aligned_storage { #if _LIBCPP_STD_VER >= 14 _LIBCPP_SUPPRESS_DEPRECATED_PUSH -template <size_t _Len, size_t _Align = __find_max_align<__all_types, _Len>::value> +template <size_t _Len, size_t _Align = __aligned_storage_alignment<_Len> > using aligned_storage_t _LIBCPP_DEPRECATED_IN_CXX23 = typename aligned_storage<_Len, _Align>::type; _LIBCPP_SUPPRESS_DEPRECATED_POP diff --git a/lib/libcxx/include/__type_traits/desugars_to.h b/lib/libcxx/include/__type_traits/desugars_to.h @@ -10,6 +10,7 @@ #define _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H #include <__config> +#include <__type_traits/integral_constant.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -64,6 +65,9 @@ template <class _CanonicalTag, class _Operation, class... _Args> inline const bool __desugars_to_v<_CanonicalTag, _Operation&&, _Args...> = __desugars_to_v<_CanonicalTag, _Operation, _Args...>; +template <class _CanonicalTag, class _Operation, class... _Args> +struct __desugars_to : integral_constant<bool, __desugars_to_v<_CanonicalTag, _Operation, _Args...> > {}; + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_DESUGARS_TO_H diff --git a/lib/libcxx/include/__type_traits/invoke.h b/lib/libcxx/include/__type_traits/invoke.h @@ -62,6 +62,9 @@ // // template <class Func, class... Args> // using __invoke_result_t = invoke_result_t<Func, Args...>; +// +// template <class Ret, class Func, class... Args> +// struct __is_invocable_r : is_invocable_r<Ret, Func, Args...> {}; _LIBCPP_BEGIN_NAMESPACE_STD @@ -112,8 +115,10 @@ inline const bool __is_invocable_r_v = __is_invocable_r_impl<_Ret, __is_invocabl template <bool __is_invocable, class... _Args> inline const bool __is_nothrow_invocable_impl = false; +# ifndef _LIBCPP_CXX03_LANG template <class... _Args> inline const bool __is_nothrow_invocable_impl<true, _Args...> = noexcept(__builtin_invoke(std::declval<_Args>()...)); +# endif template <class... _Args> inline const bool __is_nothrow_invocable_v = __is_nothrow_invocable_impl<__is_invocable_v<_Args...>, _Args...>; @@ -327,6 +332,9 @@ using __invoke_result_t _LIBCPP_NODEBUG = typename __invoke_result<_Func, _Args. #endif // __has_builtin(__builtin_invoke_r) +template <class _Ret, class _Func, class... _Args> +struct __is_invocable_r : integral_constant<bool, __is_invocable_r_v<_Ret, _Func, _Args...> > {}; + template <class _Ret, bool = is_void<_Ret>::value> struct __invoke_void_return_wrapper { template <class... _Args> diff --git a/lib/libcxx/include/__type_traits/is_allocator.h b/lib/libcxx/include/__type_traits/is_allocator.h @@ -11,7 +11,6 @@ #include <__config> #include <__cstddef/size_t.h> -#include <__type_traits/integral_constant.h> #include <__type_traits/void_t.h> #include <__utility/declval.h> @@ -21,13 +20,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD -template <typename _Alloc, typename = void, typename = void> -struct __is_allocator : false_type {}; +template <class _Alloc, class = void, class = void> +inline const bool __is_allocator_v = false; -template <typename _Alloc> -struct __is_allocator<_Alloc, - __void_t<typename _Alloc::value_type>, - __void_t<decltype(std::declval<_Alloc&>().allocate(size_t(0)))> > : true_type {}; +template <class _Alloc> +inline const bool __is_allocator_v<_Alloc, + __void_t<typename _Alloc::value_type>, + __void_t<decltype(std::declval<_Alloc&>().allocate(size_t()))> > = true; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__type_traits/is_array.h b/lib/libcxx/include/__type_traits/is_array.h @@ -26,6 +26,32 @@ template <class _Tp> _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_array_v = __is_array(_Tp); #endif +template <class _Tp> +inline const bool __is_bounded_array_v = __is_bounded_array(_Tp); + +#if _LIBCPP_STD_VER >= 20 + +template <class _Tp> +struct _LIBCPP_NO_SPECIALIZATIONS is_bounded_array : bool_constant<__is_bounded_array(_Tp)> {}; + +template <class _Tp> +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_bounded_array_v = __is_bounded_array(_Tp); + +#endif + +template <class _Tp> +inline const bool __is_unbounded_array_v = __is_unbounded_array(_Tp); + +#if _LIBCPP_STD_VER >= 20 + +template <class _Tp> +struct _LIBCPP_NO_SPECIALIZATIONS is_unbounded_array : bool_constant<__is_unbounded_array(_Tp)> {}; + +template <class _Tp> +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_unbounded_array_v = __is_unbounded_array(_Tp); + +#endif + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___TYPE_TRAITS_IS_ARRAY_H diff --git a/lib/libcxx/include/__type_traits/is_equality_comparable.h b/lib/libcxx/include/__type_traits/is_equality_comparable.h @@ -27,11 +27,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp, class _Up, class = void> -struct __is_equality_comparable : false_type {}; +inline const bool __is_equality_comparable_v = false; template <class _Tp, class _Up> -struct __is_equality_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() == std::declval<_Up>())> > : true_type { -}; +inline const bool + __is_equality_comparable_v<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() == std::declval<_Up>())> > = true; // A type is_trivially_equality_comparable if the expression `a == b` is equivalent to `std::memcmp(&a, &b, sizeof(T))` // (with `a` and `b` being of type `T`). For the case where we compare two object of the same type, we can use @@ -48,40 +48,35 @@ struct __is_equality_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() // representation may not be equivalent. template <class _Tp, class _Up, class = void> -struct __libcpp_is_trivially_equality_comparable_impl : false_type {}; +inline const bool __is_trivially_equality_comparable_impl = false; template <class _Tp> -struct __libcpp_is_trivially_equality_comparable_impl<_Tp, _Tp> +inline const bool __is_trivially_equality_comparable_impl<_Tp, _Tp> #if __has_builtin(__is_trivially_equality_comparable) - : integral_constant<bool, __is_trivially_equality_comparable(_Tp) && __is_equality_comparable<_Tp, _Tp>::value> { -}; + = __is_trivially_equality_comparable(_Tp) && __is_equality_comparable_v<_Tp, _Tp>; #else - : is_integral<_Tp> { -}; + = is_integral<_Tp>::value; #endif // __has_builtin(__is_trivially_equality_comparable) template <class _Tp, class _Up> -struct __libcpp_is_trivially_equality_comparable_impl< +inline const bool __is_trivially_equality_comparable_impl< _Tp, _Up, - __enable_if_t<is_integral<_Tp>::value && is_integral<_Up>::value && !is_same<_Tp, _Up>::value && - is_signed<_Tp>::value == is_signed<_Up>::value && sizeof(_Tp) == sizeof(_Up)> > : true_type {}; + __enable_if_t<is_integral<_Tp>::value && is_integral<_Up>::value && !is_same<_Tp, _Up>::value> > = + is_signed<_Tp>::value == is_signed<_Up>::value && sizeof(_Tp) == sizeof(_Up); template <class _Tp> -struct __libcpp_is_trivially_equality_comparable_impl<_Tp*, _Tp*> : true_type {}; +inline const bool __is_trivially_equality_comparable_impl<_Tp*, _Tp*> = true; // TODO: Use is_pointer_inverconvertible_base_of template <class _Tp, class _Up> -struct __libcpp_is_trivially_equality_comparable_impl<_Tp*, _Up*> - : integral_constant< - bool, - __is_equality_comparable<_Tp*, _Up*>::value && - (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value || is_void<_Tp>::value || is_void<_Up>::value)> { -}; +inline const bool __is_trivially_equality_comparable_impl<_Tp*, _Up*> = + __is_equality_comparable_v<_Tp*, _Up*> && + (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value || is_void<_Tp>::value || is_void<_Up>::value); template <class _Tp, class _Up> -using __libcpp_is_trivially_equality_comparable _LIBCPP_NODEBUG = - __libcpp_is_trivially_equality_comparable_impl<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >; +inline const bool __is_trivially_equality_comparable_v = + __is_trivially_equality_comparable_impl<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__type_traits/is_final.h b/lib/libcxx/include/__type_traits/is_final.h @@ -19,7 +19,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp> -struct __libcpp_is_final : integral_constant<bool, __is_final(_Tp)> {}; +inline const bool __is_final_v = __is_final(_Tp); #if _LIBCPP_STD_VER >= 14 template <class _Tp> diff --git a/lib/libcxx/include/__type_traits/is_floating_point.h b/lib/libcxx/include/__type_traits/is_floating_point.h @@ -20,18 +20,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD // clang-format off -template <class _Tp> struct __libcpp_is_floating_point : false_type {}; -template <> struct __libcpp_is_floating_point<float> : true_type {}; -template <> struct __libcpp_is_floating_point<double> : true_type {}; -template <> struct __libcpp_is_floating_point<long double> : true_type {}; +template <class _Tp> inline const bool __is_floating_point_impl = false; +template <> inline const bool __is_floating_point_impl<float> = true; +template <> inline const bool __is_floating_point_impl<double> = true; +template <> inline const bool __is_floating_point_impl<long double> = true; // clang-format on template <class _Tp> -struct _LIBCPP_NO_SPECIALIZATIONS is_floating_point : __libcpp_is_floating_point<__remove_cv_t<_Tp> > {}; +struct _LIBCPP_NO_SPECIALIZATIONS is_floating_point + : integral_constant<bool, __is_floating_point_impl<__remove_cv_t<_Tp> > > {}; #if _LIBCPP_STD_VER >= 17 template <class _Tp> -_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value; +_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_floating_point_v = __is_floating_point_impl<__remove_cv_t<_Tp>>; #endif _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__type_traits/is_generic_transparent_comparator.h b/lib/libcxx/include/__type_traits/is_generic_transparent_comparator.h @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_GENERIC_TRANSPARENT_COMPARATOR_H +#define _LIBCPP___TYPE_TRAITS_IS_GENERIC_TRANSPARENT_COMPARATOR_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// This trait returns true if the given _Comparator is known to accept any two types for comparison. This is separate +// from `__is_transparent_v`, since that only enables overloads of specific functions, but doesn't give any semantic +// guarantees. This trait guarantess that the comparator simply calls the appropriate comparison functions for any two +// types. + +template <class _Comparator> +inline const bool __is_generic_transparent_comparator_v = false; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_GENERIC_TRANSPARENT_COMPARATOR_H diff --git a/lib/libcxx/include/__type_traits/is_specialization.h b/lib/libcxx/include/__type_traits/is_specialization.h @@ -30,15 +30,11 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 17 - template <class _Tp, template <class...> class _Template> -inline constexpr bool __is_specialization_v = false; // true if and only if _Tp is a specialization of _Template +inline const bool __is_specialization_v = false; // true if and only if _Tp is a specialization of _Template template <template <class...> class _Template, class... _Args> -inline constexpr bool __is_specialization_v<_Template<_Args...>, _Template> = true; - -#endif // _LIBCPP_STD_VER >= 17 +inline const bool __is_specialization_v<_Template<_Args...>, _Template> = true; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__type_traits/is_within_lifetime.h b/lib/libcxx/include/__type_traits/is_within_lifetime.h @@ -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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_IS_WITHIN_LIFETIME_H +#define _LIBCPP___TYPE_TRAITS_IS_WITHIN_LIFETIME_H + +#include <__config> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_within_lifetime) +template <class _Tp> +_LIBCPP_HIDE_FROM_ABI consteval bool is_within_lifetime(const _Tp* __p) noexcept { + return __builtin_is_within_lifetime(__p); +} +#endif + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_IS_WITHIN_LIFETIME_H diff --git a/lib/libcxx/include/__type_traits/make_transparent.h b/lib/libcxx/include/__type_traits/make_transparent.h @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___TYPE_TRAITS_MAKE_TRANSPARENT_H +#define _LIBCPP___TYPE_TRAITS_MAKE_TRANSPARENT_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_empty.h> +#include <__type_traits/is_same.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// __make_transparent tries to create a transparent comparator from its non-transparent counterpart, e.g. obtain +// `less<>` from `less<T>`. This is useful in cases where conversions can be avoided (e.g. a string literal to a +// std::string). + +template <class _Tp, class _Comparator> +struct __make_transparent { + using type _LIBCPP_NODEBUG = _Comparator; +}; + +template <class _Tp, class _Comparator> +using __make_transparent_t _LIBCPP_NODEBUG = typename __make_transparent<_Tp, _Comparator>::type; + +template <class _Tp, + class _Comparator, + __enable_if_t<is_same<_Comparator, __make_transparent_t<_Tp, _Comparator> >::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Comparator& __as_transparent(_Comparator& __comp) { + return __comp; +} + +template <class _Tp, + class _Comparator, + __enable_if_t<!is_same<_Comparator, __make_transparent_t<_Tp, _Comparator> >::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI __make_transparent_t<_Tp, _Comparator> __as_transparent(_Comparator&) { + static_assert(is_empty<_Comparator>::value); + return __make_transparent_t<_Tp, _Comparator>(); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___TYPE_TRAITS_MAKE_TRANSPARENT_H diff --git a/lib/libcxx/include/__type_traits/reference_constructs_from_temporary.h b/lib/libcxx/include/__type_traits/reference_constructs_from_temporary.h @@ -18,7 +18,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_constructs_from_temporary) +#if _LIBCPP_STD_VER >= 23 template <class _Tp, class _Up> struct _LIBCPP_NO_SPECIALIZATIONS reference_constructs_from_temporary @@ -30,14 +30,8 @@ _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool reference_constructs_from_tempo #endif -#if __has_builtin(__reference_constructs_from_temporary) template <class _Tp, class _Up> inline const bool __reference_constructs_from_temporary_v = __reference_constructs_from_temporary(_Tp, _Up); -#else -// TODO(LLVM 22): Remove this as all supported compilers should have __reference_constructs_from_temporary implemented. -template <class _Tp, class _Up> -inline const bool __reference_constructs_from_temporary_v = __reference_binds_to_temporary(_Tp, _Up); -#endif _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/__type_traits/reference_converts_from_temporary.h b/lib/libcxx/include/__type_traits/reference_converts_from_temporary.h @@ -18,7 +18,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER >= 23 && __has_builtin(__reference_converts_from_temporary) +#if _LIBCPP_STD_VER >= 23 template <class _Tp, class _Up> struct _LIBCPP_NO_SPECIALIZATIONS reference_converts_from_temporary diff --git a/lib/libcxx/include/__utility/cmp.h b/lib/libcxx/include/__utility/cmp.h @@ -26,10 +26,18 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 +template <typename _Tp, typename _Ip> +concept __comparison_can_promote_to = + sizeof(_Tp) < sizeof(_Ip) || (sizeof(_Tp) == sizeof(_Ip) && __signed_integer<_Tp>); + template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) return __t == __u; + else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>) + return static_cast<int>(__t) == static_cast<int>(__u); + else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>) + return static_cast<long long>(__t) == static_cast<long long>(__u); else if constexpr (is_signed_v<_Tp>) return __t < 0 ? false : make_unsigned_t<_Tp>(__t) == __u; else @@ -37,14 +45,18 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_equal(_Tp __t, _Up __u) noexcept { } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_not_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_equal(__t, __u); } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept { if constexpr (is_signed_v<_Tp> == is_signed_v<_Up>) return __t < __u; + else if constexpr (__comparison_can_promote_to<_Tp, int> && __comparison_can_promote_to<_Up, int>) + return static_cast<int>(__t) < static_cast<int>(__u); + else if constexpr (__comparison_can_promote_to<_Tp, long long> && __comparison_can_promote_to<_Up, long long>) + return static_cast<long long>(__t) < static_cast<long long>(__u); else if constexpr (is_signed_v<_Tp>) return __t < 0 ? true : make_unsigned_t<_Tp>(__t) < __u; else @@ -52,22 +64,22 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less(_Tp __t, _Up __u) noexcept { } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater(_Tp __t, _Up __u) noexcept { return std::cmp_less(__u, __t); } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less_equal(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_less_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_greater(__t, __u); } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater_equal(_Tp __t, _Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool cmp_greater_equal(_Tp __t, _Up __u) noexcept { return !std::cmp_less(__t, __u); } template <__signed_or_unsigned_integer _Tp, __signed_or_unsigned_integer _Up> -_LIBCPP_HIDE_FROM_ABI constexpr bool in_range(_Up __u) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool in_range(_Up __u) noexcept { return std::cmp_less_equal(__u, numeric_limits<_Tp>::max()) && std::cmp_greater_equal(__u, numeric_limits<_Tp>::min()); } diff --git a/lib/libcxx/include/__utility/default_three_way_comparator.h b/lib/libcxx/include/__utility/default_three_way_comparator.h @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H +#define _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H + +#include <__config> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_arithmetic.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// This struct can be specialized to provide a three way comparator between _LHS and _RHS. +// The return value should be +// - less than zero if (lhs_val < rhs_val) +// - greater than zero if (rhs_val < lhs_val) +// - zero otherwise +template <class _LHS, class _RHS, class = void> +struct __default_three_way_comparator; + +template <class _LHS, class _RHS> +struct __default_three_way_comparator<_LHS, + _RHS, + __enable_if_t<is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value> > { + _LIBCPP_HIDE_FROM_ABI static int operator()(_LHS __lhs, _RHS __rhs) { + if (__lhs < __rhs) + return -1; + if (__lhs > __rhs) + return 1; + return 0; + } +}; + +#if _LIBCPP_STD_VER >= 20 && __has_builtin(__builtin_lt_synthesizes_from_spaceship) +template <class _LHS, class _RHS> +struct __default_three_way_comparator< + _LHS, + _RHS, + __enable_if_t<!(is_arithmetic<_LHS>::value && is_arithmetic<_RHS>::value) && + __builtin_lt_synthesizes_from_spaceship(const _LHS&, const _RHS&)>> { + _LIBCPP_HIDE_FROM_ABI static int operator()(const _LHS& __lhs, const _RHS& __rhs) { + auto __res = __lhs <=> __rhs; + if (__res < 0) + return -1; + if (__res > 0) + return 1; + return 0; + } +}; +#endif + +template <class _LHS, class _RHS, bool = true> +struct __has_default_three_way_comparator : false_type {}; + +template <class _LHS, class _RHS> +struct __has_default_three_way_comparator<_LHS, _RHS, sizeof(__default_three_way_comparator<_LHS, _RHS>) >= 0> + : true_type {}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_DEFAULT_THREE_WAY_COMPARATOR_H diff --git a/lib/libcxx/include/__utility/in_place.h b/lib/libcxx/include/__utility/in_place.h @@ -22,7 +22,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 17 -struct _LIBCPP_EXPORTED_FROM_ABI in_place_t { +struct in_place_t { explicit in_place_t() = default; }; inline constexpr in_place_t in_place{}; diff --git a/lib/libcxx/include/__utility/integer_sequence.h b/lib/libcxx/include/__utility/integer_sequence.h @@ -11,63 +11,52 @@ #include <__config> #include <__cstddef/size_t.h> +#include <__tuple/tuple_element.h> +#include <__tuple/tuple_size.h> #include <__type_traits/is_integral.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; +# 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"); + [[__nodiscard__]] 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); } -}; +template <class... _Args> +using __index_sequence_for _LIBCPP_NODEBUG = __make_index_sequence<sizeof...(_Args)>; + +# 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 +64,42 @@ 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 + +# if _LIBCPP_STD_VER >= 26 +// [intseq.binding], structured binding support +template <class _Tp, _Tp... _Indices> +struct tuple_size<integer_sequence<_Tp, _Indices...>> : integral_constant<size_t, sizeof...(_Indices)> {}; -#endif // _LIBCPP_STD_VER >= 14 +template <size_t _Ip, class _Tp, _Tp... _Indices> +struct tuple_element<_Ip, integer_sequence<_Tp, _Indices...>> { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (std::integer_sequence)"); + using type _LIBCPP_NODEBUG = _Tp; +}; + +template <size_t _Ip, class _Tp, _Tp... _Indices> +struct tuple_element<_Ip, const integer_sequence<_Tp, _Indices...>> { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::tuple_element<> (const std::integer_sequence)"); + using type _LIBCPP_NODEBUG = _Tp; +}; + +template <size_t _Ip, class _Tp, _Tp... _Indices> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp get(integer_sequence<_Tp, _Indices...>) noexcept { + static_assert(_Ip < sizeof...(_Indices), "Index out of bounds in std::get<> (std::integer_sequence)"); + return _Indices...[_Ip]; +} +# endif // _LIBCPP_STD_VER >= 26 + +# endif // _LIBCPP_STD_VER >= 14 _LIBCPP_END_NAMESPACE_STD +#endif // _LIBCPP_CXX03_LANG + #endif // _LIBCPP___UTILITY_INTEGER_SEQUENCE_H diff --git a/lib/libcxx/include/__utility/lazy_synth_three_way_comparator.h b/lib/libcxx/include/__utility/lazy_synth_three_way_comparator.h @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H +#define _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H + +#include <__assert> +#include <__config> +#include <__type_traits/conjunction.h> +#include <__type_traits/desugars_to.h> +#include <__type_traits/enable_if.h> +#include <__utility/default_three_way_comparator.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// This file implements a __lazy_synth_three_way_comparator, which tries to build an efficient three way comparison from +// a binary comparator. That is done in multiple steps: +// 1) Check whether the comparator desugars to a less-than operator +// If that is the case, check whether there exists a specialization of `__default_three_way_comparator`, which +// can be specialized to implement a three way comparator for the specific types. +// 2) Fall back to doing a lazy less than/greater than comparison + +_LIBCPP_BEGIN_NAMESPACE_STD + +template <class _Comparator, class _LHS, class _RHS> +struct __lazy_compare_result { + const _Comparator& __comp_; + const _LHS& __lhs_; + const _RHS& __rhs_; + + _LIBCPP_HIDE_FROM_ABI + __lazy_compare_result(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator& __comp, + _LIBCPP_CTOR_LIFETIMEBOUND const _LHS& __lhs, + _LIBCPP_CTOR_LIFETIMEBOUND const _RHS& __rhs) + : __comp_(__comp), __lhs_(__lhs), __rhs_(__rhs) {} + + _LIBCPP_HIDE_FROM_ABI bool __less() const { + bool __result = __comp_(__lhs_, __rhs_); + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__result ? !static_cast<bool>(__comp_(__rhs_, __lhs_)) : true, + "Comparator does not induce a strict weak ordering"); + return __result; + } + + _LIBCPP_HIDE_FROM_ABI bool __greater() const { + bool __result = __comp_(__rhs_, __lhs_); + _LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__result ? !static_cast<bool>(__comp_(__lhs_, __rhs_)) : true, + "Comparator does not induce a strict weak ordering"); + return __result; + } +}; + +// This class provides three way comparison between _LHS and _RHS as efficiently as possible. This can be specialized if +// a comparator only compares part of the object, potentially allowing an efficient three way comparison between the +// subobjects. The specialization should use the __lazy_synth_three_way_comparator for the subobjects to achieve this. +template <class _Comparator, class _LHS, class _RHS, class = void> +struct __lazy_synth_three_way_comparator { + const _Comparator& __comp_; + + _LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator& __comp) + : __comp_(__comp) {} + + _LIBCPP_HIDE_FROM_ABI __lazy_compare_result<_Comparator, _LHS, _RHS> + operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) const { + return __lazy_compare_result<_Comparator, _LHS, _RHS>(__comp_, __lhs, __rhs); + } +}; + +struct __eager_compare_result { + int __res_; + + _LIBCPP_HIDE_FROM_ABI explicit __eager_compare_result(int __res) : __res_(__res) {} + + _LIBCPP_HIDE_FROM_ABI bool __less() const { return __res_ < 0; } + _LIBCPP_HIDE_FROM_ABI bool __greater() const { return __res_ > 0; } +}; + +template <class _Comparator, class _LHS, class _RHS> +struct __lazy_synth_three_way_comparator<_Comparator, + _LHS, + _RHS, + __enable_if_t<_And<__desugars_to<__less_tag, _Comparator, _LHS, _RHS>, + __has_default_three_way_comparator<_LHS, _RHS> >::value> > { + // This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of + // the comparator. + _LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {} + + // Same comment as above. + _LIBCPP_HIDE_FROM_ABI static __eager_compare_result + operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) { + return __eager_compare_result(__default_three_way_comparator<_LHS, _RHS>()(__lhs, __rhs)); + } +}; + +template <class _Comparator, class _LHS, class _RHS> +struct __lazy_synth_three_way_comparator<_Comparator, + _LHS, + _RHS, + __enable_if_t<_And<__desugars_to<__greater_tag, _Comparator, _LHS, _RHS>, + __has_default_three_way_comparator<_LHS, _RHS> >::value> > { + // This lifetimebound annotation is technically incorrect, but other specializations actually capture the lifetime of + // the comparator. + _LIBCPP_HIDE_FROM_ABI __lazy_synth_three_way_comparator(_LIBCPP_CTOR_LIFETIMEBOUND const _Comparator&) {} + + // Same comment as above. + _LIBCPP_HIDE_FROM_ABI static __eager_compare_result + operator()(_LIBCPP_LIFETIMEBOUND const _LHS& __lhs, _LIBCPP_LIFETIMEBOUND const _RHS& __rhs) { + return __eager_compare_result(-__default_three_way_comparator<_LHS, _RHS>()(__lhs, __rhs)); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_LAZY_SYNTH_THREE_WAY_COMPARATOR_H diff --git a/lib/libcxx/include/__utility/pair.h b/lib/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> @@ -32,14 +31,13 @@ #include <__type_traits/is_implicitly_default_constructible.h> #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> -#include <__type_traits/is_replaceable.h> -#include <__type_traits/is_same.h> #include <__type_traits/is_swappable.h> #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/nat.h> #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> @@ -102,7 +100,6 @@ struct pair __conditional_t<__libcpp_is_trivially_relocatable<_T1>::value && __libcpp_is_trivially_relocatable<_T2>::value, pair, void>; - using __replaceable _LIBCPP_NODEBUG = __conditional_t<__is_replaceable_v<_T1> && __is_replaceable_v<_T2>, pair, void>; _LIBCPP_HIDE_FROM_ABI pair(pair const&) = default; _LIBCPP_HIDE_FROM_ABI pair(pair&&) = default; @@ -222,11 +219,7 @@ struct pair _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair(piecewise_construct_t __pc, tuple<_Args1...> __first_args, tuple<_Args2...> __second_args) noexcept( is_nothrow_constructible<first_type, _Args1...>::value && is_nothrow_constructible<second_type, _Args2...>::value) - : pair(__pc, - __first_args, - __second_args, - typename __make_tuple_indices<sizeof...(_Args1)>::type(), - typename __make_tuple_indices<sizeof...(_Args2) >::type()) {} + : pair(__pc, __first_args, __second_args, __index_sequence_for<_Args1...>(), __index_sequence_for<_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 +433,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 @@ -546,8 +539,8 @@ swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) noexcept(noexcept(__x #endif template <class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> > -make_pair(_T1&& __t1, _T2&& __t2) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> > make_pair(_T1&& __t1, _T2&& __t2) { return pair<__unwrap_ref_decay_t<_T1>, __unwrap_ref_decay_t<_T2> >(std::forward<_T1>(__t1), std::forward<_T2>(__t2)); } @@ -619,67 +612,71 @@ struct __get_pair<1> { }; template <size_t _Ip, class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template <size_t _Ip, class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type& get(const pair<_T1, _T2>& __p) _NOEXCEPT { return __get_pair<_Ip>::get(__p); } template <size_t _Ip, class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } template <size_t _Ip, class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, pair<_T1, _T2> >::type&& get(const pair<_T1, _T2>&& __p) _NOEXCEPT { return __get_pair<_Ip>::get(std::move(__p)); } #if _LIBCPP_STD_VER >= 14 template <class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(pair<_T1, _T2>& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __p.first; } template <class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { return __p.first; } template <class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return std::forward<_T1&&>(__p.first); } template <class _T1, class _T2> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { return std::forward<_T1 const&&>(__p.first); } template <class _T2, class _T1> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2& get(pair<_T1, _T2>& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2& get(pair<_T1, _T2>& __p) _NOEXCEPT { return __p.second; } template <class _T2, class _T1> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const& get(pair<_T1, _T2> const& __p) _NOEXCEPT { return __p.second; } template <class _T2, class _T1> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2&& get(pair<_T1, _T2>&& __p) _NOEXCEPT { return std::forward<_T2&&>(__p.second); } template <class _T2, class _T1> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T2 const&& get(pair<_T1, _T2> const&& __p) _NOEXCEPT { return std::forward<_T2 const&&>(__p.second); } diff --git a/lib/libcxx/include/__utility/scope_guard.h b/lib/libcxx/include/__utility/scope_guard.h @@ -43,6 +43,8 @@ public: #endif }; +_LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__scope_guard); + template <class _Func> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __scope_guard<_Func> __make_scope_guard(_Func __func) { return __scope_guard<_Func>(std::move(__func)); diff --git a/lib/libcxx/include/__utility/try_key_extraction.h b/lib/libcxx/include/__utility/try_key_extraction.h @@ -0,0 +1,114 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache 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___UTILITY_TRY_EXTRACT_KEY_H +#define _LIBCPP___UTILITY_TRY_EXTRACT_KEY_H + +#include <__config> +#include <__fwd/pair.h> +#include <__fwd/tuple.h> +#include <__type_traits/enable_if.h> +#include <__type_traits/is_same.h> +#include <__type_traits/remove_const.h> +#include <__type_traits/remove_const_ref.h> +#include <__utility/declval.h> +#include <__utility/forward.h> +#include <__utility/piecewise_construct.h> +#include <__utility/priority_tag.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template <class _KeyT, class _Ret, class _WithKey, class _WithoutKey, class... _Args> +_LIBCPP_HIDE_FROM_ABI _Ret +__try_key_extraction_impl(__priority_tag<0>, _WithKey, _WithoutKey __without_key, _Args&&... __args) { + return __without_key(std::forward<_Args>(__args)...); +} + +template <class _KeyT, + class _Ret, + class _WithKey, + class _WithoutKey, + class _Arg, + __enable_if_t<is_same<_KeyT, __remove_const_ref_t<_Arg> >::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Ret +__try_key_extraction_impl(__priority_tag<1>, _WithKey __with_key, _WithoutKey, _Arg&& __arg) { + return __with_key(__arg, std::forward<_Arg>(__arg)); +} + +template <class _KeyT, + class _Ret, + class _WithKey, + class _WithoutKey, + class _Arg, + __enable_if_t<__is_pair_v<__remove_const_ref_t<_Arg> > && + is_same<__remove_const_t<typename __remove_const_ref_t<_Arg>::first_type>, _KeyT>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _Ret +__try_key_extraction_impl(__priority_tag<1>, _WithKey __with_key, _WithoutKey, _Arg&& __arg) { + return __with_key(__arg.first, std::forward<_Arg>(__arg)); +} + +template <class _KeyT, + class _Ret, + class _WithKey, + class _WithoutKey, + class _Arg1, + class _Arg2, + __enable_if_t<is_same<_KeyT, __remove_const_ref_t<_Arg1> >::value, int> = 0> +_LIBCPP_HIDE_FROM_ABI _Ret +__try_key_extraction_impl(__priority_tag<1>, _WithKey __with_key, _WithoutKey, _Arg1&& __arg1, _Arg2&& __arg2) { + return __with_key(__arg1, std::forward<_Arg1>(__arg1), std::forward<_Arg2>(__arg2)); +} + +#ifndef _LIBCPP_CXX03_LANG +template <class _KeyT, + class _Ret, + class _WithKey, + class _WithoutKey, + class _PiecewiseConstruct, + class _Tuple1, + class _Tuple2, + __enable_if_t<is_same<__remove_const_ref_t<_PiecewiseConstruct>, piecewise_construct_t>::value && + __is_tuple_v<_Tuple1> && tuple_size<_Tuple1>::value == 1 && + is_same<__remove_const_ref_t<typename tuple_element<0, _Tuple1>::type>, _KeyT>::value, + int> = 0> +_LIBCPP_HIDE_FROM_ABI _Ret __try_key_extraction_impl( + __priority_tag<1>, + _WithKey __with_key, + _WithoutKey, + _PiecewiseConstruct&& __pc, + _Tuple1&& __tuple1, + _Tuple2&& __tuple2) { + return __with_key( + std::get<0>(__tuple1), + std::forward<_PiecewiseConstruct>(__pc), + std::forward<_Tuple1>(__tuple1), + std::forward<_Tuple2>(__tuple2)); +} +#endif // _LIBCPP_CXX03_LANG + +// This function tries extracting the given _KeyT from _Args... +// If it succeeds to extract the key, it calls the `__with_key` function with the extracted key and all of the +// arguments. Otherwise it calls the `__without_key` function with all of the arguments. +// +// Both `__with_key` and `__without_key` must take all arguments by reference. +template <class _KeyT, class _WithKey, class _WithoutKey, class... _Args> +_LIBCPP_HIDE_FROM_ABI decltype(std::declval<_WithoutKey>()(std::declval<_Args>()...)) +__try_key_extraction(_WithKey __with_key, _WithoutKey __without_key, _Args&&... __args) { + using _Ret = decltype(__without_key(std::forward<_Args>(__args)...)); + return std::__try_key_extraction_impl<_KeyT, _Ret>( + __priority_tag<1>(), __with_key, __without_key, std::forward<_Args>(__args)...); +} + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___UTILITY_TRY_EXTRACT_KEY_H diff --git a/lib/libcxx/include/__vector/vector.h b/lib/libcxx/include/__vector/vector.h @@ -12,18 +12,17 @@ #include <__algorithm/copy.h> #include <__algorithm/copy_n.h> #include <__algorithm/fill_n.h> +#include <__algorithm/iterator_operations.h> #include <__algorithm/max.h> #include <__algorithm/min.h> #include <__algorithm/move.h> #include <__algorithm/move_backward.h> -#include <__algorithm/ranges_copy_n.h> #include <__algorithm/rotate.h> #include <__assert> #include <__config> #include <__debug_utils/sanitizers.h> #include <__format/enable_insertable.h> #include <__fwd/vector.h> -#include <__iterator/advance.h> #include <__iterator/bounded_iter.h> #include <__iterator/concepts.h> #include <__iterator/distance.h> @@ -43,6 +42,7 @@ #include <__memory/temp_value.h> #include <__memory/uninitialized_algorithms.h> #include <__ranges/access.h> +#include <__ranges/as_rvalue_view.h> #include <__ranges/concepts.h> #include <__ranges/container_compatible_range.h> #include <__ranges/from_range.h> @@ -55,7 +55,6 @@ #include <__type_traits/is_nothrow_assignable.h> #include <__type_traits/is_nothrow_constructible.h> #include <__type_traits/is_pointer.h> -#include <__type_traits/is_replaceable.h> #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/type_identity.h> @@ -86,6 +85,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD template <class _Tp, class _Allocator /* = allocator<_Tp> */> class vector { + template <class _Up, class _Alloc> + using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Up, _Alloc, __split_buffer_pointer_layout>; + public: // // Types @@ -113,7 +115,7 @@ public: using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; - // A vector containers the following members which may be trivially relocatable: + // A vector contains the following members which may be trivially relocatable: // - pointer: may be trivially relocatable, so it's checked // - allocator_type: may be trivially relocatable, so it's checked // vector doesn't contain any self-references, so it's trivially relocatable if its members are. @@ -121,10 +123,6 @@ public: __libcpp_is_trivially_relocatable<pointer>::value && __libcpp_is_trivially_relocatable<allocator_type>::value, vector, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value, - vector, - void>; static_assert(__check_valid_allocator<allocator_type>::value, ""); static_assert(is_same<typename allocator_type::value_type, value_type>::value, @@ -174,7 +172,7 @@ public: __guard.__complete(); } - template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(size_type __n, const value_type& __x, const allocator_type& __a) : __alloc_(__a) { @@ -317,7 +315,7 @@ public: is_constructible<value_type, typename iterator_traits<_ForwardIterator>::reference>::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void assign(_ForwardIterator __first, _ForwardIterator __last) { - __assign_with_size(__first, __last, std::distance(__first, __last)); + __assign_with_size<_ClassicAlgPolicy>(__first, __last, std::distance(__first, __last)); } #if _LIBCPP_STD_VER >= 23 @@ -325,7 +323,7 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr void assign_range(_Range&& __range) { if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast<size_type>(ranges::distance(__range)); - __assign_with_size(ranges::begin(__range), ranges::end(__range), __n); + __assign_with_size<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), __n); } else { __assign_with_sentinel(ranges::begin(__range), ranges::end(__range)); @@ -341,59 +339,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 +408,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 +448,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_); } @@ -478,7 +485,21 @@ public: #if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr void append_range(_Range&& __range) { - insert_range(end(), std::forward<_Range>(__range)); + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + auto __len = ranges::distance(__range); + if (__len <= __cap_ - __end_) { + __construct_at_end(ranges::begin(__range), ranges::end(__range), __len); + } else { + __split_buffer<value_type, allocator_type> __buffer(__recommend(size() + __len), size(), __alloc_); + __buffer.__construct_at_end_with_size(ranges::begin(__range), __len); + __swap_out_circular_buffer(__buffer); + } + } else { + vector __buffer(__alloc_); + for (auto&& __val : __range) + __buffer.emplace_back(std::forward<decltype(__val)>(__val)); + append_range(ranges::as_rvalue_view(__buffer)); + } } #endif @@ -512,7 +533,7 @@ public: int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) { - return __insert_with_size(__position, __first, __last, std::distance(__first, __last)); + return __insert_with_size<_ClassicAlgPolicy>(__position, __first, __last, std::distance(__first, __last)); } #if _LIBCPP_STD_VER >= 23 @@ -520,7 +541,7 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr iterator insert_range(const_iterator __position, _Range&& __range) { if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast<size_type>(ranges::distance(__range)); - return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n); + return __insert_with_size<_RangeAlgPolicy>(__position, ranges::begin(__range), ranges::end(__range), __n); } else { return __insert_with_sentinel(__position, ranges::begin(__range), ranges::end(__range)); @@ -613,12 +634,13 @@ private: // The `_Iterator` in `*_with_size` functions can be input-only only if called from `*_range` (since C++23). // Otherwise, `_Iterator` is a forward iterator. - template <class _Iterator, class _Sentinel> + template <class _AlgPolicy, class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n); - template <class _Iterator, - __enable_if_t<!is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0> + template <class _AlgPolicy, + class _Iterator, + __enable_if_t<!is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) { for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) { @@ -627,25 +649,19 @@ private: } } - template <class _Iterator, - __enable_if_t<is_same<decltype(*std::declval<_Iterator&>())&&, value_type&&>::value, int> = 0> + template <class _AlgPolicy, + class _Iterator, + __enable_if_t<is_same<__policy_value_type<_AlgPolicy, _Iterator>, value_type>::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) { -#if _LIBCPP_STD_VER >= 23 - if constexpr (!forward_iterator<_Iterator>) { // Handles input-only sized ranges for insert_range - ranges::copy_n(std::move(__first), __n, __position); - } else -#endif - { - std::copy_n(__first, __n, __position); - } + std::__copy_n<_AlgPolicy>(std::move(__first), __n, __position); } template <class _InputIterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last); - template <class _Iterator, class _Sentinel> + template <class _AlgPolicy, class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __insert_with_size(const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n); @@ -653,9 +669,6 @@ private: _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __append(size_type __n, const_reference __x); - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __make_iter(pointer __p) _NOEXCEPT { #ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR // Bound the iterator according to the capacity, rather than the size. @@ -689,9 +702,9 @@ private: } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void - __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v); + __swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer - __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p); + __swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_range(pointer __from_s, pointer __from_e, pointer __to); _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign(vector& __c, true_type) @@ -811,26 +824,44 @@ private: __add_alignment_assumption(_Ptr __p) _NOEXCEPT { return __p; } + + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type>& __sb) { + auto __vector_begin = __begin_; + auto __vector_sentinel = __end_; + auto __vector_cap = __cap_; + + auto __sb_begin = __sb.begin(); + auto __sb_sentinel = __sb.__raw_sentinel(); + auto __sb_cap = __sb.__raw_capacity(); + + // TODO: replace with __set_valid_range and __set_capacity when vector supports it. + __begin_ = __sb_begin; + __end_ = __sb_sentinel; + __cap_ = __sb_cap; + + __sb.__set_valid_range(__vector_begin, __vector_sentinel); + __sb.__set_capacity(__vector_cap); + } }; #if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Alloc = allocator<__iter_value_type<_InputIterator>>, + class _Alloc = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -vector(_InputIterator, _InputIterator) -> vector<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +vector(_InputIterator, _InputIterator) -> vector<__iterator_value_type<_InputIterator>, _Alloc>; template <class _InputIterator, class _Alloc, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -vector(_InputIterator, _InputIterator, _Alloc) -> vector<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +vector(_InputIterator, _InputIterator, _Alloc) -> vector<__iterator_value_type<_InputIterator>, _Alloc>; #endif #if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Alloc = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Alloc>::value> > + class = enable_if_t<__is_allocator_v<_Alloc>>> vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_t<_Range>, _Alloc>; #endif @@ -839,17 +870,16 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_ // function has a strong exception guarantee. template <class _Tp, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 void -vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) { +vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v) { __annotate_delete(); - auto __new_begin = __v.__begin_ - (__end_ - __begin_); + auto __new_begin = __v.begin() - size(); std::__uninitialized_allocator_relocate( this->__alloc_, std::__to_address(__begin_), std::__to_address(__end_), std::__to_address(__new_begin)); - __v.__begin_ = __new_begin; + __v.__set_valid_range(__new_begin, __v.end()); __end_ = __begin_; // All the objects have been destroyed by relocating them. - std::swap(this->__begin_, __v.__begin_); - std::swap(this->__end_, __v.__end_); - std::swap(this->__cap_, __v.__cap_); - __v.__first_ = __v.__begin_; + + __swap_layouts(__v); + __v.__set_data(__v.begin()); __annotate_new(size()); } @@ -859,27 +889,25 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a // function has a strong exception guarantee if __begin_ == __p || __end_ == __p. template <class _Tp, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer -vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p) { +vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p) { __annotate_delete(); - pointer __ret = __v.__begin_; + pointer __ret = __v.begin(); // Relocate [__p, __end_) first to avoid having a hole in [__begin_, __end_) // in case something in [__begin_, __p) throws. std::__uninitialized_allocator_relocate( - this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.__end_)); - __v.__end_ += (__end_ - __p); + this->__alloc_, std::__to_address(__p), std::__to_address(__end_), std::__to_address(__v.end())); + auto __relocated_so_far = __end_ - __p; + __v.__set_sentinel(__v.end() + __relocated_so_far); __end_ = __p; // The objects in [__p, __end_) have been destroyed by relocating them. - auto __new_begin = __v.__begin_ - (__p - __begin_); + auto __new_begin = __v.begin() - (__p - __begin_); std::__uninitialized_allocator_relocate( this->__alloc_, std::__to_address(__begin_), std::__to_address(__p), std::__to_address(__new_begin)); - __v.__begin_ = __new_begin; - __end_ = __begin_; // All the objects have been destroyed by relocating them. - - std::swap(this->__begin_, __v.__begin_); - std::swap(this->__end_, __v.__end_); - std::swap(this->__cap_, __v.__cap_); - __v.__first_ = __v.__begin_; + __v.__set_valid_range(__new_begin, __v.end()); + __end_ = __begin_; // All the objects have been destroyed by relocating them. + __swap_layouts(__v); + __v.__set_data(__v.begin()); __annotate_new(size()); return __ret; } @@ -945,36 +973,6 @@ vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __ __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __tx.__pos_); } -// Default constructs __n objects starting at __end_ -// throws if construction throws -// Postcondition: size() == size() + __n -// Exception safety: strong. -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n) { - if (static_cast<size_type>(this->__cap_ - this->__end_) >= __n) - this->__construct_at_end(__n); - else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), this->__alloc_); - __v.__construct_at_end(__n); - __swap_out_circular_buffer(__v); - } -} - -// Default constructs __n objects starting at __end_ -// throws if construction throws -// Postcondition: size() == size() + __n -// Exception safety: strong. -template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__append(size_type __n, const_reference __x) { - if (static_cast<size_type>(this->__cap_ - this->__end_) >= __n) - this->__construct_at_end(__n, __x); - else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), size(), this->__alloc_); - __v.__construct_at_end(__n, __x); - __swap_out_circular_buffer(__v); - } -} - template <class _Tp, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI vector<_Tp, _Allocator>::vector(vector&& __x) #if _LIBCPP_STD_VER >= 17 @@ -1051,20 +1049,14 @@ vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __l } template <class _Tp, class _Allocator> -template <class _Iterator, class _Sentinel> +template <class _AlgPolicy, class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n) { size_type __new_size = static_cast<size_type>(__n); if (__new_size <= capacity()) { if (__new_size > size()) { -#if _LIBCPP_STD_VER >= 23 - auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in; + auto __mid = std::__copy_n<_AlgPolicy>(std::move(__first), size(), this->__begin_).first; __construct_at_end(std::move(__mid), std::move(__last), __new_size - size()); -#else - _Iterator __mid = std::next(__first, size()); - std::copy(__first, __mid, this->__begin_); - __construct_at_end(__mid, __last, __new_size - size()); -#endif } else { pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second; this->__destruct_at_end(__m); @@ -1097,7 +1089,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::reserve(size_type __ if (__n > capacity()) { if (__n > max_size()) this->__throw_length_error(); - __split_buffer<value_type, allocator_type&> __v(__n, size(), this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__n, size(), this->__alloc_); __swap_out_circular_buffer(__v); } } @@ -1108,7 +1100,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS - __split_buffer<value_type, allocator_type&> __v(size(), size(), this->__alloc_); + __split_buffer<value_type, allocator_type> __v(size(), size(), this->__alloc_); // The Standard mandates shrink_to_fit() does not increase the capacity. // With equal capacity keep the existing buffer. This avoids extra work // due to swapping the elements. @@ -1125,14 +1117,33 @@ template <class _Tp, class _Allocator> template <class... _Args> _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), size(), this->__alloc_); // __v.emplace_back(std::forward<_Args>(__args)...); - __alloc_traits::construct(this->__alloc_, std::__to_address(__v.__end_), std::forward<_Args>(__args)...); - __v.__end_++; + pointer __end = __v.end(); + __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...); + __v.__set_sentinel(++__end); __swap_out_circular_buffer(__v); return this->__end_; } +// This makes the compiler inline `__else()` if `__cond` is known to be false. Currently LLVM doesn't do that without +// the `__builtin_constant_p`, since it considers `__else` unlikely even through it's known to be run. +// See https://llvm.org/PR154292 +template <class _If, class _Else> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __if_likely_else(bool __cond, _If __if, _Else __else) { + if (__builtin_constant_p(__cond)) { + if (__cond) + __if(); + else + __else(); + } else { + if (__cond) [[__likely__]] + __if(); + else + __else(); + } +} + template <class _Tp, class _Allocator> template <class... _Args> _LIBCPP_CONSTEXPR_SINCE_CXX20 inline @@ -1143,12 +1154,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline #endif vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) { pointer __end = this->__end_; - if (__end < this->__cap_) { - __emplace_back_assume_capacity(std::forward<_Args>(__args)...); - ++__end; - } else { - __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); - } + std::__if_likely_else( + __end < this->__cap_, + [&] { + __emplace_back_assume_capacity(std::forward<_Args>(__args)...); + ++__end; + }, + [&] { __end = __emplace_back_slow_path(std::forward<_Args>(__args)...); }); + this->__end_ = __end; #if _LIBCPP_STD_VER >= 17 return *(__end - 1); @@ -1207,7 +1220,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x) *__p = *__xr; } } else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); __v.emplace_back(__x); __p = __swap_out_circular_buffer(__v, __p); } @@ -1226,7 +1239,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) { *__p = std::move(__x); } } else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); __v.emplace_back(std::move(__x)); __p = __swap_out_circular_buffer(__v, __p); } @@ -1247,7 +1260,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) { *__p = std::move(__tmp.get()); } } else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_); __v.emplace_back(std::forward<_Args>(__args)...); __p = __swap_out_circular_buffer(__v, __p); } @@ -1275,7 +1288,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_ std::fill_n(__p, __n, *__xr); } } else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); __v.__construct_at_end(__n, __x); __p = __swap_out_circular_buffer(__v, __p); } @@ -1296,28 +1309,28 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu if (__first == __last) (void)std::rotate(__p, __old_last, this->__end_); else { - __split_buffer<value_type, allocator_type&> __v(__alloc_); + __split_buffer<value_type, allocator_type> __v(__alloc_); auto __guard = std::__make_exception_guard( _AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, this->__end_)); __v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last)); - __split_buffer<value_type, allocator_type&> __merged( + __split_buffer<value_type, allocator_type> __merged( __recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front std::__uninitialized_allocator_relocate( - __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.__end_)); + __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end())); __guard.__complete(); // Release the guard once objects in [__old_last_, __end_) have been successfully relocated. - __merged.__end_ += this->__end_ - __old_last; + __merged.__set_sentinel(__merged.end() + (this->__end_ - __old_last)); this->__end_ = __old_last; std::__uninitialized_allocator_relocate( - __alloc_, std::__to_address(__v.__begin_), std::__to_address(__v.__end_), std::__to_address(__merged.__end_)); - __merged.__end_ += __v.size(); - __v.__end_ = __v.__begin_; + __alloc_, std::__to_address(__v.begin()), std::__to_address(__v.end()), std::__to_address(__merged.end())); + __merged.__set_sentinel(__merged.size() + __v.size()); + __v.__set_sentinel(__v.begin()); __p = __swap_out_circular_buffer(__merged, __p); } return __make_iter(__p); } template <class _Tp, class _Allocator> -template <class _Iterator, class _Sentinel> +template <class _AlgPolicy, class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::__insert_with_size( const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n) { @@ -1338,15 +1351,15 @@ vector<_Tp, _Allocator>::__insert_with_size( __construct_at_end(__m, __last, __n - __dx); if (__dx > 0) { __move_range(__p, __old_last, __p + __n); - __insert_assign_n_unchecked(__first, __dx, __p); + __insert_assign_n_unchecked<_AlgPolicy>(__first, __dx, __p); } } } else { __move_range(__p, __old_last, __p + __n); - __insert_assign_n_unchecked(std::move(__first), __n, __p); + __insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p); } } else { - __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); + __split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); __v.__construct_at_end_with_size(std::move(__first), __n); __p = __swap_out_circular_buffer(__v, __p); } @@ -1355,21 +1368,35 @@ vector<_Tp, _Allocator>::__insert_with_size( } template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __sz) { - size_type __cs = size(); - if (__cs < __sz) - this->__append(__sz - __cs); - else if (__cs > __sz) - this->__destruct_at_end(this->__begin_ + __sz); +_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __new_size) { + size_type __current_size = size(); + if (__current_size < __new_size) { + if (__new_size <= capacity()) { + __construct_at_end(__new_size - __current_size); + } else { + __split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_); + __v.__construct_at_end(__new_size - __current_size); + __swap_out_circular_buffer(__v); + } + } else if (__current_size > __new_size) { + this->__destruct_at_end(this->__begin_ + __new_size); + } } template <class _Tp, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __sz, const_reference __x) { - size_type __cs = size(); - if (__cs < __sz) - this->__append(__sz - __cs, __x); - else if (__cs > __sz) - this->__destruct_at_end(this->__begin_ + __sz); +_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __new_size, const_reference __x) { + size_type __current_size = size(); + if (__current_size < __new_size) { + if (__new_size <= capacity()) + __construct_at_end(__new_size - __current_size, __x); + else { + __split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_); + __v.__construct_at_end(__new_size - __current_size, __x); + __swap_out_circular_buffer(__v); + } + } else if (__current_size > __new_size) { + this->__destruct_at_end(this->__begin_ + __new_size); + } } template <class _Tp, class _Allocator> diff --git a/lib/libcxx/include/__vector/vector_bool.h b/lib/libcxx/include/__vector/vector_bool.h @@ -11,6 +11,7 @@ #include <__algorithm/copy.h> #include <__algorithm/copy_backward.h> +#include <__algorithm/copy_n.h> #include <__algorithm/fill_n.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/max.h> @@ -19,7 +20,7 @@ #include <__bit_reference> #include <__config> #include <__functional/unary_function.h> -#include <__fwd/bit_reference.h> // TODO: This is a workaround for https://github.com/llvm/llvm-project/issues/131814 +#include <__fwd/bit_reference.h> // TODO: This is a workaround for https://llvm.org/PR131814 #include <__fwd/functional.h> #include <__fwd/vector.h> #include <__iterator/distance.h> @@ -234,74 +235,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); } @@ -463,7 +479,6 @@ private: return (__new_size + (__bits_per_word - 1)) & ~((size_type)__bits_per_word - 1); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __new_size) const; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(size_type __n, bool __x); template <class _InputIterator, class _Sentinel> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n); @@ -552,20 +567,6 @@ vector<bool, _Allocator>::__recommend(size_type __new_size) const { return std::max<size_type>(2 * __cap, __align_it(__new_size)); } -// Default constructs __n objects starting at __end_ -// Precondition: size() + __n <= capacity() -// Postcondition: size() == size() + __n -template <class _Allocator> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -vector<bool, _Allocator>::__construct_at_end(size_type __n, bool __x) { - _LIBCPP_ASSERT_INTERNAL( - capacity() >= size() + __n, "vector<bool>::__construct_at_end called with insufficient capacity"); - std::fill_n(end(), __n, __x); - this->__size_ += __n; - if (end().__ctz_ != 0) // Ensure uninitialized leading bits in the last word are set to zero - std::fill_n(end(), __bits_per_word - end().__ctz_, 0); -} - template <class _Allocator> template <class _InputIterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 void @@ -598,7 +599,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n) : __begin_(nullptr), __size_(0), __cap_(0) { if (__n > 0) { __vallocate(__n); - __construct_at_end(__n, false); + std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0)); + __size_ = __n; } } @@ -608,7 +610,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) { if (__n > 0) { __vallocate(__n); - __construct_at_end(__n, false); + std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0)); + __size_ = __n; } } #endif @@ -618,7 +621,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(size_type __n, co : __begin_(nullptr), __size_(0), __cap_(0) { if (__n > 0) { __vallocate(__n); - __construct_at_end(__n, __x); + std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x); + __size_ = __n; } } @@ -628,7 +632,8 @@ vector<bool, _Allocator>::vector(size_type __n, const value_type& __x, const all : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(static_cast<__storage_allocator>(__a)) { if (__n > 0) { __vallocate(__n); - __construct_at_end(__n, __x); + std::fill_n(__begin_, __external_cap_to_internal(__n), __storage_type(0) - __x); + __size_ = __n; } } @@ -697,7 +702,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v __alloc_(__storage_traits::select_on_container_copy_construction(__v.__alloc_)) { if (__v.size() > 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end(), __v.size()); + std::copy_n(__v.__begin_, __external_cap_to_internal(__v.size()), __begin_); + __size_ = __v.size(); } } @@ -706,7 +712,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>::vector(const vector& __v : __begin_(nullptr), __size_(0), __cap_(0), __alloc_(__a) { if (__v.size() > 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end(), __v.size()); + std::copy_n(__v.__begin_, __external_cap_to_internal(__v.size()), __begin_); + __size_ = __v.size(); } } @@ -719,7 +726,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>& vector<bool, _Allocator> __vdeallocate(); __vallocate(__v.__size_); } - std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_); + std::copy_n(__v.__begin_, __external_cap_to_internal(__v.size()), __begin_); } __size_ = __v.__size_; } @@ -754,7 +761,8 @@ vector<bool, _Allocator>::vector(vector&& __v, const __type_identity_t<allocator __v.__cap_ = __v.__size_ = 0; } else if (__v.size() > 0) { __vallocate(__v.size()); - __construct_at_end(__v.begin(), __v.end(), __v.size()); + __size_ = __v.__size_; + std::copy_n(__v.__begin_, __external_cap_to_internal(__v.size()), __begin_); } } @@ -849,7 +857,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::reserve(size_type _ this->__throw_length_error(); vector __v(this->get_allocator()); __v.__vallocate(__n); - __v.__construct_at_end(this->begin(), this->end(), this->size()); + __v.__size_ = __size_; + std::copy_n(__begin_, __external_cap_to_internal(__size_), __v.__begin_); swap(__v); } } @@ -956,21 +965,14 @@ vector<bool, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inp } vector __v(get_allocator()); if (__first != __last) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - __v.__assign_with_sentinel(std::move(__first), std::move(__last)); - difference_type __old_size = static_cast<difference_type>(__old_end - begin()); - difference_type __old_p = __p - begin(); - reserve(__recommend(size() + __v.size())); - __p = begin() + __old_p; - __old_end = begin() + __old_size; -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - erase(__old_end, end()); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { erase(__old_end, end()); }); + __v.__assign_with_sentinel(std::move(__first), std::move(__last)); + difference_type __old_size = static_cast<difference_type>(__old_end - begin()); + difference_type __old_p = __p - begin(); + reserve(__recommend(size() + __v.size())); + __p = begin() + __old_p; + __old_end = begin() + __old_size; + __guard.__complete(); } __p = std::rotate(__p, __old_end, end()); insert(__p, __v.begin(), __v.end()); @@ -1048,25 +1050,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::swap(vector& __x) } template <class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::resize(size_type __sz, value_type __x) { - size_type __cs = size(); - if (__cs < __sz) { - iterator __r; - size_type __c = capacity(); - size_type __n = __sz - __cs; - if (__n <= __c && __cs <= __c - __n) { - __r = end(); - __size_ += __n; - } else { - vector __v(get_allocator()); - __v.reserve(__recommend(__size_ + __n)); - __v.__size_ = __size_ + __n; - __r = std::copy(cbegin(), cend(), __v.begin()); - swap(__v); - } - std::fill_n(__r, __n, __x); - } else - __size_ = __sz; +_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::resize(size_type __new_size, value_type __x) { + size_type __current_size = size(); + if (__new_size < __current_size) { + __size_ = __new_size; + return; + } + + reserve(__new_size); + std::fill_n(end(), __new_size - __current_size, __x); + __size_ = __new_size; } template <class _Allocator> diff --git a/lib/libcxx/include/any b/lib/libcxx/include/any @@ -84,14 +84,12 @@ namespace std { # include <__cxx03/__config> #else # include <__config> -# include <__memory/allocator.h> -# include <__memory/allocator_destructor.h> -# include <__memory/allocator_traits.h> -# include <__memory/unique_ptr.h> +# include <__memory/construct_at.h> +# include <__new/allocate.h> # include <__type_traits/add_cv_quals.h> # include <__type_traits/add_pointer.h> -# include <__type_traits/aligned_storage.h> # include <__type_traits/conditional.h> +# include <__type_traits/conjunction.h> # include <__type_traits/decay.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_constructible.h> @@ -100,9 +98,11 @@ namespace std { # include <__type_traits/is_reference.h> # include <__type_traits/is_same.h> # include <__type_traits/is_void.h> +# include <__type_traits/negation.h> # include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> # include <__type_traits/remove_reference.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/in_place.h> # include <__utility/move.h> @@ -142,21 +142,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD class any; template <class _ValueType> -_LIBCPP_HIDE_FROM_ABI add_pointer_t<add_const_t<_ValueType>> any_cast(any const*) _NOEXCEPT; +_LIBCPP_HIDE_FROM_ABI add_pointer_t<add_const_t<_ValueType>> any_cast(any const*) noexcept; template <class _ValueType> -_LIBCPP_HIDE_FROM_ABI add_pointer_t<_ValueType> any_cast(any*) _NOEXCEPT; +_LIBCPP_HIDE_FROM_ABI add_pointer_t<_ValueType> any_cast(any*) noexcept; namespace __any_imp { -_LIBCPP_SUPPRESS_DEPRECATED_PUSH -using _Buffer _LIBCPP_NODEBUG = aligned_storage_t<3 * sizeof(void*), alignof(void*)>; -_LIBCPP_SUPPRESS_DEPRECATED_POP +inline constexpr size_t __small_buffer_size = 3 * sizeof(void*); +inline constexpr size_t __small_buffer_alignment = alignof(void*); template <class _Tp> using _IsSmallObject _LIBCPP_NODEBUG = integral_constant<bool, - sizeof(_Tp) <= sizeof(_Buffer) && alignof(_Buffer) % alignof(_Tp) == 0 && - is_nothrow_move_constructible<_Tp>::value >; + sizeof(_Tp) <= __small_buffer_size && alignof(_Tp) <= __small_buffer_alignment && + is_nothrow_move_constructible_v<_Tp>>; enum class _Action { _Destroy, _Copy, _Move, _Get, _TypeInfo }; @@ -192,37 +191,44 @@ using _Handler _LIBCPP_NODEBUG = conditional_t< _IsSmallObject<_Tp>::value, _Sma class any { public: // construct/destruct - _LIBCPP_HIDE_FROM_ABI constexpr any() _NOEXCEPT : __h_(nullptr) {} + _LIBCPP_HIDE_FROM_ABI constexpr any() noexcept : __h_(nullptr) {} _LIBCPP_HIDE_FROM_ABI any(any const& __other) : __h_(nullptr) { if (__other.__h_) __other.__call(_Action::_Copy, this); } - _LIBCPP_HIDE_FROM_ABI any(any&& __other) _NOEXCEPT : __h_(nullptr) { + _LIBCPP_HIDE_FROM_ABI any(any&& __other) noexcept : __h_(nullptr) { if (__other.__h_) __other.__call(_Action::_Move, this); } - template < class _ValueType, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< !is_same<_Tp, any>::value && !__is_inplace_type<_ValueType>::value && - is_copy_constructible<_Tp>::value> > - _LIBCPP_HIDE_FROM_ABI any(_ValueType&& __value); + template < + class _ValueType, + class _Tp = decay_t<_ValueType>, + enable_if_t<_And<_Not<is_same<_Tp, any>>, _Not<__is_inplace_type<_ValueType>>, is_copy_constructible<_Tp>>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI any(_ValueType&& __value) : __h_(nullptr) { + __any_imp::_Handler<_Tp>::__create(*this, std::forward<_ValueType>(__value)); + } template <class _ValueType, class... _Args, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< is_constructible<_Tp, _Args...>::value && is_copy_constructible<_Tp>::value > > - _LIBCPP_HIDE_FROM_ABI explicit any(in_place_type_t<_ValueType>, _Args&&... __args); + class _Tp = decay_t<_ValueType>, + enable_if_t<is_constructible_v<_Tp, _Args...> && is_copy_constructible_v<_Tp>, int> = 0> + _LIBCPP_HIDE_FROM_ABI explicit any(in_place_type_t<_ValueType>, _Args&&... __args) { + __any_imp::_Handler<_Tp>::__create(*this, std::forward<_Args>(__args)...); + } - template <class _ValueType, - class _Up, - class... _Args, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value && - is_copy_constructible<_Tp>::value> > - _LIBCPP_HIDE_FROM_ABI explicit any(in_place_type_t<_ValueType>, initializer_list<_Up>, _Args&&... __args); + template < + class _ValueType, + class _Up, + class... _Args, + class _Tp = decay_t<_ValueType>, + enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...> && is_copy_constructible_v<_Tp>, int> = 0> + _LIBCPP_HIDE_FROM_ABI explicit any(in_place_type_t<_ValueType>, initializer_list<_Up> __il, _Args&&... __args) { + __any_imp::_Handler<_Tp>::__create(*this, __il, std::forward<_Args>(__args)...); + } _LIBCPP_HIDE_FROM_ABI ~any() { this->reset(); } @@ -232,43 +238,65 @@ public: return *this; } - _LIBCPP_HIDE_FROM_ABI any& operator=(any&& __rhs) _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI any& operator=(any&& __rhs) noexcept { any(std::move(__rhs)).swap(*this); return *this; } - template < class _ValueType, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< !is_same<_Tp, any>::value && is_copy_constructible<_Tp>::value> > - _LIBCPP_HIDE_FROM_ABI any& operator=(_ValueType&& __rhs); - template <class _ValueType, - class... _Args, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< is_constructible<_Tp, _Args...>::value && is_copy_constructible<_Tp>::value> > - _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&...); + class _Tp = decay_t<_ValueType>, + enable_if_t<!is_same_v<_Tp, any> && is_copy_constructible_v<_Tp>, int> = 0> + _LIBCPP_HIDE_FROM_ABI any& operator=(_ValueType&& __rhs) { + any(std::forward<_ValueType>(__rhs)).swap(*this); + return *this; + } template <class _ValueType, - class _Up, class... _Args, - class _Tp = decay_t<_ValueType>, - class = enable_if_t< is_constructible<_Tp, initializer_list<_Up>&, _Args...>::value && - is_copy_constructible<_Tp>::value> > - _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up>, _Args&&...); + class _Tp = decay_t<_ValueType>, + enable_if_t<is_constructible_v<_Tp, _Args...> && is_copy_constructible_v<_Tp>, int> = 0> + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(_Args&&... __args) { + reset(); + return __any_imp::_Handler<_Tp>::__create(*this, std::forward<_Args>(__args)...); + } + + template < + class _ValueType, + class _Up, + class... _Args, + class _Tp = decay_t<_ValueType>, + enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...> && is_copy_constructible_v<_Tp>, int> = 0> + _LIBCPP_HIDE_FROM_ABI _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { + reset(); + return __any_imp::_Handler<_Tp>::__create(*this, __il, std::forward<_Args>(__args)...); + } // 6.3.3 any modifiers - _LIBCPP_HIDE_FROM_ABI void reset() _NOEXCEPT { + _LIBCPP_HIDE_FROM_ABI void reset() noexcept { if (__h_) this->__call(_Action::_Destroy); } - _LIBCPP_HIDE_FROM_ABI void swap(any& __rhs) _NOEXCEPT; + _LIBCPP_HIDE_FROM_ABI void swap(any& __rhs) noexcept { + if (this == &__rhs) + return; + if (__h_ && __rhs.__h_) { + any __tmp; + __rhs.__call(_Action::_Move, &__tmp); + this->__call(_Action::_Move, &__rhs); + __tmp.__call(_Action::_Move, this); + } else if (__h_) { + this->__call(_Action::_Move, &__rhs); + } else if (__rhs.__h_) { + __rhs.__call(_Action::_Move, this); + } + } // 6.3.4 any observers - _LIBCPP_HIDE_FROM_ABI bool has_value() const _NOEXCEPT { return __h_ != nullptr; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool has_value() const noexcept { return __h_ != nullptr; } # if _LIBCPP_HAS_RTTI - _LIBCPP_HIDE_FROM_ABI const type_info& type() const _NOEXCEPT { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const type_info& type() const noexcept { if (__h_) { return *static_cast<type_info const*>(this->__call(_Action::_TypeInfo)); } else { @@ -285,7 +313,7 @@ private: union _Storage { _LIBCPP_HIDE_FROM_ABI constexpr _Storage() : __ptr(nullptr) {} void* __ptr; - __any_imp::_Buffer __buf; + alignas(__any_imp::__small_buffer_alignment) char __buf[__any_imp::__small_buffer_size]; }; _LIBCPP_HIDE_FROM_ABI void* @@ -305,10 +333,10 @@ private: friend struct __any_imp::_LargeHandler; template <class _ValueType> - friend add_pointer_t<add_const_t<_ValueType>> any_cast(any const*) _NOEXCEPT; + friend add_pointer_t<add_const_t<_ValueType>> any_cast(any const*) noexcept; template <class _ValueType> - friend add_pointer_t<_ValueType> any_cast(any*) _NOEXCEPT; + friend add_pointer_t<_ValueType> any_cast(any*) noexcept; _HandleFuncPtr __h_ = nullptr; _Storage __s_; @@ -339,22 +367,14 @@ struct _SmallHandler { template <class... _Args> _LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) { - typedef allocator<_Tp> _Alloc; - typedef allocator_traits<_Alloc> _ATraits; - _Alloc __a; - _Tp* __ret = static_cast<_Tp*>(static_cast<void*>(&__dest.__s_.__buf)); - _ATraits::construct(__a, __ret, std::forward<_Args>(__args)...); + auto __ret = std::__construct_at(reinterpret_cast<_Tp*>(&__dest.__s_.__buf), std::forward<_Args>(__args)...); __dest.__h_ = &_SmallHandler::__handle; return *__ret; } private: _LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) { - typedef allocator<_Tp> _Alloc; - typedef allocator_traits<_Alloc> _ATraits; - _Alloc __a; - _Tp* __p = static_cast<_Tp*>(static_cast<void*>(&__this.__s_.__buf)); - _ATraits::destroy(__a, __p); + std::__destroy_at(reinterpret_cast<_Tp*>(&__this.__s_.__buf)); __this.__h_ = nullptr; } @@ -406,26 +426,20 @@ struct _LargeHandler { template <class... _Args> _LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) { - typedef allocator<_Tp> _Alloc; - typedef allocator_traits<_Alloc> _ATraits; - typedef __allocator_destructor<_Alloc> _Dp; - _Alloc __a; - unique_ptr<_Tp, _Dp> __hold(_ATraits::allocate(__a, 1), _Dp(__a, 1)); - _Tp* __ret = __hold.get(); - _ATraits::construct(__a, __ret, std::forward<_Args>(__args)...); - __dest.__s_.__ptr = __hold.release(); + _Tp* __ptr = static_cast<_Tp*>(std::__libcpp_allocate<_Tp>(__element_count(1))); + std::__exception_guard __guard([&] { std::__libcpp_deallocate<_Tp>(__ptr, __element_count(1)); }); + std::__construct_at(__ptr, std::forward<_Args>(__args)...); + __guard.__complete(); + __dest.__s_.__ptr = __ptr; __dest.__h_ = &_LargeHandler::__handle; - return *__ret; + return *__ptr; } private: _LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) { - typedef allocator<_Tp> _Alloc; - typedef allocator_traits<_Alloc> _ATraits; - _Alloc __a; _Tp* __p = static_cast<_Tp*>(__this.__s_.__ptr); - _ATraits::destroy(__a, __p); - _ATraits::deallocate(__a, __p, 1); + std::__destroy_at(__p); + std::__libcpp_deallocate<_Tp>(__p, __element_count(1)); __this.__h_ = nullptr; } @@ -456,72 +470,24 @@ private: } // namespace __any_imp -template <class _ValueType, class _Tp, class> -any::any(_ValueType&& __v) : __h_(nullptr) { - __any_imp::_Handler<_Tp>::__create(*this, std::forward<_ValueType>(__v)); -} - -template <class _ValueType, class... _Args, class _Tp, class> -any::any(in_place_type_t<_ValueType>, _Args&&... __args) { - __any_imp::_Handler<_Tp>::__create(*this, std::forward<_Args>(__args)...); -} - -template <class _ValueType, class _Up, class... _Args, class _Tp, class> -any::any(in_place_type_t<_ValueType>, initializer_list<_Up> __il, _Args&&... __args) { - __any_imp::_Handler<_Tp>::__create(*this, __il, std::forward<_Args>(__args)...); -} - -template <class _ValueType, class, class> -inline _LIBCPP_HIDE_FROM_ABI any& any::operator=(_ValueType&& __v) { - any(std::forward<_ValueType>(__v)).swap(*this); - return *this; -} - -template <class _ValueType, class... _Args, class _Tp, class> -inline _LIBCPP_HIDE_FROM_ABI _Tp& any::emplace(_Args&&... __args) { - reset(); - return __any_imp::_Handler<_Tp>::__create(*this, std::forward<_Args>(__args)...); -} - -template <class _ValueType, class _Up, class... _Args, class _Tp, class> -inline _LIBCPP_HIDE_FROM_ABI _Tp& any::emplace(initializer_list<_Up> __il, _Args&&... __args) { - reset(); - return __any_imp::_Handler<_Tp>::__create(*this, __il, std::forward<_Args>(__args)...); -} - -inline _LIBCPP_HIDE_FROM_ABI void any::swap(any& __rhs) _NOEXCEPT { - if (this == &__rhs) - return; - if (__h_ && __rhs.__h_) { - any __tmp; - __rhs.__call(_Action::_Move, &__tmp); - this->__call(_Action::_Move, &__rhs); - __tmp.__call(_Action::_Move, this); - } else if (__h_) { - this->__call(_Action::_Move, &__rhs); - } else if (__rhs.__h_) { - __rhs.__call(_Action::_Move, this); - } -} - // 6.4 Non-member functions -inline _LIBCPP_HIDE_FROM_ABI void swap(any& __lhs, any& __rhs) _NOEXCEPT { __lhs.swap(__rhs); } +inline _LIBCPP_HIDE_FROM_ABI void swap(any& __lhs, any& __rhs) noexcept { __lhs.swap(__rhs); } template <class _Tp, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI any make_any(_Args&&... __args) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI any make_any(_Args&&... __args) { return any(in_place_type<_Tp>, std::forward<_Args>(__args)...); } template <class _Tp, class _Up, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI any make_any(initializer_list<_Up> __il, _Args&&... __args) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI any make_any(initializer_list<_Up> __il, _Args&&... __args) { return any(in_place_type<_Tp>, __il, std::forward<_Args>(__args)...); } template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any const& __v) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any const& __v) { using _RawValueType = __remove_cvref_t<_ValueType>; - static_assert(is_constructible<_ValueType, _RawValueType const&>::value, + static_assert(is_constructible_v<_ValueType, _RawValueType const&>, "ValueType is required to be a const lvalue reference " "or a CopyConstructible type"); auto __tmp = std::any_cast<add_const_t<_RawValueType>>(&__v); @@ -531,9 +497,9 @@ inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any const& __v) { } template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any& __v) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any& __v) { using _RawValueType = __remove_cvref_t<_ValueType>; - static_assert(is_constructible<_ValueType, _RawValueType&>::value, + static_assert(is_constructible_v<_ValueType, _RawValueType&>, "ValueType is required to be an lvalue reference " "or a CopyConstructible type"); auto __tmp = std::any_cast<_RawValueType>(&__v); @@ -543,9 +509,9 @@ inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any& __v) { } template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any&& __v) { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any&& __v) { using _RawValueType = __remove_cvref_t<_ValueType>; - static_assert(is_constructible<_ValueType, _RawValueType>::value, + static_assert(is_constructible_v<_ValueType, _RawValueType>, "ValueType is required to be an rvalue reference " "or a CopyConstructible type"); auto __tmp = std::any_cast<_RawValueType>(&__v); @@ -555,39 +521,31 @@ inline _LIBCPP_HIDE_FROM_ABI _ValueType any_cast(any&& __v) { } template <class _ValueType> -inline _LIBCPP_HIDE_FROM_ABI add_pointer_t<add_const_t<_ValueType>> any_cast(any const* __any) _NOEXCEPT { +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI add_pointer_t<add_const_t<_ValueType>> any_cast(any const* __any) noexcept { static_assert(!is_void_v<_ValueType>, "_ValueType may not be void."); - static_assert(!is_reference<_ValueType>::value, "_ValueType may not be a reference."); + static_assert(!is_reference_v<_ValueType>, "_ValueType may not be a reference."); return std::any_cast<_ValueType>(const_cast<any*>(__any)); } -template <class _RetType> -inline _LIBCPP_HIDE_FROM_ABI _RetType __pointer_or_func_cast(void* __p, /*IsFunction*/ false_type) noexcept { - return static_cast<_RetType>(__p); -} - -template <class _RetType> -inline _LIBCPP_HIDE_FROM_ABI _RetType __pointer_or_func_cast(void*, /*IsFunction*/ true_type) noexcept { - return nullptr; -} - template <class _ValueType> -_LIBCPP_HIDE_FROM_ABI add_pointer_t<_ValueType> any_cast(any* __any) _NOEXCEPT { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI add_pointer_t<_ValueType> any_cast(any* __any) noexcept { using __any_imp::_Action; static_assert(!is_void_v<_ValueType>, "_ValueType may not be void."); - static_assert(!is_reference<_ValueType>::value, "_ValueType may not be a reference."); - typedef add_pointer_t<_ValueType> _ReturnType; - if (__any && __any->__h_) { - void* __p = __any->__call( - _Action::_Get, - nullptr, + static_assert(!is_reference_v<_ValueType>, "_ValueType may not be a reference."); + if constexpr (!is_function_v<_ValueType>) { + using _ReturnType = add_pointer_t<_ValueType>; + if (__any && __any->__h_) { + void* __p = __any->__call( + _Action::_Get, + nullptr, # if _LIBCPP_HAS_RTTI - &typeid(_ValueType), + &typeid(_ValueType), # else - nullptr, + nullptr, # endif - __any_imp::__get_fallback_typeid<_ValueType>()); - return std::__pointer_or_func_cast<_ReturnType>(__p, is_function<_ValueType>{}); + __any_imp::__get_fallback_typeid<_ValueType>()); + return static_cast<_ReturnType>(__p); + } } return nullptr; } @@ -613,6 +571,11 @@ _LIBCPP_POP_MACROS # include <type_traits> # include <variant> # endif + +# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23 +# include <cstring> +# include <limits> +# endif #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_ANY diff --git a/lib/libcxx/include/array b/lib/libcxx/include/array @@ -134,7 +134,6 @@ template <size_t I, class T, size_t N> const T&& get(const array<T, N>&&) noexce # include <__type_traits/is_const.h> # include <__type_traits/is_constructible.h> # include <__type_traits/is_nothrow_constructible.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> # include <__type_traits/is_trivially_relocatable.h> @@ -176,7 +175,6 @@ template <class _Tp, size_t _Size> struct array { using __trivially_relocatable _LIBCPP_NODEBUG = __conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, array, void>; - using __replaceable _LIBCPP_NODEBUG = __conditional_t<__is_replaceable_v<_Tp>, array, void>; // types: using __self _LIBCPP_NODEBUG = array; @@ -212,28 +210,28 @@ struct array { } // iterators: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<_Size>(data(), data()); # else return iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<_Size>(data(), data()); # else return const_iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<_Size>(data() + _Size, data()); # else return iterator(data() + _Size); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<_Size>(data() + _Size, data()); # else @@ -241,62 +239,81 @@ struct array { # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { + return begin(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { + return end(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator + crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { + return rend(); + } // capacity: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return _Size; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return _Size; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return _Size; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return _Size; } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return _Size == 0; } // element access: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type __n) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>"); return __elems_[__n]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference operator[](size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference + operator[](size_type __n) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < _Size, "out-of-bounds access in std::array<T, N>"); return __elems_[__n]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type __n) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type __n) { if (__n >= _Size) std::__throw_out_of_range("array::at"); return __elems_[__n]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type __n) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type __n) const { if (__n >= _Size) std::__throw_out_of_range("array::at"); return __elems_[__n]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT { return (*this)[0]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT { return (*this)[0]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT { return (*this)[_Size - 1]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT { + return (*this)[0]; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT { + return (*this)[0]; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT { + return (*this)[_Size - 1]; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT { return (*this)[_Size - 1]; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { return __elems_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { return __elems_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { + return __elems_; + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { + return __elems_; + } }; template <class _Tp> @@ -330,8 +347,10 @@ struct array<_Tp, 0> { }; _ALIGNAS_TYPE(_ArrayInStructT) _EmptyType __elems_[sizeof(_ArrayInStructT)]; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { return nullptr; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { return nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 value_type* data() _NOEXCEPT { return nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const value_type* data() const _NOEXCEPT { + return nullptr; + } // No explicit construct/copy/destroy for aggregate type _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void fill(const value_type&) { @@ -343,28 +362,28 @@ struct array<_Tp, 0> { } // iterators: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator begin() _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<0>(data(), data()); # else return iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator begin() const _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<0>(data(), data()); # else return const_iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 iterator end() _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<0>(data(), data()); # else return iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator end() const _NOEXCEPT { # if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STD_ARRAY) return std::__make_static_bounded_iter<0>(data(), data()); # else @@ -372,68 +391,77 @@ struct array<_Tp, 0> { # endif } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cbegin() const _NOEXCEPT { + return begin(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_iterator cend() const _NOEXCEPT { + return end(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator + crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 const_reverse_iterator crend() const _NOEXCEPT { + return rend(); + } // capacity: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return 0; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return 0; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT { return 0; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT { return 0; } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return true; } // element access: - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference operator[](size_type) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference operator[](size_type) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference + operator[](size_type) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::operator[] on a zero-sized array"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference at(size_type) { std::__throw_out_of_range("array<T, 0>::at"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference at(size_type) const { std::__throw_out_of_range("array<T, 0>::at"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::front() on a zero-sized array"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 reference back() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array"); __libcpp_unreachable(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const_reference back() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "cannot call array<T, 0>::back() on a zero-sized array"); __libcpp_unreachable(); } @@ -503,25 +531,29 @@ struct tuple_element<_Ip, array<_Tp, _Size> > { }; template <size_t _Ip, class _Tp, size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp& get(array<_Tp, _Size>& __a) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp& +get(array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array)"); return __a.__elems_[_Ip]; } template <size_t _Ip, class _Tp, size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& get(const array<_Tp, _Size>& __a) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp& +get(const array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array)"); return __a.__elems_[_Ip]; } template <size_t _Ip, class _Tp, size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp&& get(array<_Tp, _Size>&& __a) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp&& +get(array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array &&)"); return std::move(__a.__elems_[_Ip]); } template <size_t _Ip, class _Tp, size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& get(const array<_Tp, _Size>&& __a) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Tp&& +get(const array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array &&)"); return std::move(__a.__elems_[_Ip]); } @@ -541,7 +573,7 @@ __to_array_rvalue_impl(_Tp (&&__arr)[_Size], index_sequence<_Index...>) { } template <typename _Tp, size_t _Size> -_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size> to_array(_Tp (&__arr)[_Size]) noexcept(is_nothrow_constructible_v<_Tp, _Tp&>) { static_assert(!is_array_v<_Tp>, "[array.creation]/1: to_array does not accept multidimensional arrays."); static_assert(is_constructible_v<_Tp, _Tp&>, "[array.creation]/1: to_array requires copy constructible elements."); @@ -549,7 +581,7 @@ to_array(_Tp (&__arr)[_Size]) noexcept(is_nothrow_constructible_v<_Tp, _Tp&>) { } template <typename _Tp, size_t _Size> -_LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr array<remove_cv_t<_Tp>, _Size> to_array(_Tp (&&__arr)[_Size]) noexcept(is_nothrow_move_constructible_v<_Tp>) { static_assert(!is_array_v<_Tp>, "[array.creation]/4: to_array does not accept multidimensional arrays."); static_assert(is_move_constructible_v<_Tp>, "[array.creation]/4: to_array requires move constructible elements."); diff --git a/lib/libcxx/include/atomic b/lib/libcxx/include/atomic @@ -608,6 +608,8 @@ template <class T> # include <__atomic/atomic_init.h> # include <__atomic/atomic_lock_free.h> # include <__atomic/atomic_sync.h> +# include <__atomic/atomic_sync_timed.h> +# include <__atomic/atomic_waitable_traits.h> # include <__atomic/check_memory_order.h> # include <__atomic/contention_t.h> # include <__atomic/fence.h> diff --git a/lib/libcxx/include/barrier b/lib/libcxx/include/barrier @@ -57,8 +57,6 @@ namespace std # include <__atomic/memory_order.h> # include <__cstddef/ptrdiff_t.h> # include <__memory/unique_ptr.h> -# include <__thread/poll_with_backoff.h> -# include <__thread/timed_backoff_policy.h> # include <__utility/move.h> # include <cstdint> # include <limits> @@ -97,19 +95,20 @@ using __barrier_phase_t _LIBCPP_NODEBUG = uint8_t; class __barrier_algorithm_base; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base* -__construct_barrier_algorithm_base(ptrdiff_t& __expected); +[[__gnu__::__returns_nonnull__, __gnu__::__malloc__]] +_LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base* __construct_barrier_algorithm_base(ptrdiff_t& __expected); -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI bool -__arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier, __barrier_phase_t __old_phase) noexcept; +_LIBCPP_EXPORTED_FROM_ABI bool +__arrive_barrier_algorithm_base([[__gnu__::__nonnull__]] _LIBCPP_NOESCAPE __barrier_algorithm_base* __barrier, + __barrier_phase_t __old_phase) noexcept; -_LIBCPP_AVAILABILITY_SYNC _LIBCPP_EXPORTED_FROM_ABI void -__destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier) noexcept; +_LIBCPP_EXPORTED_FROM_ABI void __destroy_barrier_algorithm_base( + [[__gnu__::__nonnull__]] _LIBCPP_NOESCAPE __barrier_algorithm_base* __barrier) noexcept; template <class _CompletionF> class __barrier_base { ptrdiff_t __expected_; - unique_ptr<__barrier_algorithm_base, void (*)(__barrier_algorithm_base*)> __base_; + unique_ptr<__barrier_algorithm_base, void (*)(_LIBCPP_NOESCAPE __barrier_algorithm_base*)> __base_; atomic<ptrdiff_t> __expected_adjustment_; _CompletionF __completion_; atomic<__barrier_phase_t> __phase_; @@ -119,14 +118,13 @@ public: static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI - __barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF()) + _LIBCPP_HIDE_FROM_ABI __barrier_base(ptrdiff_t __expected, _CompletionF __completion = _CompletionF()) : __expected_(__expected), __base_(std::__construct_barrier_algorithm_base(this->__expected_), &__destroy_barrier_algorithm_base), __expected_adjustment_(0), __completion_(std::move(__completion)), __phase_(0) {} - [[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __update <= __expected_, "update is greater than the expected count for the current barrier phase"); @@ -141,11 +139,10 @@ public: } return __old_phase; } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __old_phase) const { - auto const __test_fn = [this, __old_phase]() -> bool { return __phase_.load(memory_order_acquire) != __old_phase; }; - std::__libcpp_thread_poll_with_backoff(__test_fn, __libcpp_timed_backoff_policy()); + _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __old_phase) const { + __phase_.wait(__old_phase, std::memory_order_acquire); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() { + _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() { __expected_adjustment_.fetch_sub(1, memory_order_relaxed); (void)arrive(1); } @@ -158,9 +155,10 @@ class barrier { public: using arrival_token = typename __barrier_base<_CompletionF>::arrival_token; - static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return __barrier_base<_CompletionF>::max(); } + [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { + return __barrier_base<_CompletionF>::max(); + } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI explicit barrier(ptrdiff_t __count, _CompletionF __completion = _CompletionF()) : __b_(__count, std::move(__completion)) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( @@ -175,15 +173,13 @@ public: barrier(barrier const&) = delete; barrier& operator=(barrier const&) = delete; - [[nodiscard]] _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update = 1) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI arrival_token arrive(ptrdiff_t __update = 1) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update > 0, "barrier:arrive must be called with a value greater than 0"); return __b_.arrive(__update); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __phase) const { - __b_.wait(std::move(__phase)); - } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait() { wait(arrive()); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() { __b_.arrive_and_drop(); } + _LIBCPP_HIDE_FROM_ABI void wait(arrival_token&& __phase) const { __b_.wait(std::move(__phase)); } + _LIBCPP_HIDE_FROM_ABI void arrive_and_wait() { wait(arrive()); } + _LIBCPP_HIDE_FROM_ABI void arrive_and_drop() { __b_.arrive_and_drop(); } }; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/bitset b/lib/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 @@ -677,53 +675,63 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& set(size_t __pos, bool __val = true); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& reset() _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& reset(size_t __pos); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator~() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator~() const _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& flip() _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset& flip(size_t __pos); // element access: -# ifdef _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { + // TODO(LLVM 24): Remove the opt-out +# ifndef _LIBCPP_DEPRECATED_ABI_BITSET_CONST_SUBSCRIPT_RETURN_REF + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator[](size_t __p) const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds"); return __base::__make_ref(__p); } # else - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference operator[](size_t __p) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __const_reference operator[](size_t __p) const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds"); return __base::__make_ref(__p); } # endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 reference operator[](size_t __p) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__p < _Size, "bitset::operator[] index out of bounds"); return __base::__make_ref(__p); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { return __base::to_ulong(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long to_ulong() const { + return __base::to_ulong(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unsigned long long to_ullong() const { return __base::to_ullong(); } template <class _CharT, class _Traits, class _Allocator> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, _Allocator> to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const; template <class _CharT, class _Traits> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, allocator<_CharT> > + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, _Traits, allocator<_CharT> > to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const; template <class _CharT> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, char_traits<_CharT>, allocator<_CharT> > + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<_CharT, char_traits<_CharT>, allocator<_CharT> > to_string(_CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) const; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<char, char_traits<char>, allocator<char> > + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX23 basic_string<char, char_traits<char>, allocator<char> > to_string(char __zero = '0', char __one = '1') const; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t count() const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_t size() const _NOEXCEPT { return _Size; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t count() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR size_t size() const _NOEXCEPT { return _Size; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const bitset& __rhs) const _NOEXCEPT; # if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI bool operator!=(const bitset& __rhs) const _NOEXCEPT; # endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool test(size_t __pos) const; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { return __base::all(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT { return __base::any(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool none() const _NOEXCEPT { return !any(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator<<(size_t __pos) const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator>>(size_t __pos) const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool test(size_t __pos) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool all() const _NOEXCEPT { + return __base::all(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool any() const _NOEXCEPT { + return __base::any(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool none() const _NOEXCEPT { return !any(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator<<(size_t __pos) const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset operator>>(size_t __pos) const _NOEXCEPT; private: template <class _CharT, class _Traits> @@ -869,7 +877,16 @@ bitset<_Size>::to_string(char __zero, char __one) const { template <size_t _Size> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 size_t bitset<_Size>::count() const _NOEXCEPT { - return static_cast<size_t>(std::count(__base::__make_iter(0), __base::__make_iter(_Size), true)); +# if defined(_LIBCPP_COMPILER_CLANG_BASED) && !defined(_LIBCPP_CXX03_LANG) + if constexpr (_Size == 0) { + return 0; + } else if constexpr (_Size <= __base::__bits_per_word) { + return __builtin_popcountg(static_cast<unsigned _BitInt(_Size)>(__base::__first_)); + } else +# endif + { + return static_cast<size_t>(std::count(__base::__make_iter(0), __base::__make_iter(_Size), true)); + } } template <size_t _Size> @@ -912,7 +929,7 @@ bitset<_Size>::operator>>(size_t __pos) const _NOEXCEPT { } template <size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> operator&(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { bitset<_Size> __r = __x; __r &= __y; @@ -920,7 +937,7 @@ operator&(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { } template <size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { bitset<_Size> __r = __x; __r |= __y; @@ -928,7 +945,7 @@ operator|(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { } template <size_t _Size> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bitset<_Size> operator^(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { bitset<_Size> __r = __x; __r ^= __y; @@ -937,7 +954,9 @@ operator^(const bitset<_Size>& __x, const bitset<_Size>& __y) _NOEXCEPT { template <size_t _Size> struct hash<bitset<_Size> > : public __unary_function<bitset<_Size>, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(const bitset<_Size>& __bs) const _NOEXCEPT { return __bs.__hash_code(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const bitset<_Size>& __bs) const _NOEXCEPT { + return __bs.__hash_code(); + } }; template <class _CharT, class _Traits, size_t _Size> diff --git a/lib/libcxx/include/ccomplex b/lib/libcxx/include/ccomplex @@ -26,18 +26,10 @@ # pragma GCC system_header # endif -# if _LIBCPP_STD_VER >= 20 - -using __standard_header_ccomplex - _LIBCPP_DEPRECATED_("removed in C++20. Include <complex> instead.") _LIBCPP_NODEBUG = void; -using __use_standard_header_ccomplex _LIBCPP_NODEBUG = __standard_header_ccomplex; - -# elif _LIBCPP_STD_VER >= 17 - -using __standard_header_ccomplex _LIBCPP_DEPRECATED_("Include <complex> instead.") _LIBCPP_NODEBUG = void; -using __use_standard_header_ccomplex _LIBCPP_NODEBUG = __standard_header_ccomplex; - +# if _LIBCPP_STD_VER >= 17 && !__building_module(std) && _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS +# warning <ccomplex> is deprecated in C++17 and removed in C++20. Include <complex> instead. # endif + #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_CCOMPLEX diff --git a/lib/libcxx/include/chrono b/lib/libcxx/include/chrono @@ -218,6 +218,9 @@ template <class ToDuration, class Rep, class Period> template <class ToDuration, class Rep, class Period> constexpr ToDuration round(const duration<Rep, Period>& d); // C++17 +template <class T> struct is_clock; // C++20 +template <class T> inline constexpr bool is_clock_v = is_clock<T>::value; // C++20 + // duration I/O template<class charT, class traits, class Rep, class Period> // C++20 basic_ostream<charT, traits>& @@ -1035,6 +1038,49 @@ constexpr chrono::year operator ""y(unsigned lo } // chrono_literals } // literals +namespace std { + template<class T> + struct hash; // C++26 + template<class Rep, class Period> + struct hash<chrono::duration<Rep, Period>>; // C++26 + template<class Clock, class Duration> + struct hash<chrono::time_point<Clock, Duration>>; // C++26 + template<> + struct hash<chrono::day>; // C++26 + template<> + struct hash<chrono::month>; // C++26 + template<> + struct hash<chrono::year>; // C++26 + template<> + struct hash<chrono::weekday>; // C++26 + template<> + struct hash<chrono::weekday_indexed>; // C++26 + template<> + struct hash<chrono::weekday_last>; // C++26 + template<> + struct hash<chrono::month_day>; // C++26 + template<> + struct hash<chrono::month_day_last>; // C++26 + template<> + struct hash<chrono::month_weekday>; // C++26 + template<> + struct hash<chrono::month_weekday_last>; // C++26 + template<> + struct hash<chrono::year_month>; // C++26 + template<> + struct hash<chrono::year_month_day>; // C++26 + template<> + struct hash<chrono::year_month_day_last>; // C++26 + template<> + struct hash<chrono::year_month_weekday>; // C++26 + template<> + struct hash<chrono::year_month_weekday_last>; // C++26 + template<class Duration, class TimeZonePtr> + struct hash<chrono::zoned_time<Duration, TimeZonePtr>>; // C++26 + template<> + struct hash<chrono::leap_second>; // C++26 +} // namespace std + } // std */ @@ -1057,6 +1103,7 @@ constexpr chrono::year operator ""y(unsigned lo # include <__chrono/day.h> # include <__chrono/exception.h> # include <__chrono/hh_mm_ss.h> +# include <__chrono/is_clock.h> # include <__chrono/literals.h> # include <__chrono/local_info.h> # include <__chrono/month.h> diff --git a/lib/libcxx/include/ciso646 b/lib/libcxx/include/ciso646 @@ -24,13 +24,10 @@ # pragma GCC system_header # endif -# if _LIBCPP_STD_VER >= 20 - -using __standard_header_ciso646 - _LIBCPP_DEPRECATED_("removed in C++20. Include <version> instead.") _LIBCPP_NODEBUG = void; -using __use_standard_header_ciso646 _LIBCPP_NODEBUG = __standard_header_ciso646; - +# if _LIBCPP_STD_VER >= 20 && !__building_module(std) && _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS +# warning <ciso646> is removed in C++20. Include <version> instead. # endif + #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_CISO646 diff --git a/lib/libcxx/include/complex b/lib/libcxx/include/complex @@ -319,8 +319,8 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 complex(const complex<_Xp>& __c) : __re_(__c.real()), __im_(__c.imag()) {} - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type real() const { return __re_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type imag() const { return __im_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type real() const { return __re_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 value_type imag() const { return __im_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; } @@ -432,8 +432,8 @@ public: _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<double>& __c); _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<long double>& __c); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float real() const { return __re_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float imag() const { return __im_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float real() const { return __re_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR float imag() const { return __im_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; } @@ -529,8 +529,8 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c); _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<long double>& __c); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double real() const { return __re_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double imag() const { return __im_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double real() const { return __re_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR double imag() const { return __im_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; } @@ -630,8 +630,8 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<double>& __c); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double real() const { return __re_; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double imag() const { return __im_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double real() const { return __re_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR long double imag() const { return __im_; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void real(value_type __re) { __re_ = __re; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void imag(value_type __im) { __im_ = __im; } @@ -732,7 +732,7 @@ inline _LIBCPP_CONSTEXPR complex<long double>::complex(const complex<double>& __ // 26.3.6 operators: template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator+(const complex<_Tp>& __x, const complex<_Tp>& __y) { complex<_Tp> __t(__x); __t += __y; @@ -740,7 +740,7 @@ operator+(const complex<_Tp>& __x, const complex<_Tp>& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator+(const complex<_Tp>& __x, const _Tp& __y) { complex<_Tp> __t(__x); __t += __y; @@ -748,7 +748,7 @@ operator+(const complex<_Tp>& __x, const _Tp& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator+(const _Tp& __x, const complex<_Tp>& __y) { complex<_Tp> __t(__y); __t += __x; @@ -756,7 +756,7 @@ operator+(const _Tp& __x, const complex<_Tp>& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator-(const complex<_Tp>& __x, const complex<_Tp>& __y) { complex<_Tp> __t(__x); __t -= __y; @@ -764,7 +764,7 @@ operator-(const complex<_Tp>& __x, const complex<_Tp>& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator-(const complex<_Tp>& __x, const _Tp& __y) { complex<_Tp> __t(__x); __t -= __y; @@ -772,7 +772,7 @@ operator-(const complex<_Tp>& __x, const _Tp& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator-(const _Tp& __x, const complex<_Tp>& __y) { complex<_Tp> __t(-__y); __t += __x; @@ -780,13 +780,13 @@ operator-(const _Tp& __x, const complex<_Tp>& __y) { } template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const complex<_Tp>& __lhs, const complex<_Tp>& __rhs) { return complex<_Tp>(__from_builtin_tag(), __lhs.__builtin() * __rhs.__builtin()); } template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const complex<_Tp>& __z, const complex<_Tp>& __w) { _Tp __a = __z.real(); _Tp __b = __z.imag(); @@ -797,7 +797,7 @@ operator*(const complex<_Tp>& __z, const complex<_Tp>& __w) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const complex<_Tp>& __x, const _Tp& __y) { complex<_Tp> __t(__x); __t *= __y; @@ -805,7 +805,7 @@ operator*(const complex<_Tp>& __x, const _Tp& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator*(const _Tp& __x, const complex<_Tp>& __y) { complex<_Tp> __t(__y); __t *= __x; @@ -813,13 +813,13 @@ operator*(const _Tp& __x, const complex<_Tp>& __y) { } template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const complex<_Tp>& __lhs, const complex<_Tp>& __rhs) { return complex<_Tp>(__from_builtin_tag(), __lhs.__builtin() / __rhs.__builtin()); } template <class _Tp, __enable_if_t<!is_floating_point<_Tp>::value, int> > -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const complex<_Tp>& __z, const complex<_Tp>& __w) { _Tp __a = __z.real(); _Tp __b = __z.imag(); @@ -831,13 +831,13 @@ operator/(const complex<_Tp>& __z, const complex<_Tp>& __w) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const complex<_Tp>& __x, const _Tp& __y) { return complex<_Tp>(__x.real() / __y, __x.imag() / __y); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator/(const _Tp& __x, const complex<_Tp>& __y) { complex<_Tp> __t(__x); __t /= __y; @@ -845,12 +845,14 @@ operator/(const _Tp& __x, const complex<_Tp>& __y) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator+(const complex<_Tp>& __x) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +operator+(const complex<_Tp>& __x) { return __x; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> operator-(const complex<_Tp>& __x) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +operator-(const complex<_Tp>& __x) { return complex<_Tp>(-__x.real(), -__x.imag()); } @@ -912,12 +914,13 @@ struct __libcpp_complex_overload_traits<_Tp, false, true> { // real template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp real(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp real(const complex<_Tp>& __c) { return __c.real(); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __libcpp_complex_overload_traits<_Tp>::_ValueType +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename __libcpp_complex_overload_traits<_Tp>::_ValueType real(_Tp __re) { return __re; } @@ -925,12 +928,13 @@ real(_Tp __re) { // imag template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp imag(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp imag(const complex<_Tp>& __c) { return __c.imag(); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __libcpp_complex_overload_traits<_Tp>::_ValueType +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename __libcpp_complex_overload_traits<_Tp>::_ValueType imag(_Tp) { return 0; } @@ -938,36 +942,36 @@ imag(_Tp) { // abs template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _Tp abs(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _Tp abs(const complex<_Tp>& __c) { return std::hypot(__c.real(), __c.imag()); } // arg template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _Tp arg(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _Tp arg(const complex<_Tp>& __c) { return std::atan2(__c.imag(), __c.real()); } template <class _Tp, __enable_if_t<is_same<_Tp, long double>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI long double arg(_Tp __re) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI long double arg(_Tp __re) { return std::atan2l(0.L, __re); } template <class _Tp, __enable_if_t<is_integral<_Tp>::value || is_same<_Tp, double>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI double arg(_Tp __re) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI double arg(_Tp __re) { return std::atan2(0., __re); } template <class _Tp, __enable_if_t<is_same<_Tp, float>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI float arg(_Tp __re) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI float arg(_Tp __re) { return std::atan2f(0.F, __re); } // norm template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp norm(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp norm(const complex<_Tp>& __c) { if (std::__constexpr_isinf(__c.real())) return std::abs(__c.real()); if (std::__constexpr_isinf(__c.imag())) @@ -976,7 +980,8 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp norm(const comple } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __libcpp_complex_overload_traits<_Tp>::_ValueType +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +typename __libcpp_complex_overload_traits<_Tp>::_ValueType norm(_Tp __re) { typedef typename __libcpp_complex_overload_traits<_Tp>::_ValueType _ValueType; return static_cast<_ValueType>(__re) * __re; @@ -985,12 +990,14 @@ norm(_Tp __re) { // conj template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> conj(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 complex<_Tp> +conj(const complex<_Tp>& __c) { return complex<_Tp>(__c.real(), -__c.imag()); } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __libcpp_complex_overload_traits<_Tp>::_ComplexType +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 +typename __libcpp_complex_overload_traits<_Tp>::_ComplexType conj(_Tp __re) { typedef typename __libcpp_complex_overload_traits<_Tp>::_ComplexType _ComplexType; return _ComplexType(__re); @@ -999,7 +1006,7 @@ conj(_Tp __re) { // proj template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> proj(const complex<_Tp>& __c) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> proj(const complex<_Tp>& __c) { complex<_Tp> __r = __c; if (std::isinf(__c.real()) || std::isinf(__c.imag())) __r = complex<_Tp>(INFINITY, std::copysign(_Tp(0), __c.imag())); @@ -1007,14 +1014,16 @@ inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> proj(const complex<_Tp>& __c) { } template <class _Tp, __enable_if_t<is_floating_point<_Tp>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI typename __libcpp_complex_overload_traits<_Tp>::_ComplexType proj(_Tp __re) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI typename __libcpp_complex_overload_traits<_Tp>::_ComplexType +proj(_Tp __re) { if (std::isinf(__re)) __re = std::abs(__re); return complex<_Tp>(__re); } template <class _Tp, __enable_if_t<is_integral<_Tp>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI typename __libcpp_complex_overload_traits<_Tp>::_ComplexType proj(_Tp __re) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI typename __libcpp_complex_overload_traits<_Tp>::_ComplexType +proj(_Tp __re) { typedef typename __libcpp_complex_overload_traits<_Tp>::_ComplexType _ComplexType; return _ComplexType(__re); } @@ -1022,7 +1031,7 @@ inline _LIBCPP_HIDE_FROM_ABI typename __libcpp_complex_overload_traits<_Tp>::_Co // polar template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> polar(const _Tp& __rho, const _Tp& __theta = _Tp()) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> polar(const _Tp& __rho, const _Tp& __theta = _Tp()) { if (std::isnan(__rho) || std::signbit(__rho)) return complex<_Tp>(_Tp(NAN), _Tp(NAN)); if (std::isnan(__theta)) { @@ -1047,21 +1056,21 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> polar(const _Tp& __rho, const _Tp& __theta = // log template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> log(const complex<_Tp>& __x) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> log(const complex<_Tp>& __x) { return complex<_Tp>(std::log(std::abs(__x)), std::arg(__x)); } // log10 template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> log10(const complex<_Tp>& __x) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> log10(const complex<_Tp>& __x) { return std::log(__x) / std::log(_Tp(10)); } // sqrt template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> sqrt(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> sqrt(const complex<_Tp>& __x) { if (std::isinf(__x.imag())) return complex<_Tp>(_Tp(INFINITY), __x.imag()); if (std::isinf(__x.real())) { @@ -1075,7 +1084,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> sqrt(const complex<_Tp>& __x) { // exp template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) { _Tp __i = __x.imag(); if (__i == 0) { return complex<_Tp>(std::exp(__x.real()), std::copysign(_Tp(0), __x.imag())); @@ -1097,24 +1106,27 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> exp(const complex<_Tp>& __x) { // pow template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> pow(const complex<_Tp>& __x, const complex<_Tp>& __y) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> pow(const complex<_Tp>& __x, const complex<_Tp>& __y) { return std::exp(__y * std::log(__x)); } template <class _Tp, class _Up, __enable_if_t<is_floating_point<_Tp>::value && is_floating_point<_Up>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > pow(const complex<_Tp>& __x, const complex<_Up>& __y) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > +pow(const complex<_Tp>& __x, const complex<_Up>& __y) { typedef complex<__promote_t<_Tp, _Up> > result_type; return std::pow(result_type(__x), result_type(__y)); } template <class _Tp, class _Up, __enable_if_t<is_floating_point<_Tp>::value && is_arithmetic<_Up>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > pow(const complex<_Tp>& __x, const _Up& __y) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > +pow(const complex<_Tp>& __x, const _Up& __y) { typedef complex<__promote_t<_Tp, _Up> > result_type; return std::pow(result_type(__x), result_type(__y)); } template <class _Tp, class _Up, __enable_if_t<is_arithmetic<_Tp>::value && is_floating_point<_Up>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > pow(const _Tp& __x, const complex<_Up>& __y) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<__promote_t<_Tp, _Up> > +pow(const _Tp& __x, const complex<_Up>& __y) { typedef complex<__promote_t<_Tp, _Up> > result_type; return std::pow(result_type(__x), result_type(__y)); } @@ -1129,7 +1141,7 @@ inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> __sqr(const complex<_Tp>& __x) { // asinh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> asinh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> asinh(const complex<_Tp>& __x) { const _Tp __pi(atan2(+0., -0.)); if (std::isinf(__x.real())) { if (std::isnan(__x.imag())) @@ -1154,7 +1166,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> asinh(const complex<_Tp>& __x) { // acosh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> acosh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> acosh(const complex<_Tp>& __x) { const _Tp __pi(atan2(+0., -0.)); if (std::isinf(__x.real())) { if (std::isnan(__x.imag())) @@ -1183,7 +1195,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> acosh(const complex<_Tp>& __x) { // atanh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> atanh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> atanh(const complex<_Tp>& __x) { const _Tp __pi(atan2(+0., -0.)); if (std::isinf(__x.imag())) { return complex<_Tp>(std::copysign(_Tp(0), __x.real()), std::copysign(__pi / _Tp(2), __x.imag())); @@ -1209,7 +1221,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> atanh(const complex<_Tp>& __x) { // sinh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> sinh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> sinh(const complex<_Tp>& __x) { if (std::isinf(__x.real()) && !std::isfinite(__x.imag())) return complex<_Tp>(__x.real(), _Tp(NAN)); if (__x.real() == 0 && !std::isfinite(__x.imag())) @@ -1222,7 +1234,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> sinh(const complex<_Tp>& __x) { // cosh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> cosh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> cosh(const complex<_Tp>& __x) { if (std::isinf(__x.real()) && !std::isfinite(__x.imag())) return complex<_Tp>(std::abs(__x.real()), _Tp(NAN)); if (__x.real() == 0 && !std::isfinite(__x.imag())) @@ -1237,7 +1249,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> cosh(const complex<_Tp>& __x) { // tanh template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> tanh(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> tanh(const complex<_Tp>& __x) { if (std::isinf(__x.real())) { if (!std::isfinite(__x.imag())) return complex<_Tp>(std::copysign(_Tp(1), __x.real()), _Tp(0)); @@ -1257,7 +1269,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> tanh(const complex<_Tp>& __x) { // asin template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> asin(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> asin(const complex<_Tp>& __x) { complex<_Tp> __z = std::asinh(complex<_Tp>(-__x.imag(), __x.real())); return complex<_Tp>(__z.imag(), -__z.real()); } @@ -1265,7 +1277,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> asin(const complex<_Tp>& __x) { // acos template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> acos(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> acos(const complex<_Tp>& __x) { const _Tp __pi(atan2(+0., -0.)); if (std::isinf(__x.real())) { if (std::isnan(__x.imag())) @@ -1297,7 +1309,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> acos(const complex<_Tp>& __x) { // atan template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> atan(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> atan(const complex<_Tp>& __x) { complex<_Tp> __z = std::atanh(complex<_Tp>(-__x.imag(), __x.real())); return complex<_Tp>(__z.imag(), -__z.real()); } @@ -1305,7 +1317,7 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> atan(const complex<_Tp>& __x) { // sin template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> sin(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> sin(const complex<_Tp>& __x) { complex<_Tp> __z = std::sinh(complex<_Tp>(-__x.imag(), __x.real())); return complex<_Tp>(__z.imag(), -__z.real()); } @@ -1313,14 +1325,14 @@ _LIBCPP_HIDE_FROM_ABI complex<_Tp> sin(const complex<_Tp>& __x) { // cos template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> cos(const complex<_Tp>& __x) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI complex<_Tp> cos(const complex<_Tp>& __x) { return std::cosh(complex<_Tp>(-__x.imag(), __x.real())); } // tan template <class _Tp> -_LIBCPP_HIDE_FROM_ABI complex<_Tp> tan(const complex<_Tp>& __x) { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI complex<_Tp> tan(const complex<_Tp>& __x) { complex<_Tp> __z = std::tanh(complex<_Tp>(-__x.imag(), __x.real())); return complex<_Tp>(__z.imag(), -__z.real()); } @@ -1398,7 +1410,7 @@ struct tuple_element<_Ip, complex<_Tp>> { }; template <size_t _Ip, class _Xp> -_LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>& __z) noexcept { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>& __z) noexcept { static_assert(_Ip < 2, "Index value is out of range."); if constexpr (_Ip == 0) { return __z.__re_; @@ -1408,7 +1420,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Xp& get(complex<_Xp>& __z) noexcept { } template <size_t _Ip, class _Xp> -_LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&& __z) noexcept { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&& __z) noexcept { static_assert(_Ip < 2, "Index value is out of range."); if constexpr (_Ip == 0) { return std::move(__z.__re_); @@ -1418,7 +1430,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Xp&& get(complex<_Xp>&& __z) noexcept { } template <size_t _Ip, class _Xp> -_LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>& __z) noexcept { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>& __z) noexcept { static_assert(_Ip < 2, "Index value is out of range."); if constexpr (_Ip == 0) { return __z.__re_; @@ -1428,7 +1440,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr const _Xp& get(const complex<_Xp>& __z) noexcept } template <size_t _Ip, class _Xp> -_LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&& __z) noexcept { +[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr const _Xp&& get(const complex<_Xp>&& __z) noexcept { static_assert(_Ip < 2, "Index value is out of range."); if constexpr (_Ip == 0) { return std::move(__z.__re_); diff --git a/lib/libcxx/include/complex.h b/lib/libcxx/include/complex.h @@ -18,19 +18,19 @@ */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/complex.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# ifdef __cplusplus -# include <complex> -# elif __has_include_next(<complex.h>) -# include_next <complex.h> -# endif -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#ifdef __cplusplus +# include <complex> +#elif __has_include_next(<complex.h>) +# include_next <complex.h> +#endif #endif // _LIBCPP_COMPLEX_H diff --git a/lib/libcxx/include/condition_variable b/lib/libcxx/include/condition_variable @@ -206,14 +206,14 @@ public: # if _LIBCPP_STD_VER >= 20 template <class _Lock, class _Predicate> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool wait(_Lock& __lock, stop_token __stoken, _Predicate __pred); + _LIBCPP_HIDE_FROM_ABI bool wait(_Lock& __lock, stop_token __stoken, _Predicate __pred); template <class _Lock, class _Clock, class _Duration, class _Predicate> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool wait_until( + _LIBCPP_HIDE_FROM_ABI bool wait_until( _Lock& __lock, stop_token __stoken, const chrono::time_point<_Clock, _Duration>& __abs_time, _Predicate __pred); template <class _Lock, class _Rep, class _Period, class _Predicate> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool + _LIBCPP_HIDE_FROM_ABI bool wait_for(_Lock& __lock, stop_token __stoken, const chrono::duration<_Rep, _Period>& __rel_time, _Predicate __pred); # endif // _LIBCPP_STD_VER >= 20 diff --git a/lib/libcxx/include/cstdalign b/lib/libcxx/include/cstdalign @@ -43,17 +43,10 @@ Macros: # undef __alignof_is_defined # define __alignof_is_defined 1 -# if _LIBCPP_STD_VER >= 20 - -using __standard_header_cstdalign _LIBCPP_DEPRECATED_("removed in C++20.") _LIBCPP_NODEBUG = void; -using __use_standard_header_cstdalign _LIBCPP_NODEBUG = __standard_header_cstdalign; - -# elif _LIBCPP_STD_VER >= 17 - -using __standard_header_cstdalign _LIBCPP_DEPRECATED _LIBCPP_NODEBUG = void; -using __use_standard_header_cstdalign _LIBCPP_NODEBUG = __standard_header_cstdalign; - +# if _LIBCPP_STD_VER >= 17 && !__building_module(std) && _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS +# warning <cstdalign> is deprecated in C++17 and removed in C++20. # endif + #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_CSTDALIGN diff --git a/lib/libcxx/include/cstdbool b/lib/libcxx/include/cstdbool @@ -31,17 +31,10 @@ Macros: # undef __bool_true_false_are_defined # define __bool_true_false_are_defined 1 -# if _LIBCPP_STD_VER >= 20 - -using __standard_header_cstdbool _LIBCPP_DEPRECATED_("removed in C++20.") _LIBCPP_NODEBUG = void; -using __use_standard_header_cstdbool _LIBCPP_NODEBUG = __standard_header_cstdbool; - -# elif _LIBCPP_STD_VER >= 17 - -using __standard_header_cstdbool _LIBCPP_DEPRECATED _LIBCPP_NODEBUG = void; -using __use_standard_header_cstdbool _LIBCPP_NODEBUG = __standard_header_cstdbool; - +# if _LIBCPP_STD_VER >= 17 && !__building_module(std) && _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS +# warning <cstdbool> is deprecated in C++17 and removed in C++20. # endif + #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_CSTDBOOL diff --git a/lib/libcxx/include/ctgmath b/lib/libcxx/include/ctgmath @@ -28,17 +28,8 @@ # pragma GCC system_header # endif -# if _LIBCPP_STD_VER >= 20 - -using __standard_header_ctgmath - _LIBCPP_DEPRECATED_("removed in C++20. Include <cmath> and <complex> instead.") _LIBCPP_NODEBUG = void; -using __use_standard_header_ctgmath _LIBCPP_NODEBUG = __standard_header_ctgmath; - -# elif _LIBCPP_STD_VER >= 17 - -using __standard_header_ctgmath _LIBCPP_DEPRECATED_("Include <cmath> and <complex> instead.") _LIBCPP_NODEBUG = void; -using __use_standard_header_ctgmath _LIBCPP_NODEBUG = __standard_header_ctgmath; - +# if _LIBCPP_STD_VER >= 17 && !__building_module(std) && _LIBCPP_DIAGNOSE_DEPRECATED_HEADERS +# warning <ctgmath> is deprecated in C++17 and removed in C++20. Include <cmath> and <complex> instead. # endif #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) diff --git a/lib/libcxx/include/ctype.h b/lib/libcxx/include/ctype.h @@ -30,36 +30,36 @@ int toupper(int c); */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/ctype.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# if __has_include_next(<ctype.h>) -# include_next <ctype.h> -# endif +#if __has_include_next(<ctype.h>) +# include_next <ctype.h> +#endif -# ifdef __cplusplus +#ifdef __cplusplus -# undef isalnum -# undef isalpha -# undef isblank -# undef iscntrl -# undef isdigit -# undef isgraph -# undef islower -# undef isprint -# undef ispunct -# undef isspace -# undef isupper -# undef isxdigit -# undef tolower -# undef toupper +# undef isalnum +# undef isalpha +# undef isblank +# undef iscntrl +# undef isdigit +# undef isgraph +# undef islower +# undef isprint +# undef ispunct +# undef isspace +# undef isupper +# undef isxdigit +# undef tolower +# undef toupper -# endif -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif #endif // _LIBCPP_CTYPE_H diff --git a/lib/libcxx/include/cwchar b/lib/libcxx/include/cwchar @@ -231,8 +231,8 @@ __constexpr_wmemcmp(const wchar_t* __lhs, const wchar_t* __rhs, size_t __count) template <class _Tp, class _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __constexpr_wmemchr(_Tp* __str, _Up __value, size_t __count) { - static_assert(sizeof(_Tp) == sizeof(wchar_t)&& _LIBCPP_ALIGNOF(_Tp) >= _LIBCPP_ALIGNOF(wchar_t) && - __libcpp_is_trivially_equality_comparable<_Tp, _Tp>::value, + static_assert(sizeof(_Tp) == sizeof(wchar_t) && _LIBCPP_ALIGNOF(_Tp) >= _LIBCPP_ALIGNOF(wchar_t) && + __is_trivially_equality_comparable_v<_Tp, _Tp>, "Calling wmemchr on non-trivially equality comparable types is unsafe."); # if __has_builtin(__builtin_wmemchr) diff --git a/lib/libcxx/include/deque b/lib/libcxx/include/deque @@ -191,9 +191,9 @@ template <class T, class Allocator, class Predicate> # include <__algorithm/min.h> # include <__algorithm/move.h> # include <__algorithm/move_backward.h> +# include <__algorithm/ranges_copy_n.h> # include <__algorithm/remove.h> # include <__algorithm/remove_if.h> -# include <__algorithm/unwrap_iter.h> # include <__assert> # include <__config> # include <__debug_utils/sanitizers.h> @@ -220,21 +220,19 @@ template <class T, class Allocator, class Predicate> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> -# include <__ranges/size.h> # include <__split_buffer> # include <__type_traits/conditional.h> # include <__type_traits/container_traits.h> -# include <__type_traits/disjunction.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_allocator.h> # include <__type_traits/is_convertible.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> # include <__type_traits/is_trivially_relocatable.h> # include <__type_traits/type_identity.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/move.h> # include <__utility/pair.h> @@ -461,9 +459,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_; } @@ -488,6 +485,9 @@ const _DiffType __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, template <class _Tp, class _Allocator /*= allocator<_Tp>*/> class deque { + template <class _Up, class _Alloc> + using __split_buffer _LIBCPP_NODEBUG = std::__split_buffer<_Up, _Alloc, __split_buffer_pointer_layout>; + public: // types: @@ -531,10 +531,6 @@ public: __libcpp_is_trivially_relocatable<__map>::value && __libcpp_is_trivially_relocatable<allocator_type>::value, deque, void>; - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<__map> && __container_allocator_is_replaceable<__alloc_traits>::value, - deque, - void>; static_assert(is_nothrow_default_constructible<allocator_type>::value == is_nothrow_default_constructible<__pointer_allocator>::value, @@ -635,7 +631,7 @@ public: # endif _LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v); - template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0> _LIBCPP_HIDE_FROM_ABI deque(size_type __n, const value_type& __v, const allocator_type& __a) : __map_(__pointer_allocator(__a)), __start_(0), __size_(0), __alloc_(__a) { __annotate_new(0); @@ -703,8 +699,16 @@ public: __assign_with_size_random_access(ranges::begin(__range), __n); } else if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { - auto __n = static_cast<size_type>(ranges::distance(__range)); - __assign_with_size(ranges::begin(__range), __n); + auto __n = ranges::distance(__range); + auto __first = ranges::begin(__range); + + auto __result = std::ranges::copy_n(std::move(__first), std::min<size_t>(__n, size()), begin()); + + if (static_cast<size_type>(__n) > size()) { + __append_with_size(std::move(__result.in), __n - size()); + } else { + __erase_to_end(__result.out); + } } else { __assign_with_sentinel(ranges::begin(__range), ranges::end(__range)); @@ -720,45 +724,53 @@ public: // iterators: - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { __map_pointer __mp = __map_.begin() + __start_ / __block_size; return iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { __map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __start_ / __block_size); return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __start_ % __block_size); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { size_type __p = size() + __start_; __map_pointer __mp = __map_.begin() + __p / __block_size; return iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { size_type __p = size() + __start_; __map_const_pointer __mp = static_cast<__map_const_pointer>(__map_.begin() + __p / __block_size); return const_iterator(__mp, __map_.empty() ? 0 : *__mp + __p % __block_size); } - _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()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return const_reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } // capacity: - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size(); } _LIBCPP_HIDE_FROM_ABI size_type& __size() _NOEXCEPT { return __size_; } _LIBCPP_HIDE_FROM_ABI const size_type& __size() const _NOEXCEPT { return __size_; } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return std::min<size_type>(__alloc_traits::max_size(__alloc()), numeric_limits<difference_type>::max()); } _LIBCPP_HIDE_FROM_ABI void resize(size_type __n); @@ -767,18 +779,22 @@ public: [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return size() == 0; } // element access: - _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __i) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __i) const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI reference at(size_type __i); - _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __i) const; - _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __i) _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __i) const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference at(size_type __i); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __i) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT; // 23.2.2.3 modifiers: _LIBCPP_HIDE_FROM_ABI void push_front(const value_type& __v); _LIBCPP_HIDE_FROM_ABI void push_back(const value_type& __v); + + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI iterator __emplace(const_iterator __p, _Args&&... __args); + # ifndef _LIBCPP_CXX03_LANG # if _LIBCPP_STD_VER >= 17 template <class... _Args> @@ -791,8 +807,11 @@ public: template <class... _Args> _LIBCPP_HIDE_FROM_ABI void emplace_back(_Args&&... __args); # endif + template <class... _Args> - _LIBCPP_HIDE_FROM_ABI iterator emplace(const_iterator __p, _Args&&... __args); + _LIBCPP_HIDE_FROM_ABI iterator emplace(const_iterator __p, _Args&&... __args) { + return __emplace(__p, std::forward<_Args>(__args)...); + } _LIBCPP_HIDE_FROM_ABI void push_front(value_type&& __v); _LIBCPP_HIDE_FROM_ABI void push_back(value_type&& __v); @@ -805,17 +824,21 @@ public: template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI void append_range(_Range&& __range) { - insert_range(end(), std::forward<_Range>(__range)); + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { + __append_with_size(ranges::begin(__range), ranges::distance(__range)); + } else { + __append_with_sentinel(ranges::begin(__range), ranges::end(__range)); + } } # endif - _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, value_type&& __v); + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, value_type&& __v) { return __emplace(__p, std::move(__v)); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, initializer_list<value_type> __il) { return insert(__p, __il.begin(), __il.end()); } # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, const value_type& __v); + _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, const value_type& __v) { return __emplace(__p, __v); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, size_type __n, const value_type& __v); template <class _InputIter, __enable_if_t<__has_exactly_input_iterator_category<_InputIter>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, _InputIter __f, _InputIter __l); @@ -1109,7 +1132,7 @@ public: // This function tests deque object annotations. if (empty()) { for (__map_const_iterator __it = __map_.begin(); __it != __map_.end(); ++__it) { - if (!__sanitizer_verify_double_ended_contiguous_container( + if (!::__sanitizer_verify_double_ended_contiguous_container( std::__to_address(*__it), std::__to_address(*__it), std::__to_address(*__it), @@ -1141,7 +1164,7 @@ public: // Is the block before or after deque blocks that contain elements? if (__it < __first_mp || __it > __last_mp) { - if (!__sanitizer_verify_double_ended_contiguous_container( + if (!::__sanitizer_verify_double_ended_contiguous_container( std::__to_address(*__it), std::__to_address(*__it), std::__to_address(*__it), @@ -1151,7 +1174,7 @@ public: const void* __containers_buffer_beg = (__it == __first_mp) ? __p_beg : (const void*)std::__to_address(*__it); const void* __containers_buffer_end = (__it == __last_mp) ? __p_end : (const void*)std::__to_address(*__it + __block_size); - if (!__sanitizer_verify_double_ended_contiguous_container( + if (!::__sanitizer_verify_double_ended_contiguous_container( std::__to_address(*__it), __containers_buffer_beg, __containers_buffer_end, @@ -1191,7 +1214,7 @@ private: template <class _RandomAccessIterator> _LIBCPP_HIDE_FROM_ABI void __assign_with_size_random_access(_RandomAccessIterator __f, difference_type __n); - template <class _Iterator> + template <class _AlgPolicy, class _Iterator> _LIBCPP_HIDE_FROM_ABI void __assign_with_size(_Iterator __f, difference_type __n); template <class _Iterator, class _Sentinel> @@ -1239,8 +1262,8 @@ private: clear(); shrink_to_fit(); } - __alloc() = __c.__alloc(); - __map_.__alloc_ = __c.__map_.__alloc_; + __alloc() = __c.__alloc(); + __map_.__get_allocator() = __c.__map_.__get_allocator(); } _LIBCPP_HIDE_FROM_ABI void __copy_assign_alloc(const deque&, false_type) {} @@ -1256,22 +1279,22 @@ _LIBCPP_CONSTEXPR const typename allocator_traits<_Alloc>::difference_type deque # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Alloc = allocator<__iter_value_type<_InputIterator>>, + class _Alloc = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -deque(_InputIterator, _InputIterator) -> deque<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +deque(_InputIterator, _InputIterator) -> deque<__iterator_value_type<_InputIterator>, _Alloc>; template <class _InputIterator, class _Alloc, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -deque(_InputIterator, _InputIterator, _Alloc) -> deque<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +deque(_InputIterator, _InputIterator, _Alloc) -> deque<__iterator_value_type<_InputIterator>, _Alloc>; # endif # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Alloc = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Alloc>::value> > + class = enable_if_t<__is_allocator_v<_Alloc>>> deque(from_range_t, _Range&&, _Alloc = _Alloc()) -> deque<ranges::range_value_t<_Range>, _Alloc>; # endif @@ -1319,7 +1342,7 @@ deque<_Tp, _Allocator>::deque(const deque& __c) : __map_(__pointer_allocator(__alloc_traits::select_on_container_copy_construction(__c.__alloc()))), __start_(0), __size_(0), - __alloc_(__map_.__alloc_) { + __alloc_(__map_.__get_allocator()) { __annotate_new(0); __append(__c.begin(), __c.end()); } @@ -1452,24 +1475,6 @@ deque<_Tp, _Allocator>::__assign_with_size_random_access(_RandomAccessIterator _ } template <class _Tp, class _Allocator> -template <class _Iterator> -_LIBCPP_HIDE_FROM_ABI void deque<_Tp, _Allocator>::__assign_with_size(_Iterator __f, difference_type __n) { - if (static_cast<size_type>(__n) > size()) { - auto __added_size = __n - size(); - - auto __i = begin(); - for (auto __count = size(); __count != 0; --__count) { - *__i++ = *__f++; - } - - __append_with_size(__f, __added_size); - - } else { - __erase_to_end(std::copy_n(__f, __n, begin())); - } -} - -template <class _Tp, class _Allocator> void deque<_Tp, _Allocator>::assign(size_type __n, const value_type& __v) { if (__n > size()) { std::fill_n(begin(), size(), __v); @@ -1661,56 +1666,11 @@ deque<_Tp, _Allocator>::emplace_front(_Args&&... __args) { return *begin(); # endif } - -template <class _Tp, class _Allocator> -typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_iterator __p, value_type&& __v) { - size_type __pos = __p - begin(); - size_type __to_end = size() - __pos; - allocator_type& __a = __alloc(); - if (__pos < __to_end) { // insert by shifting things backward - if (__front_spare() == 0) - __add_front_capacity(); - // __front_spare() >= 1 - __annotate_increase_front(1); - if (__pos == 0) { - __alloc_traits::construct(__a, std::addressof(*--begin()), std::move(__v)); - --__start_; - ++__size(); - } else { - iterator __b = begin(); - iterator __bm1 = std::prev(__b); - __alloc_traits::construct(__a, std::addressof(*__bm1), std::move(*__b)); - --__start_; - ++__size(); - if (__pos > 1) - __b = std::move(std::next(__b), __b + __pos, __b); - *__b = std::move(__v); - } - } else { // insert by shifting things forward - if (__back_spare() == 0) - __add_back_capacity(); - // __back_capacity >= 1 - __annotate_increase_back(1); - size_type __de = size() - __pos; - if (__de == 0) { - __alloc_traits::construct(__a, std::addressof(*end()), std::move(__v)); - ++__size(); - } else { - iterator __e = end(); - iterator __em1 = std::prev(__e); - __alloc_traits::construct(__a, std::addressof(*__e), std::move(*__em1)); - ++__size(); - if (__de > 1) - __e = std::move_backward(__e - __de, __em1, __e); - *--__e = std::move(__v); - } - } - return begin() + __pos; -} +# endif // _LIBCPP_CXX03_LANG template <class _Tp, class _Allocator> template <class... _Args> -typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::emplace(const_iterator __p, _Args&&... __args) { +typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::__emplace(const_iterator __p, _Args&&... __args) { size_type __pos = __p - begin(); size_type __to_end = size() - __pos; allocator_type& __a = __alloc(); @@ -1757,60 +1717,6 @@ typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::emplace(const_ return begin() + __pos; } -# endif // _LIBCPP_CXX03_LANG - -template <class _Tp, class _Allocator> -typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_iterator __p, const value_type& __v) { - size_type __pos = __p - begin(); - size_type __to_end = size() - __pos; - allocator_type& __a = __alloc(); - if (__pos < __to_end) { // insert by shifting things backward - if (__front_spare() == 0) - __add_front_capacity(); - // __front_spare() >= 1 - __annotate_increase_front(1); - if (__pos == 0) { - __alloc_traits::construct(__a, std::addressof(*--begin()), __v); - --__start_; - ++__size(); - } else { - const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v); - iterator __b = begin(); - iterator __bm1 = std::prev(__b); - if (__vt == pointer_traits<const_pointer>::pointer_to(*__b)) - __vt = pointer_traits<const_pointer>::pointer_to(*__bm1); - __alloc_traits::construct(__a, std::addressof(*__bm1), std::move(*__b)); - --__start_; - ++__size(); - if (__pos > 1) - __b = __move_and_check(std::next(__b), __b + __pos, __b, __vt); - *__b = *__vt; - } - } else { // insert by shifting things forward - if (__back_spare() == 0) - __add_back_capacity(); - // __back_capacity >= 1 - __annotate_increase_back(1); - size_type __de = size() - __pos; - if (__de == 0) { - __alloc_traits::construct(__a, std::addressof(*end()), __v); - ++__size(); - } else { - const_pointer __vt = pointer_traits<const_pointer>::pointer_to(__v); - iterator __e = end(); - iterator __em1 = std::prev(__e); - if (__vt == pointer_traits<const_pointer>::pointer_to(*__em1)) - __vt = pointer_traits<const_pointer>::pointer_to(*__e); - __alloc_traits::construct(__a, std::addressof(*__e), std::move(*__em1)); - ++__size(); - if (__de > 1) - __e = __move_backward_and_check(__e - __de, __em1, __e, __vt); - *--__e = *__vt; - } - } - return begin() + __pos; -} - template <class _Tp, class _Allocator> typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_iterator __p, size_type __n, const value_type& __v) { @@ -1874,9 +1780,9 @@ template <class _Tp, class _Allocator> template <class _Iterator, class _Sentinel> _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __p, _Iterator __f, _Sentinel __l) { - __split_buffer<value_type, allocator_type&> __buf(__alloc()); + __split_buffer<value_type, allocator_type> __buf(__alloc()); __buf.__construct_at_end_with_sentinel(std::move(__f), std::move(__l)); - typedef typename __split_buffer<value_type, allocator_type&>::iterator __bi; + typedef typename __split_buffer<value_type, allocator_type>::iterator __bi; return insert(__p, move_iterator<__bi>(__buf.begin()), move_iterator<__bi>(__buf.end())); } @@ -1891,9 +1797,9 @@ template <class _Tp, class _Allocator> template <class _Iterator> _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::__insert_with_size(const_iterator __p, _Iterator __f, size_type __n) { - __split_buffer<value_type, allocator_type&> __buf(__n, 0, __alloc()); - __buf.__construct_at_end_with_size(__f, __n); - typedef typename __split_buffer<value_type, allocator_type&>::iterator __fwd; + __split_buffer<value_type, allocator_type> __buf(__n, 0, __alloc()); + __buf.__construct_at_end_with_size(std::move(__f), __n); + typedef typename __split_buffer<value_type, allocator_type>::iterator __fwd; return insert(__p, move_iterator<__fwd>(__buf.begin()), move_iterator<__fwd>(__buf.end())); } @@ -2071,8 +1977,8 @@ void deque<_Tp, _Allocator>::__add_front_capacity() { } // Else need to allocate 1 buffer, *and* we need to reallocate __map_. else { - __split_buffer<pointer, __pointer_allocator&> __buf( - std::max<size_type>(2 * __map_.capacity(), 1), 0, __map_.__alloc_); + __split_buffer<pointer, __pointer_allocator> __buf( + std::max<size_type>(2 * __map_.capacity(), 1), 0, __map_.__get_allocator()); typedef __allocator_destructor<_Allocator> _Dp; unique_ptr<pointer, _Dp> __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size)); @@ -2081,10 +1987,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() { for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i) __buf.emplace_back(*__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ = __map_.size() == 1 ? __block_size / 2 : __start_ + __block_size; } __annotate_whole_block(0, __asan_poison); @@ -2134,34 +2037,26 @@ void deque<_Tp, _Allocator>::__add_front_capacity(size_type __n) { // Else need to allocate __nb buffers, *and* we need to reallocate __map_. else { size_type __ds = (__nb + __back_capacity) * __block_size - __map_.empty(); - __split_buffer<pointer, __pointer_allocator&> __buf( - std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__alloc_); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (; __nb > 0; --__nb) { - __buf.emplace_back(__alloc_traits::allocate(__a, __block_size)); - // ASan: this is empty container, we have to poison whole block - __annotate_poison_block(std::__to_address(__buf.back()), std::__to_address(__buf.back() + __block_size)); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + __split_buffer<pointer, __pointer_allocator> __buf( + std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()), 0, __map_.__get_allocator()); + auto __guard = std::__make_exception_guard([&] { __annotate_delete(); for (__map_pointer __i = __buf.begin(); __i != __buf.end(); ++__i) __alloc_traits::deallocate(__a, *__i, __block_size); - throw; + }); + for (; __nb > 0; --__nb) { + __buf.emplace_back(__alloc_traits::allocate(__a, __block_size)); + // ASan: this is empty container, we have to poison whole block + __annotate_poison_block(std::__to_address(__buf.back()), std::__to_address(__buf.back() + __block_size)); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); for (; __back_capacity > 0; --__back_capacity) { __buf.emplace_back(__map_.back()); __map_.pop_back(); } for (__map_pointer __i = __map_.begin(); __i != __map_.end(); ++__i) __buf.emplace_back(*__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ += __ds; } } @@ -2194,8 +2089,8 @@ void deque<_Tp, _Allocator>::__add_back_capacity() { } // Else need to allocate 1 buffer, *and* we need to reallocate __map_. else { - __split_buffer<pointer, __pointer_allocator&> __buf( - std::max<size_type>(2 * __map_.capacity(), 1), __map_.size(), __map_.__alloc_); + __split_buffer<pointer, __pointer_allocator> __buf( + std::max<size_type>(2 * __map_.capacity(), 1), __map_.size(), __map_.__get_allocator()); typedef __allocator_destructor<_Allocator> _Dp; unique_ptr<pointer, _Dp> __hold(__alloc_traits::allocate(__a, __block_size), _Dp(__a, __block_size)); @@ -2204,10 +2099,7 @@ void deque<_Tp, _Allocator>::__add_back_capacity() { for (__map_pointer __i = __map_.end(); __i != __map_.begin();) __buf.emplace_front(*--__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __annotate_whole_block(__map_.size() - 1, __asan_poison); } } @@ -2257,36 +2149,28 @@ void deque<_Tp, _Allocator>::__add_back_capacity(size_type __n) { // Else need to allocate __nb buffers, *and* we need to reallocate __map_. else { size_type __ds = __front_capacity * __block_size; - __split_buffer<pointer, __pointer_allocator&> __buf( + __split_buffer<pointer, __pointer_allocator> __buf( std::max<size_type>(2 * __map_.capacity(), __nb + __map_.size()), __map_.size() - __front_capacity, - __map_.__alloc_); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (; __nb > 0; --__nb) { - __buf.emplace_back(__alloc_traits::allocate(__a, __block_size)); - // ASan: this is an empty container, we have to poison the whole block - __annotate_poison_block(std::__to_address(__buf.back()), std::__to_address(__buf.back() + __block_size)); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + __map_.__get_allocator()); + auto __guard = std::__make_exception_guard([&] { __annotate_delete(); for (__map_pointer __i = __buf.begin(); __i != __buf.end(); ++__i) __alloc_traits::deallocate(__a, *__i, __block_size); - throw; + }); + for (; __nb > 0; --__nb) { + __buf.emplace_back(__alloc_traits::allocate(__a, __block_size)); + // ASan: this is an empty container, we have to poison the whole block + __annotate_poison_block(std::__to_address(__buf.back()), std::__to_address(__buf.back() + __block_size)); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); for (; __front_capacity > 0; --__front_capacity) { __buf.emplace_back(__map_.front()); __map_.pop_front(); } for (__map_pointer __i = __map_.end(); __i != __map_.begin();) __buf.emplace_front(*--__i); - std::swap(__map_.__first_, __buf.__first_); - std::swap(__map_.__begin_, __buf.__begin_); - std::swap(__map_.__end_, __buf.__end_); - std::swap(__map_.__cap_, __buf.__cap_); + __map_.__swap_without_allocator(__buf); __start_ -= __ds; } } diff --git a/lib/libcxx/include/errno.h b/lib/libcxx/include/errno.h @@ -23,381 +23,381 @@ Macros: */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/errno.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# if __has_include_next(<errno.h>) -# include_next <errno.h> -# endif +#if __has_include_next(<errno.h>) +# include_next <errno.h> +#endif -# ifdef __cplusplus +#ifdef __cplusplus -# if !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) +# if !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) -# ifdef ELAST +# ifdef ELAST static const int __elast1 = ELAST + 1; static const int __elast2 = ELAST + 2; -# else +# else static const int __elast1 = 104; static const int __elast2 = 105; -# endif +# endif -# ifdef ENOTRECOVERABLE +# ifdef ENOTRECOVERABLE -# define EOWNERDEAD __elast1 +# define EOWNERDEAD __elast1 -# ifdef ELAST -# undef ELAST -# define ELAST EOWNERDEAD -# endif +# ifdef ELAST +# undef ELAST +# define ELAST EOWNERDEAD +# endif -# elif defined(EOWNERDEAD) +# elif defined(EOWNERDEAD) -# define ENOTRECOVERABLE __elast1 -# ifdef ELAST -# undef ELAST -# define ELAST ENOTRECOVERABLE -# endif +# define ENOTRECOVERABLE __elast1 +# ifdef ELAST +# undef ELAST +# define ELAST ENOTRECOVERABLE +# endif -# else // defined(EOWNERDEAD) +# else // defined(EOWNERDEAD) -# define EOWNERDEAD __elast1 -# define ENOTRECOVERABLE __elast2 -# ifdef ELAST -# undef ELAST -# define ELAST ENOTRECOVERABLE -# endif +# define EOWNERDEAD __elast1 +# define ENOTRECOVERABLE __elast2 +# ifdef ELAST +# undef ELAST +# define ELAST ENOTRECOVERABLE +# endif -# endif // defined(EOWNERDEAD) +# endif // defined(EOWNERDEAD) -# endif // !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) +# endif // !defined(EOWNERDEAD) || !defined(ENOTRECOVERABLE) // supply errno values likely to be missing, particularly on Windows -# ifndef EAFNOSUPPORT -# define EAFNOSUPPORT 9901 -# endif +# ifndef EAFNOSUPPORT +# define EAFNOSUPPORT 9901 +# endif -# ifndef EADDRINUSE -# define EADDRINUSE 9902 -# endif +# ifndef EADDRINUSE +# define EADDRINUSE 9902 +# endif -# ifndef EADDRNOTAVAIL -# define EADDRNOTAVAIL 9903 -# endif +# ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL 9903 +# endif -# ifndef EISCONN -# define EISCONN 9904 -# endif +# ifndef EISCONN +# define EISCONN 9904 +# endif -# ifndef EBADMSG -# define EBADMSG 9905 -# endif +# ifndef EBADMSG +# define EBADMSG 9905 +# endif -# ifndef ECONNABORTED -# define ECONNABORTED 9906 -# endif +# ifndef ECONNABORTED +# define ECONNABORTED 9906 +# endif -# ifndef EALREADY -# define EALREADY 9907 -# endif +# ifndef EALREADY +# define EALREADY 9907 +# endif -# ifndef ECONNREFUSED -# define ECONNREFUSED 9908 -# endif +# ifndef ECONNREFUSED +# define ECONNREFUSED 9908 +# endif -# ifndef ECONNRESET -# define ECONNRESET 9909 -# endif +# ifndef ECONNRESET +# define ECONNRESET 9909 +# endif -# ifndef EDESTADDRREQ -# define EDESTADDRREQ 9910 -# endif +# ifndef EDESTADDRREQ +# define EDESTADDRREQ 9910 +# endif -# ifndef EHOSTUNREACH -# define EHOSTUNREACH 9911 -# endif +# ifndef EHOSTUNREACH +# define EHOSTUNREACH 9911 +# endif -# ifndef EIDRM -# define EIDRM 9912 -# endif +# ifndef EIDRM +# define EIDRM 9912 +# endif -# ifndef EMSGSIZE -# define EMSGSIZE 9913 -# endif +# ifndef EMSGSIZE +# define EMSGSIZE 9913 +# endif -# ifndef ENETDOWN -# define ENETDOWN 9914 -# endif +# ifndef ENETDOWN +# define ENETDOWN 9914 +# endif -# ifndef ENETRESET -# define ENETRESET 9915 -# endif +# ifndef ENETRESET +# define ENETRESET 9915 +# endif -# ifndef ENETUNREACH -# define ENETUNREACH 9916 -# endif +# ifndef ENETUNREACH +# define ENETUNREACH 9916 +# endif -# ifndef ENOBUFS -# define ENOBUFS 9917 -# endif +# ifndef ENOBUFS +# define ENOBUFS 9917 +# endif -# ifndef ENOLINK -# define ENOLINK 9918 -# endif +# ifndef ENOLINK +# define ENOLINK 9918 +# endif -# ifndef ENODATA -# define ENODATA 9919 -# endif +# ifndef ENODATA +# define ENODATA 9919 +# endif -# ifndef ENOMSG -# define ENOMSG 9920 -# endif +# ifndef ENOMSG +# define ENOMSG 9920 +# endif -# ifndef ENOPROTOOPT -# define ENOPROTOOPT 9921 -# endif +# ifndef ENOPROTOOPT +# define ENOPROTOOPT 9921 +# endif -# ifndef ENOSR -# define ENOSR 9922 -# endif +# ifndef ENOSR +# define ENOSR 9922 +# endif -# ifndef ENOTSOCK -# define ENOTSOCK 9923 -# endif +# ifndef ENOTSOCK +# define ENOTSOCK 9923 +# endif -# ifndef ENOSTR -# define ENOSTR 9924 -# endif +# ifndef ENOSTR +# define ENOSTR 9924 +# endif -# ifndef ENOTCONN -# define ENOTCONN 9925 -# endif +# ifndef ENOTCONN +# define ENOTCONN 9925 +# endif -# ifndef ENOTSUP -# define ENOTSUP 9926 -# endif +# ifndef ENOTSUP +# define ENOTSUP 9926 +# endif -# ifndef ECANCELED -# define ECANCELED 9927 -# endif +# ifndef ECANCELED +# define ECANCELED 9927 +# endif -# ifndef EINPROGRESS -# define EINPROGRESS 9928 -# endif +# ifndef EINPROGRESS +# define EINPROGRESS 9928 +# endif -# ifndef EOPNOTSUPP -# define EOPNOTSUPP 9929 -# endif +# ifndef EOPNOTSUPP +# define EOPNOTSUPP 9929 +# endif -# ifndef EWOULDBLOCK -# define EWOULDBLOCK 9930 -# endif +# ifndef EWOULDBLOCK +# define EWOULDBLOCK 9930 +# endif -# ifndef EOWNERDEAD -# define EOWNERDEAD 9931 -# endif +# ifndef EOWNERDEAD +# define EOWNERDEAD 9931 +# endif -# ifndef EPROTO -# define EPROTO 9932 -# endif +# ifndef EPROTO +# define EPROTO 9932 +# endif -# ifndef EPROTONOSUPPORT -# define EPROTONOSUPPORT 9933 -# endif +# ifndef EPROTONOSUPPORT +# define EPROTONOSUPPORT 9933 +# endif -# ifndef ENOTRECOVERABLE -# define ENOTRECOVERABLE 9934 -# endif +# ifndef ENOTRECOVERABLE +# define ENOTRECOVERABLE 9934 +# endif -# ifndef ETIME -# define ETIME 9935 -# endif +# ifndef ETIME +# define ETIME 9935 +# endif -# ifndef ETXTBSY -# define ETXTBSY 9936 -# endif +# ifndef ETXTBSY +# define ETXTBSY 9936 +# endif -# ifndef ETIMEDOUT -# define ETIMEDOUT 9938 -# endif +# ifndef ETIMEDOUT +# define ETIMEDOUT 9938 +# endif -# ifndef ELOOP -# define ELOOP 9939 -# endif +# ifndef ELOOP +# define ELOOP 9939 +# endif -# ifndef EOVERFLOW -# define EOVERFLOW 9940 -# endif +# ifndef EOVERFLOW +# define EOVERFLOW 9940 +# endif -# ifndef EPROTOTYPE -# define EPROTOTYPE 9941 -# endif +# ifndef EPROTOTYPE +# define EPROTOTYPE 9941 +# endif -# ifndef ENOSYS -# define ENOSYS 9942 -# endif +# ifndef ENOSYS +# define ENOSYS 9942 +# endif -# ifndef EINVAL -# define EINVAL 9943 -# endif +# ifndef EINVAL +# define EINVAL 9943 +# endif -# ifndef ERANGE -# define ERANGE 9944 -# endif +# ifndef ERANGE +# define ERANGE 9944 +# endif -# ifndef EILSEQ -# define EILSEQ 9945 -# endif +# ifndef EILSEQ +# define EILSEQ 9945 +# endif // Windows Mobile doesn't appear to define these: -# ifndef E2BIG -# define E2BIG 9946 -# endif +# ifndef E2BIG +# define E2BIG 9946 +# endif -# ifndef EDOM -# define EDOM 9947 -# endif +# ifndef EDOM +# define EDOM 9947 +# endif -# ifndef EFAULT -# define EFAULT 9948 -# endif +# ifndef EFAULT +# define EFAULT 9948 +# endif -# ifndef EBADF -# define EBADF 9949 -# endif +# ifndef EBADF +# define EBADF 9949 +# endif -# ifndef EPIPE -# define EPIPE 9950 -# endif +# ifndef EPIPE +# define EPIPE 9950 +# endif -# ifndef EXDEV -# define EXDEV 9951 -# endif +# ifndef EXDEV +# define EXDEV 9951 +# endif -# ifndef EBUSY -# define EBUSY 9952 -# endif +# ifndef EBUSY +# define EBUSY 9952 +# endif -# ifndef ENOTEMPTY -# define ENOTEMPTY 9953 -# endif +# ifndef ENOTEMPTY +# define ENOTEMPTY 9953 +# endif -# ifndef ENOEXEC -# define ENOEXEC 9954 -# endif +# ifndef ENOEXEC +# define ENOEXEC 9954 +# endif -# ifndef EEXIST -# define EEXIST 9955 -# endif +# ifndef EEXIST +# define EEXIST 9955 +# endif -# ifndef EFBIG -# define EFBIG 9956 -# endif +# ifndef EFBIG +# define EFBIG 9956 +# endif -# ifndef ENAMETOOLONG -# define ENAMETOOLONG 9957 -# endif +# ifndef ENAMETOOLONG +# define ENAMETOOLONG 9957 +# endif -# ifndef ENOTTY -# define ENOTTY 9958 -# endif +# ifndef ENOTTY +# define ENOTTY 9958 +# endif -# ifndef EINTR -# define EINTR 9959 -# endif +# ifndef EINTR +# define EINTR 9959 +# endif -# ifndef ESPIPE -# define ESPIPE 9960 -# endif +# ifndef ESPIPE +# define ESPIPE 9960 +# endif -# ifndef EIO -# define EIO 9961 -# endif +# ifndef EIO +# define EIO 9961 +# endif -# ifndef EISDIR -# define EISDIR 9962 -# endif +# ifndef EISDIR +# define EISDIR 9962 +# endif -# ifndef ECHILD -# define ECHILD 9963 -# endif +# ifndef ECHILD +# define ECHILD 9963 +# endif -# ifndef ENOLCK -# define ENOLCK 9964 -# endif +# ifndef ENOLCK +# define ENOLCK 9964 +# endif -# ifndef ENOSPC -# define ENOSPC 9965 -# endif +# ifndef ENOSPC +# define ENOSPC 9965 +# endif -# ifndef ENXIO -# define ENXIO 9966 -# endif +# ifndef ENXIO +# define ENXIO 9966 +# endif -# ifndef ENODEV -# define ENODEV 9967 -# endif +# ifndef ENODEV +# define ENODEV 9967 +# endif -# ifndef ENOENT -# define ENOENT 9968 -# endif +# ifndef ENOENT +# define ENOENT 9968 +# endif -# ifndef ESRCH -# define ESRCH 9969 -# endif +# ifndef ESRCH +# define ESRCH 9969 +# endif -# ifndef ENOTDIR -# define ENOTDIR 9970 -# endif +# ifndef ENOTDIR +# define ENOTDIR 9970 +# endif -# ifndef ENOMEM -# define ENOMEM 9971 -# endif +# ifndef ENOMEM +# define ENOMEM 9971 +# endif -# ifndef EPERM -# define EPERM 9972 -# endif +# ifndef EPERM +# define EPERM 9972 +# endif -# ifndef EACCES -# define EACCES 9973 -# endif +# ifndef EACCES +# define EACCES 9973 +# endif -# ifndef EROFS -# define EROFS 9974 -# endif +# ifndef EROFS +# define EROFS 9974 +# endif -# ifndef EDEADLK -# define EDEADLK 9975 -# endif +# ifndef EDEADLK +# define EDEADLK 9975 +# endif -# ifndef EAGAIN -# define EAGAIN 9976 -# endif +# ifndef EAGAIN +# define EAGAIN 9976 +# endif -# ifndef ENFILE -# define ENFILE 9977 -# endif +# ifndef ENFILE +# define ENFILE 9977 +# endif -# ifndef EMFILE -# define EMFILE 9978 -# endif +# ifndef EMFILE +# define EMFILE 9978 +# endif -# ifndef EMLINK -# define EMLINK 9979 -# endif +# ifndef EMLINK +# define EMLINK 9979 +# endif -# endif // __cplusplus -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif // __cplusplus #endif // _LIBCPP_ERRNO_H diff --git a/lib/libcxx/include/exception b/lib/libcxx/include/exception @@ -93,10 +93,13 @@ template <class E> void rethrow_if_nested(const E& e); # if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 # include <cstddef> -# include <cstdlib> # include <new> # include <type_traits> # endif + +# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23 +# include <cstdlib> +# endif #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) #endif // _LIBCPP_EXCEPTION diff --git a/lib/libcxx/include/ext/hash_map b/lib/libcxx/include/ext/hash_map @@ -206,6 +206,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc> #else # include <__config> # include <__hash_table> +# include <__memory/compressed_pair.h> # include <algorithm> # include <ext/__hash> # include <functional> @@ -224,21 +225,9 @@ _LIBCPP_WARNING("Use of the header <ext/hash_map> is deprecated. Migrate to <un namespace __gnu_cxx { -template <class _Tp, class _Hash, bool = std::is_empty<_Hash>::value && !std::__libcpp_is_final<_Hash>::value > -class __hash_map_hasher : private _Hash { -public: - _LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : _Hash() {} - _LIBCPP_HIDE_FROM_ABI __hash_map_hasher(const _Hash& __h) : _Hash(__h) {} - _LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const { return *this; } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Tp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { - return static_cast<const _Hash&>(*this)(__x); - } -}; - template <class _Tp, class _Hash> -class __hash_map_hasher<_Tp, _Hash, false> { - _Hash __hash_; +class __hash_map_hasher { + _LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_); public: _LIBCPP_HIDE_FROM_ABI __hash_map_hasher() : __hash_() {} @@ -248,30 +237,9 @@ public: _LIBCPP_HIDE_FROM_ABI size_t operator()(const typename _Tp::first_type& __x) const { return __hash_(__x); } }; -template <class _Tp, class _Pred, bool = std::is_empty<_Pred>::value && !std::__libcpp_is_final<_Pred>::value > -class __hash_map_equal : private _Pred { -public: - _LIBCPP_HIDE_FROM_ABI __hash_map_equal() : _Pred() {} - _LIBCPP_HIDE_FROM_ABI __hash_map_equal(const _Pred& __p) : _Pred(__p) {} - _LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const _Tp& __y) const { - return static_cast<const _Pred&>(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const typename _Tp::first_type& __x, const _Tp& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Tp& __x, const typename _Tp::first_type& __y) const { - return static_cast<const _Pred&>(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool - operator()(const typename _Tp::first_type& __x, const typename _Tp::first_type& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y); - } -}; - template <class _Tp, class _Pred> -class __hash_map_equal<_Tp, _Pred, false> { - _Pred __pred_; +class __hash_map_equal { + _LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_); public: _LIBCPP_HIDE_FROM_ABI __hash_map_equal() : __pred_() {} @@ -467,8 +435,6 @@ private: __table __table_; - typedef typename __table::__node_pointer __node_pointer; - typedef typename __table::__node_const_pointer __node_const_pointer; typedef typename __table::__node_traits __node_traits; typedef typename __table::__node_allocator __node_allocator; typedef typename __table::__node __node; @@ -604,10 +570,7 @@ hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_map( } template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_map(const hash_map& __u) : __table_(__u.__table_) { - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} +hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_map(const hash_map& __u) : __table_(__u.__table_) {} template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> typename hash_map<_Key, _Tp, _Hash, _Pred, _Alloc>::__node_holder @@ -693,7 +656,6 @@ private: __table __table_; - typedef typename __table::__node_traits __node_traits; typedef typename __table::__node_allocator __node_allocator; typedef typename __table::__node __node; typedef __hash_map_node_destructor<__node_allocator> _Dp; @@ -822,10 +784,7 @@ hash_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_multimap( } template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -hash_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_multimap(const hash_multimap& __u) : __table_(__u.__table_) { - __table_.__rehash_multi(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} +hash_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::hash_multimap(const hash_multimap& __u) : __table_(__u.__table_) {} template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> template <class _InputIterator> diff --git a/lib/libcxx/include/ext/hash_set b/lib/libcxx/include/ext/hash_set @@ -356,10 +356,7 @@ hash_set<_Value, _Hash, _Pred, _Alloc>::hash_set( } template <class _Value, class _Hash, class _Pred, class _Alloc> -hash_set<_Value, _Hash, _Pred, _Alloc>::hash_set(const hash_set& __u) : __table_(__u.__table_) { - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} +hash_set<_Value, _Hash, _Pred, _Alloc>::hash_set(const hash_set& __u) : __table_(__u.__table_) {} template <class _Value, class _Hash, class _Pred, class _Alloc> template <class _InputIterator> @@ -534,10 +531,7 @@ hash_multiset<_Value, _Hash, _Pred, _Alloc>::hash_multiset( } template <class _Value, class _Hash, class _Pred, class _Alloc> -hash_multiset<_Value, _Hash, _Pred, _Alloc>::hash_multiset(const hash_multiset& __u) : __table_(__u.__table_) { - __table_.__rehash_multi(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} +hash_multiset<_Value, _Hash, _Pred, _Alloc>::hash_multiset(const hash_multiset& __u) : __table_(__u.__table_) {} template <class _Value, class _Hash, class _Pred, class _Alloc> template <class _InputIterator> diff --git a/lib/libcxx/include/fenv.h b/lib/libcxx/include/fenv.h @@ -50,69 +50,69 @@ int feupdateenv(const fenv_t* envp); */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/fenv.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# if __has_include_next(<fenv.h>) -# include_next <fenv.h> -# endif +#if __has_include_next(<fenv.h>) +# include_next <fenv.h> +#endif -# ifdef __cplusplus +#ifdef __cplusplus extern "C++" { -# ifdef feclearexcept -# undef feclearexcept -# endif +# ifdef feclearexcept +# undef feclearexcept +# endif -# ifdef fegetexceptflag -# undef fegetexceptflag -# endif +# ifdef fegetexceptflag +# undef fegetexceptflag +# endif -# ifdef feraiseexcept -# undef feraiseexcept -# endif +# ifdef feraiseexcept +# undef feraiseexcept +# endif -# ifdef fesetexceptflag -# undef fesetexceptflag -# endif +# ifdef fesetexceptflag +# undef fesetexceptflag +# endif -# ifdef fetestexcept -# undef fetestexcept -# endif +# ifdef fetestexcept +# undef fetestexcept +# endif -# ifdef fegetround -# undef fegetround -# endif +# ifdef fegetround +# undef fegetround +# endif -# ifdef fesetround -# undef fesetround -# endif +# ifdef fesetround +# undef fesetround +# endif -# ifdef fegetenv -# undef fegetenv -# endif +# ifdef fegetenv +# undef fegetenv +# endif -# ifdef feholdexcept -# undef feholdexcept -# endif +# ifdef feholdexcept +# undef feholdexcept +# endif -# ifdef fesetenv -# undef fesetenv -# endif +# ifdef fesetenv +# undef fesetenv +# endif -# ifdef feupdateenv -# undef feupdateenv -# endif +# ifdef feupdateenv +# undef feupdateenv +# endif } // extern "C++" -# endif // defined(__cplusplus) -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif // defined(__cplusplus) #endif // _LIBCPP_FENV_H diff --git a/lib/libcxx/include/flat_map b/lib/libcxx/include/flat_map @@ -17,18 +17,359 @@ #include <initializer_list> // see [initializer.list.syn] namespace std { + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + // [flat.map], class template flat_map template<class Key, class T, class Compare = less<Key>, class KeyContainer = vector<Key>, class MappedContainer = vector<T>> - class flat_map; + class flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair<key_type, mapped_type>; + using key_compare = Compare; + using reference = pair<const key_type&, mapped_type&>; + using const_reference = pair<const key_type&, const mapped_type&>; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; + class value_compare { + private: + key_compare comp; // exposition only + constexpr value_compare(key_compare c) : comp(c) { } // exposition only + + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return comp(x.first, y.first); + } + }; + + struct containers { + key_container_type keys; + mapped_container_type values; + }; + + // [flat.map.cons], constructors + constexpr flat_map() : flat_map(key_compare()) { } + + constexpr flat_map(const flat_map&); + constexpr flat_map(flat_map&&); + constexpr flat_map& operator=(const flat_map&); + constexpr flat_map& operator=(flat_map&&); + + constexpr explicit flat_map(const key_compare& comp) + : c(), compare(comp) { } + + constexpr flat_map(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + constexpr flat_map(sorted_unique_t, key_container_type key_cont, + mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + template<class InputIterator> + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(first, last); } + + template<class InputIterator> + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(sorted_unique, first, last); } + + template<container-compatible-range<value_type> R> + constexpr flat_map(from_range_t, R&& rg) + : flat_map(from_range, std::forward<R>(rg), key_compare()) { } + template<container-compatible-range<value_type> R> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp) + : flat_map(comp) { insert_range(std::forward<R>(rg)); } + + constexpr flat_map(initializer_list<value_type> il, const key_compare& comp = key_compare()) + : flat_map(il.begin(), il.end(), comp) { } + + constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, + const key_compare& comp = key_compare()) + : flat_map(sorted_unique, il.begin(), il.end(), comp) { } + + // [flat.map.cons.alloc], constructors with allocators + + template<class Alloc> + constexpr explicit flat_map(const Alloc& a); + template<class Alloc> + constexpr flat_map(const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const Alloc& a); + template<class Alloc> + constexpr flat_map(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template<class Alloc> + constexpr flat_map(sorted_unique_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_map(const flat_map&, const Alloc& a); + template<class Alloc> + constexpr flat_map(flat_map&&, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_map(InputIterator first, InputIterator last, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_map(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_map(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_map(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_map(initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_map(initializer_list<value_type> il, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_map(sorted_unique_t, initializer_list<value_type> il, + const key_compare& comp, const Alloc& a); + + constexpr flat_map& operator=(initializer_list<value_type>); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // [flat.map.capacity], capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.map.access], element access + constexpr mapped_type& operator[](const key_type& x); + constexpr mapped_type& operator[](key_type&& x); + template<class K> constexpr mapped_type& operator[](K&& x); + constexpr mapped_type& at(const key_type& x); + constexpr const mapped_type& at(const key_type& x) const; + template<class K> constexpr mapped_type& at(const K& x); + template<class K> constexpr const mapped_type& at(const K& x) const; + + // [flat.map.modifiers], modifiers + template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args); + template<class... Args> + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr pair<iterator, bool> insert(const value_type& x) + { return emplace(x); } + constexpr pair<iterator, bool> insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template<class P> constexpr pair<iterator, bool> insert(P&& x); + template<class P> + constexpr iterator insert(const_iterator position, P&&); + template<class InputIterator> + constexpr void insert(InputIterator first, InputIterator last); + template<class InputIterator> + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); + template<container-compatible-range<value_type> R> + constexpr void insert_range(R&& rg); + template<container-compatible-range<value_type> R> + constexpr void insert_range(sorted_unique_t, R&& rg); + + constexpr void insert(initializer_list<value_type> il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_unique_t, initializer_list<value_type> il) + { insert(sorted_unique, il.begin(), il.end()); } + + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + template<class... Args> + constexpr pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); + template<class... Args> + constexpr pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); + template<class K, class... Args> + constexpr pair<iterator, bool> try_emplace(K&& k, Args&&... args); + template<class... Args> + constexpr iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); + template<class... Args> + constexpr iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); + template<class K, class... Args> + constexpr iterator try_emplace(const_iterator hint, K&& k, Args&&... args); + template<class M> + constexpr pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); + template<class M> + constexpr pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); + template<class K, class M> + constexpr pair<iterator, bool> insert_or_assign(K&& k, M&& obj); + template<class M> + constexpr iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); + template<class M> + constexpr iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); + template<class K, class M> + constexpr iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template<class K> constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_map& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + constexpr const key_container_type& keys() const noexcept { return c.keys; } + constexpr const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template<class K> constexpr iterator find(const K& x); + template<class K> constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template<class K> constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template<class K> constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template<class K> constexpr iterator lower_bound(const K& x); + template<class K> constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template<class K> constexpr iterator upper_bound(const K& x); + template<class K> constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair<iterator, iterator> equal_range(const key_type& x); + constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const; + template<class K> constexpr pair<iterator, iterator> equal_range(const K& x); + template<class K> + constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_map& x, const flat_map& y); + + friend constexpr synth-three-way-result<value_type> + operator<=>(const flat_map& x, const flat_map& y); + + friend constexpr void swap(flat_map& x, flat_map& y) noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + containers c; // exposition only + key_compare compare; // exposition only + + struct key-equiv { // exposition only + constexpr key-equiv(key_compare c) : comp(c) { } + constexpr bool operator()(const_reference x, const_reference y) const { + return !comp(x.first, y.first) && !comp(y.first, x.first); + } + key_compare comp; + }; + }; + + template<class KeyContainer, class MappedContainer, + class Compare = less<typename KeyContainer::value_type>> + flat_map(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, class Allocator> + flat_map(KeyContainer, MappedContainer, Allocator) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; + template<class KeyContainer, class MappedContainer, class Compare, class Allocator> + flat_map(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, + class Compare = less<typename KeyContainer::value_type>> + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, class Allocator> + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; + template<class KeyContainer, class MappedContainer, class Compare, class Allocator> + flat_map(sorted_unique_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_map<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> + flat_map(InputIterator, InputIterator, Compare = Compare()) + -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; + + template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> + flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_map<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; + + template<ranges::input_range R, class Compare = less<range-key-type<R>>, + class Allocator = allocator<byte>> + flat_map(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_map<range-key-type<R>, range-mapped-type<R>, Compare, + vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>, + vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>; + + template<ranges::input_range R, class Allocator> + flat_map(from_range_t, R&&, Allocator) + -> flat_map<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>, + vector<range-key-type<R>, alloc-rebind<Allocator, range-key-type<R>>>, + vector<range-mapped-type<R>, alloc-rebind<Allocator, range-mapped-type<R>>>>; + + template<class Key, class T, class Compare = less<Key>> + flat_map(initializer_list<pair<Key, T>>, Compare = Compare()) + -> flat_map<Key, T, Compare>; + + template<class Key, class T, class Compare = less<Key>> + flat_map(sorted_unique_t, initializer_list<pair<Key, T>>, Compare = Compare()) + -> flat_map<Key, T, Compare>; template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, - class Allocator> - struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>, - Allocator>; + class Allocator> + struct uses_allocator<flat_map<Key, T, Compare, KeyContainer, MappedContainer>, Allocator> + : bool_constant<uses_allocator_v<KeyContainer, Allocator> && + uses_allocator_v<MappedContainer, Allocator>> { }; // [flat.map.erasure], erasure for flat_map template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, @@ -36,18 +377,329 @@ namespace std { typename flat_map<Key, T, Compare, KeyContainer, MappedContainer>::size_type erase_if(flat_map<Key, T, Compare, KeyContainer, MappedContainer>& c, Predicate pred); + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multimap], class template flat_multimap template<class Key, class T, class Compare = less<Key>, class KeyContainer = vector<Key>, class MappedContainer = vector<T>> - class flat_multimap; + class flat_multimap { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = pair<key_type, mapped_type>; + using key_compare = Compare; + using reference = pair<const key_type&, mapped_type&>; + using const_reference = pair<const key_type&, const mapped_type&>; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using key_container_type = KeyContainer; + using mapped_container_type = MappedContainer; - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; + class value_compare { + private: + key_compare comp; // exposition only + constexpr value_compare(key_compare c) : comp(c) { } // exposition only + + public: + constexpr bool operator()(const_reference x, const_reference y) const { + return comp(x.first, y.first); + } + }; + + struct containers { + key_container_type keys; + mapped_container_type values; + }; + + // [flat.multimap.cons], constructors + constexpr flat_multimap() : flat_multimap(key_compare()) { } + + constexpr flat_multimap(const flat_multimap&); + constexpr flat_multimap(flat_multimap&&); + constexpr flat_multimap& operator=(const flat_multimap&); + constexpr flat_multimap& operator=(flat_multimap&&); + + constexpr explicit flat_multimap(const key_compare& comp) + : c(), compare(comp) { } + + constexpr flat_multimap(key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + constexpr flat_multimap(sorted_equivalent_t, + key_container_type key_cont, mapped_container_type mapped_cont, + const key_compare& comp = key_compare()); + + template<class InputIterator> + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template<class InputIterator> + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) { insert(sorted_equivalent, first, last); } + + template<container-compatible-range<value_type> R> + constexpr flat_multimap(from_range_t, R&& rg) + : flat_multimap(from_range, std::forward<R>(rg), key_compare()) { } + template<container-compatible-range<value_type> R> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp) + : flat_multimap(comp) { insert_range(std::forward<R>(rg)); } + + constexpr flat_multimap(initializer_list<value_type> il, + const key_compare& comp = key_compare()) + : flat_multimap(il.begin(), il.end(), comp) { } + + constexpr 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) { } + + // [flat.multimap.cons.alloc], constructors with allocators + + template<class Alloc> + constexpr explicit flat_multimap(const Alloc& a); + template<class Alloc> + constexpr flat_multimap(const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(sorted_equivalent_t, const key_container_type& key_cont, + const mapped_container_type& mapped_cont, + const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(const flat_multimap&, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(flat_multimap&&, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multimap(InputIterator first, InputIterator last, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multimap(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multimap(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_multimap(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_multimap(initializer_list<value_type> il, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il, + const Alloc& a); + template<class Alloc> + constexpr flat_multimap(sorted_equivalent_t, initializer_list<value_type> il, + const key_compare& comp, const Alloc& a); + + flat_multimap& operator=(initializer_list<value_type>); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // modifiers + template<class... Args> constexpr iterator emplace(Args&&... args); + template<class... Args> + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr iterator insert(const value_type& x) + { return emplace(x); } + constexpr iterator insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template<class P> constexpr iterator insert(P&& x); + template<class P> + constexpr iterator insert(const_iterator position, P&&); + template<class InputIterator> + constexpr void insert(InputIterator first, InputIterator last); + template<class InputIterator> + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template<container-compatible-range<value_type> R> + constexpr void insert_range(R&& rg); + template<container-compatible-range<value_type> R> + constexpr void insert_range(sorted_equivalent_t, R&& rg); + + constexpr void insert(initializer_list<value_type> il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_equivalent_t, initializer_list<value_type> il) + { insert(sorted_equivalent, il.begin(), il.end()); } + + constexpr containers extract() &&; + constexpr void replace(key_container_type&& key_cont, mapped_container_type&& mapped_cont); + + constexpr iterator erase(iterator position); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template<class K> constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_multimap&) + noexcept(is_nothrow_swappable_v<key_container_type> && + is_nothrow_swappable_v<mapped_container_type> && + is_nothrow_swappable_v<key_compare>); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + constexpr const key_container_type& keys() const noexcept { return c.keys; } + constexpr const mapped_container_type& values() const noexcept { return c.values; } + + // map operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template<class K> constexpr iterator find(const K& x); + template<class K> constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template<class K> constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template<class K> constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template<class K> constexpr iterator lower_bound(const K& x); + template<class K> constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template<class K> constexpr iterator upper_bound(const K& x); + template<class K> constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair<iterator, iterator> equal_range(const key_type& x); + constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const; + template<class K> + constexpr pair<iterator, iterator> equal_range(const K& x); + template<class K> + constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_multimap& x, const flat_multimap& y); + + friend constexpr synth-three-way-result<value_type> + operator<=>(const flat_multimap& x, const flat_multimap& y); + + friend constexpr void swap(flat_multimap& x, flat_multimap& y) + noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + containers c; // exposition only + key_compare compare; // exposition only + }; + + template<class KeyContainer, class MappedContainer, + class Compare = less<typename KeyContainer::value_type>> + flat_multimap(KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, class Allocator> + flat_multimap(KeyContainer, MappedContainer, Allocator) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; + template<class KeyContainer, class MappedContainer, class Compare, class Allocator> + flat_multimap(KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, + class Compare = less<typename KeyContainer::value_type>> + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare = Compare()) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class KeyContainer, class MappedContainer, class Allocator> + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Allocator) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer, MappedContainer>; + template<class KeyContainer, class MappedContainer, class Compare, class Allocator> + flat_multimap(sorted_equivalent_t, KeyContainer, MappedContainer, Compare, Allocator) + -> flat_multimap<typename KeyContainer::value_type, typename MappedContainer::value_type, + Compare, KeyContainer, MappedContainer>; + + template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> + flat_multimap(InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; + + template<class InputIterator, class Compare = less<iter-key-type<InputIterator>>> + flat_multimap(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multimap<iter-key-type<InputIterator>, iter-mapped-type<InputIterator>, Compare>; + + template<ranges::input_range R, class Compare = less<range-key-type<R>>, + class Allocator = allocator<byte>> + flat_multimap(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multimap<range-key-type<R>, range-mapped-type<R>, Compare, + vector<range-key-type<R>, + alloc-rebind<Allocator, range-key-type<R>>>, + vector<range-mapped-type<R>, + alloc-rebind<Allocator, range-mapped-type<R>>>>; + + template<ranges::input_range R, class Allocator> + flat_multimap(from_range_t, R&&, Allocator) + -> flat_multimap<range-key-type<R>, range-mapped-type<R>, less<range-key-type<R>>, + vector<range-key-type<R>, + alloc-rebind<Allocator, range-key-type<R>>>, + vector<range-mapped-type<R>, + alloc-rebind<Allocator, range-mapped-type<R>>>>; + + template<class Key, class T, class Compare = less<Key>> + flat_multimap(initializer_list<pair<Key, T>>, Compare = Compare()) + -> flat_multimap<Key, T, Compare>; + + template<class Key, class T, class Compare = less<Key>> + flat_multimap(sorted_equivalent_t, initializer_list<pair<Key, T>>, Compare = Compare()) + -> flat_multimap<Key, T, Compare>; template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, - class Allocator> + class Allocator> struct uses_allocator<flat_multimap<Key, T, Compare, KeyContainer, MappedContainer>, - Allocator>; + Allocator> + : bool_constant<uses_allocator_v<KeyContainer, Allocator> && + uses_allocator_v<MappedContainer, Allocator>> { }; // [flat.multimap.erasure], erasure for flat_multimap template<class Key, class T, class Compare, class KeyContainer, class MappedContainer, diff --git a/lib/libcxx/include/flat_set b/lib/libcxx/include/flat_set @@ -17,30 +17,565 @@ #include <initializer_list> // see [initializer.list.syn] namespace std { + struct sorted_unique_t { explicit sorted_unique_t() = default; }; + inline constexpr sorted_unique_t sorted_unique{}; + // [flat.set], class template flat_set template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>> - class flat_set; + class flat_set { + public: + // types + using key_type = Key; + using value_type = Key; + using key_compare = Compare; + using value_compare = Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = KeyContainer::size_type; + using difference_type = KeyContainer::difference_type; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using container_type = KeyContainer; - struct sorted_unique_t { explicit sorted_unique_t() = default; }; - inline constexpr sorted_unique_t sorted_unique{}; + // [flat.set.cons], constructors + constexpr flat_set() : flat_set(key_compare()) { } + + constexpr flat_set(const flat_set&); + constexpr flat_set(flat_set&&); + constexpr flat_set& operator=(const flat_set&); + constexpr flat_set& operator=(flat_set&&); + + constexpr explicit flat_set(const key_compare& comp) + : c(), compare(comp) { } + + constexpr explicit flat_set(container_type cont, const key_compare& comp = key_compare()); + + constexpr flat_set(sorted_unique_t, container_type cont, + const key_compare& comp = key_compare()) + : c(std::move(cont)), compare(comp) { } + + template<class InputIterator> + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template<class InputIterator> + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(first, last), compare(comp) { } + + template<container-compatible-range<value_type> R> + constexpr flat_set(from_range_t, R&& rg) + : flat_set(from_range, std::forward<R>(rg), key_compare()) { } + template<container-compatible-range<value_type> R> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp) + : flat_set(comp) + { insert_range(std::forward<R>(rg)); } + + constexpr flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare()) + : flat_set(il.begin(), il.end(), comp) { } + + constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, + const key_compare& comp = key_compare()) + : flat_set(sorted_unique, il.begin(), il.end(), comp) { } + + // [flat.set.cons.alloc], constructors with allocators + + template<class Alloc> + constexpr explicit flat_set(const Alloc& a); + template<class Alloc> + constexpr flat_set(const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_set(const container_type& cont, const Alloc& a); + template<class Alloc> + constexpr flat_set(const container_type& cont, const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_set(sorted_unique_t, const container_type& cont, const Alloc& a); + template<class Alloc> + constexpr flat_set(sorted_unique_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_set(const flat_set&, const Alloc& a); + template<class Alloc> + constexpr flat_set(flat_set&&, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_set(InputIterator first, InputIterator last, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_set(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_set(sorted_unique_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_set(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_set(initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_set(initializer_list<value_type> il, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_set(sorted_unique_t, initializer_list<value_type> il, + const key_compare& comp, const Alloc& a); + + constexpr flat_set& operator=(initializer_list<value_type>); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.set.modifiers], modifiers + template<class... Args> constexpr pair<iterator, bool> emplace(Args&&... args); + template<class... Args> + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr pair<iterator, bool> insert(const value_type& x) + { return emplace(x); } + constexpr pair<iterator, bool> insert(value_type&& x) + { return emplace(std::move(x)); } + template<class K> constexpr pair<iterator, bool> insert(K&& x); + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + template<class K> constexpr iterator insert(const_iterator hint, K&& x); + + template<class InputIterator> + constexpr void insert(InputIterator first, InputIterator last); + template<class InputIterator> + constexpr void insert(sorted_unique_t, InputIterator first, InputIterator last); + template<container-compatible-range<value_type> R> + constexpr void insert_range(R&& rg); + template<container-compatible-range<value_type> R> + constexpr void insert_range(sorted_unique_t, R&& rg); + + constexpr void insert(initializer_list<value_type> il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_unique_t, initializer_list<value_type> il) + { insert(sorted_unique, il.begin(), il.end()); } + + constexpr container_type extract() &&; + constexpr void replace(container_type&&); + + constexpr iterator erase(iterator position) requires (!same_as<iterator, const_iterator>); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template<class K> constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_set& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + // set operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template<class K> constexpr iterator find(const K& x); + template<class K> constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template<class K> constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template<class K> constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template<class K> constexpr iterator lower_bound(const K& x); + template<class K> constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template<class K> constexpr iterator upper_bound(const K& x); + template<class K> constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair<iterator, iterator> equal_range(const key_type& x); + constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const; + template<class K> + constexpr pair<iterator, iterator> equal_range(const K& x); + template<class K> + constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_set& x, const flat_set& y); + + friend constexpr synth-three-way-result<value_type> + operator<=>(const flat_set& x, const flat_set& y); + + friend constexpr void swap(flat_set& x, flat_set& y) noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + container_type c; // exposition only + key_compare compare; // exposition only + }; + + template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> + flat_set(KeyContainer, Compare = Compare()) + -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; + template<class KeyContainer, class Allocator> + flat_set(KeyContainer, Allocator) + -> flat_set<typename KeyContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer>; + template<class KeyContainer, class Compare, class Allocator> + flat_set(KeyContainer, Compare, Allocator) + -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; + + template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> + flat_set(sorted_unique_t, KeyContainer, Compare = Compare()) + -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; + template<class KeyContainer, class Allocator> + flat_set(sorted_unique_t, KeyContainer, Allocator) + -> flat_set<typename KeyContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer>; + template<class KeyContainer, class Compare, class Allocator> + flat_set(sorted_unique_t, KeyContainer, Compare, Allocator) + -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>; + + template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> + flat_set(InputIterator, InputIterator, Compare = Compare()) + -> flat_set<iter-value-type<InputIterator>, Compare>; + + template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> + flat_set(sorted_unique_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_set<iter-value-type<InputIterator>, Compare>; + + template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>, + class Allocator = allocator<ranges::range_value_t<R>>> + flat_set(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_set<ranges::range_value_t<R>, Compare, + vector<ranges::range_value_t<R>, + alloc-rebind<Allocator, ranges::range_value_t<R>>>>; + + template<ranges::input_range R, class Allocator> + flat_set(from_range_t, R&&, Allocator) + -> flat_set<ranges::range_value_t<R>, less<ranges::range_value_t<R>>, + vector<ranges::range_value_t<R>, + alloc-rebind<Allocator, ranges::range_value_t<R>>>>; + + template<class Key, class Compare = less<Key>> + flat_set(initializer_list<Key>, Compare = Compare()) + -> flat_set<Key, Compare>; + + template<class Key, class Compare = less<Key>> + flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare()) + -> flat_set<Key, Compare>; template<class Key, class Compare, class KeyContainer, class Allocator> - struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator>; + struct uses_allocator<flat_set<Key, Compare, KeyContainer>, Allocator> + : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { }; // [flat.set.erasure], erasure for flat_set template<class Key, class Compare, class KeyContainer, class Predicate> typename flat_set<Key, Compare, KeyContainer>::size_type erase_if(flat_set<Key, Compare, KeyContainer>& c, Predicate pred); + struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; + inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multiset], class template flat_multiset template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>> - class flat_multiset; + class flat_multiset { + public: + // types + using key_type = Key; + using value_type = Key; + using key_compare = Compare; + using value_compare = Compare; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = KeyContainer::size_type; + using difference_type = KeyContainer::difference_type; + using iterator = implementation-defined; // see [container.requirements] + using const_iterator = implementation-defined; // see [container.requirements] + using reverse_iterator = std::reverse_iterator<iterator>; + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using container_type = KeyContainer; - struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; }; - inline constexpr sorted_equivalent_t sorted_equivalent{}; + // [flat.multiset.cons], constructors + constexpr flat_multiset() : flat_multiset(key_compare()) { } + + constexpr flat_multiset(const flat_multiset&); + constexpr flat_multiset(flat_multiset&&); + constexpr flat_multiset& operator=(const flat_multiset&); + constexpr flat_multiset& operator=(flat_multiset&&); + + constexpr explicit flat_multiset(const key_compare& comp) + : c(), compare(comp) { } + + constexpr explicit flat_multiset(container_type cont, + const key_compare& comp = key_compare()); + + constexpr flat_multiset(sorted_equivalent_t, container_type cont, + const key_compare& comp = key_compare()) + : c(std::move(cont)), compare(comp) { } + + template<class InputIterator> + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(), compare(comp) + { insert(first, last); } + + template<class InputIterator> + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp = key_compare()) + : c(first, last), compare(comp) { } + + template<container-compatible-range<value_type> R> + constexpr flat_multiset(from_range_t, R&& rg) + : flat_multiset(from_range, std::forward<R>(rg), key_compare()) { } + template<container-compatible-range<value_type> R> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp) + : flat_multiset(comp) + { insert_range(std::forward<R>(rg)); } + + constexpr flat_multiset(initializer_list<value_type> il, + const key_compare& comp = key_compare()) + : flat_multiset(il.begin(), il.end(), comp) { } + + constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, + const key_compare& comp = key_compare()) + : flat_multiset(sorted_equivalent, il.begin(), il.end(), comp) { } + + // [flat.multiset.cons.alloc], constructors with allocators + + template<class Alloc> + constexpr explicit flat_multiset(const Alloc& a); + template<class Alloc> + constexpr flat_multiset(const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(const container_type& cont, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(const container_type& cont, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(sorted_equivalent_t, const container_type& cont, + const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(const flat_multiset&, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(flat_multiset&&, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multiset(InputIterator first, InputIterator last, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multiset(InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const Alloc& a); + template<class InputIterator, class Alloc> + constexpr flat_multiset(sorted_equivalent_t, InputIterator first, InputIterator last, + const key_compare& comp, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const Alloc& a); + template<container-compatible-range<value_type> R, class Alloc> + constexpr flat_multiset(from_range_t, R&& rg, const key_compare& comp, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(initializer_list<value_type> il, const Alloc& a); + template<class Alloc> + constexpr flat_multiset(initializer_list<value_type> il, const key_compare& comp, + const Alloc& a); + template<class Alloc> + constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, + const Alloc& a); + template<class Alloc> + constexpr flat_multiset(sorted_equivalent_t, initializer_list<value_type> il, + const key_compare& comp, const Alloc& a); + + constexpr flat_multiset& operator=(initializer_list<value_type>); + + // iterators + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + + constexpr reverse_iterator rbegin() noexcept; + constexpr const_reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() noexcept; + constexpr const_reverse_iterator rend() const noexcept; + + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + // capacity + constexpr bool empty() const noexcept; + constexpr size_type size() const noexcept; + constexpr size_type max_size() const noexcept; + + // [flat.multiset.modifiers], modifiers + template<class... Args> constexpr iterator emplace(Args&&... args); + template<class... Args> + constexpr iterator emplace_hint(const_iterator position, Args&&... args); + + constexpr iterator insert(const value_type& x) + { return emplace(x); } + constexpr iterator insert(value_type&& x) + { return emplace(std::move(x)); } + constexpr iterator insert(const_iterator position, const value_type& x) + { return emplace_hint(position, x); } + constexpr iterator insert(const_iterator position, value_type&& x) + { return emplace_hint(position, std::move(x)); } + + template<class InputIterator> + constexpr void insert(InputIterator first, InputIterator last); + template<class InputIterator> + constexpr void insert(sorted_equivalent_t, InputIterator first, InputIterator last); + template<container-compatible-range<value_type> R> + constexpr void insert_range(R&& rg); + template<container-compatible-range<value_type> R> + constexpr void insert_range(sorted_equivalent_t, R&& rg); + + constexpr void insert(initializer_list<value_type> il) + { insert(il.begin(), il.end()); } + constexpr void insert(sorted_equivalent_t, initializer_list<value_type> il) + { insert(sorted_equivalent, il.begin(), il.end()); } + + constexpr container_type extract() &&; + constexpr void replace(container_type&&); + + constexpr iterator erase(iterator position) requires (!same_as<iterator, const_iterator>); + constexpr iterator erase(const_iterator position); + constexpr size_type erase(const key_type& x); + template<class K> constexpr size_type erase(K&& x); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void swap(flat_multiset& y) noexcept(see below); + constexpr void clear() noexcept; + + // observers + constexpr key_compare key_comp() const; + constexpr value_compare value_comp() const; + + // set operations + constexpr iterator find(const key_type& x); + constexpr const_iterator find(const key_type& x) const; + template<class K> constexpr iterator find(const K& x); + template<class K> constexpr const_iterator find(const K& x) const; + + constexpr size_type count(const key_type& x) const; + template<class K> constexpr size_type count(const K& x) const; + + constexpr bool contains(const key_type& x) const; + template<class K> constexpr bool contains(const K& x) const; + + constexpr iterator lower_bound(const key_type& x); + constexpr const_iterator lower_bound(const key_type& x) const; + template<class K> constexpr iterator lower_bound(const K& x); + template<class K> constexpr const_iterator lower_bound(const K& x) const; + + constexpr iterator upper_bound(const key_type& x); + constexpr const_iterator upper_bound(const key_type& x) const; + template<class K> constexpr iterator upper_bound(const K& x); + template<class K> constexpr const_iterator upper_bound(const K& x) const; + + constexpr pair<iterator, iterator> equal_range(const key_type& x); + constexpr pair<const_iterator, const_iterator> equal_range(const key_type& x) const; + template<class K> + constexpr pair<iterator, iterator> equal_range(const K& x); + template<class K> + constexpr pair<const_iterator, const_iterator> equal_range(const K& x) const; + + friend constexpr bool operator==(const flat_multiset& x, const flat_multiset& y); + + friend constexpr synth-three-way-result<value_type> + operator<=>(const flat_multiset& x, const flat_multiset& y); + + friend constexpr void swap(flat_multiset& x, flat_multiset& y) + noexcept(noexcept(x.swap(y))) + { x.swap(y); } + + private: + container_type c; // exposition only + key_compare compare; // exposition only + }; + + template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> + flat_multiset(KeyContainer, Compare = Compare()) + -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; + template<class KeyContainer, class Allocator> + flat_multiset(KeyContainer, Allocator) + -> flat_multiset<typename KeyContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer>; + template<class KeyContainer, class Compare, class Allocator> + flat_multiset(KeyContainer, Compare, Allocator) + -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; + + template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>> + flat_multiset(sorted_equivalent_t, KeyContainer, Compare = Compare()) + -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; + template<class KeyContainer, class Allocator> + flat_multiset(sorted_equivalent_t, KeyContainer, Allocator) + -> flat_multiset<typename KeyContainer::value_type, + less<typename KeyContainer::value_type>, KeyContainer>; + template<class KeyContainer, class Compare, class Allocator> + flat_multiset(sorted_equivalent_t, KeyContainer, Compare, Allocator) + -> flat_multiset<typename KeyContainer::value_type, Compare, KeyContainer>; + + template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> + flat_multiset(InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<iter-value-type<InputIterator>, Compare>; + + template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>> + flat_multiset(sorted_equivalent_t, InputIterator, InputIterator, Compare = Compare()) + -> flat_multiset<iter-value-type<InputIterator>, Compare>; + + template<ranges::input_range R, class Compare = less<ranges::range_value_t<R>>, + class Allocator = allocator<ranges::range_value_t<R>>> + flat_multiset(from_range_t, R&&, Compare = Compare(), Allocator = Allocator()) + -> flat_multiset<ranges::range_value_t<R>, Compare, + vector<ranges::range_value_t<R>, + alloc-rebind<Allocator, ranges::range_value_t<R>>>>; + + template<ranges::input_range R, class Allocator> + flat_multiset(from_range_t, R&&, Allocator) + -> flat_multiset<ranges::range_value_t<R>, less<ranges::range_value_t<R>>, + vector<ranges::range_value_t<R>, + alloc-rebind<Allocator, ranges::range_value_t<R>>>>; + + template<class Key, class Compare = less<Key>> + flat_multiset(initializer_list<Key>, Compare = Compare()) + -> flat_multiset<Key, Compare>; + + template<class Key, class Compare = less<Key>> + flat_multiset(sorted_equivalent_t, initializer_list<Key>, Compare = Compare()) + -> flat_multiset<Key, Compare>; template<class Key, class Compare, class KeyContainer, class Allocator> - struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>; + struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator> + : bool_constant<uses_allocator_v<KeyContainer, Allocator>> { }; // [flat.multiset.erasure], erasure for flat_multiset template<class Key, class Compare, class KeyContainer, class Predicate> diff --git a/lib/libcxx/include/float.h b/lib/libcxx/include/float.h @@ -71,29 +71,29 @@ Macros: */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/float.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# if __has_include_next(<float.h>) -# include_next <float.h> -# endif +#if __has_include_next(<float.h>) +# include_next <float.h> +#endif -# ifdef __cplusplus +#ifdef __cplusplus -# ifndef FLT_EVAL_METHOD -# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ -# endif +# ifndef FLT_EVAL_METHOD +# define FLT_EVAL_METHOD __FLT_EVAL_METHOD__ +# endif -# ifndef DECIMAL_DIG -# define DECIMAL_DIG __DECIMAL_DIG__ -# endif +# ifndef DECIMAL_DIG +# define DECIMAL_DIG __DECIMAL_DIG__ +# endif -# endif // __cplusplus -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif // __cplusplus #endif // _LIBCPP_FLOAT_H diff --git a/lib/libcxx/include/forward_list b/lib/libcxx/include/forward_list @@ -223,18 +223,17 @@ template <class T, class Allocator, class Predicate> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> -# include <__type_traits/conditional.h> # include <__type_traits/container_traits.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_allocator.h> # include <__type_traits/is_const.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> -# include <__type_traits/is_pointer.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> # include <__type_traits/remove_cv.h> # include <__type_traits/type_identity.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/move.h> # include <__utility/swap.h> @@ -283,17 +282,6 @@ struct __forward_node_traits { typedef _NodePtr __node_pointer; typedef __forward_begin_node<_NodePtr> __begin_node; typedef __rebind_pointer_t<_NodePtr, __begin_node> __begin_node_pointer; - -// TODO(LLVM 22): Remove this check -# ifndef _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB - static_assert(sizeof(__begin_node_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__begin_node_pointer) == - _LIBCPP_ALIGNOF(__node_pointer), - "It looks like you are using std::forward_list with a fancy pointer type that thas a different " - "representation depending on whether it points to a forward_list base pointer or a forward_list node " - "pointer (both of which are implementation details of the standard library). This means that your ABI " - "is being broken between LLVM 19 and LLVM 20. If you don't care about your ABI being broken, define " - "the _LIBCPP_ABI_FORWARD_LIST_REMOVE_NODE_POINTER_UB macro to silence this diagnostic."); -# endif }; template <class _NodePtr> @@ -680,7 +668,7 @@ public: # endif _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v); - template <__enable_if_t<__is_allocator<_Alloc>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Alloc>, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI forward_list(size_type __n, const value_type& __v, const allocator_type& __a) : __base(__a) { @@ -744,50 +732,52 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __v); - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(this->__alloc_); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__base::__before_begin()->__next_); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()->__next_); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return iterator(nullptr); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { + return iterator(nullptr); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return const_iterator(nullptr); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return const_iterator(__base::__before_begin()->__next_); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return const_iterator(nullptr); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator before_begin() _NOEXCEPT { return iterator(__base::__before_begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator before_begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbefore_begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbefore_begin() const _NOEXCEPT { return const_iterator(__base::__before_begin()); } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __base::__before_begin()->__next_ == nullptr; } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return std::min<size_type>(__node_traits::max_size(this->__alloc_), numeric_limits<difference_type>::max()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference front() { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference front() { _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list"); return __base::__before_begin()->__next_->__get_value(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference front() const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference front() const { _LIBCPP_ASSERT_NON_NULL(!empty(), "forward_list::front called on an empty list"); return __base::__before_begin()->__next_->__get_value(); } @@ -918,22 +908,22 @@ private: # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Alloc = allocator<__iter_value_type<_InputIterator>>, + class _Alloc = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -forward_list(_InputIterator, _InputIterator) -> forward_list<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +forward_list(_InputIterator, _InputIterator) -> forward_list<__iterator_value_type<_InputIterator>, _Alloc>; template <class _InputIterator, class _Alloc, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -forward_list(_InputIterator, _InputIterator, _Alloc) -> forward_list<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +forward_list(_InputIterator, _InputIterator, _Alloc) -> forward_list<__iterator_value_type<_InputIterator>, _Alloc>; # endif # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Alloc = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Alloc>::value> > + class = enable_if_t<__is_allocator_v<_Alloc>>> forward_list(from_range_t, _Range&&, _Alloc = _Alloc()) -> forward_list<ranges::range_value_t<_Range>, _Alloc>; # endif @@ -1180,22 +1170,17 @@ forward_list<_Tp, _Alloc>::__insert_after(const_iterator __p, size_type __n, _Ar if (__n > 0) { __node_pointer __first = this->__create_node(/* next = */ nullptr, std::forward<_Args>(__args)...); __node_pointer __last = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (--__n; __n != 0; --__n, __last = __last->__next_) { - __last->__next_ = this->__create_node(/* next = */ nullptr, std::forward<_Args>(__args)...); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (__first != nullptr) { __node_pointer __next = __first->__next_; this->__delete_node(__first); __first = __next; } - throw; + }); + for (--__n; __n != 0; --__n, __last = __last->__next_) { + __last->__next_ = this->__create_node(/* next = */ nullptr, std::forward<_Args>(__args)...); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __last->__next_ = __r->__next_; __r->__next_ = __first; __r = std::__static_fancy_pointer_cast<__begin_node_pointer>(__last); @@ -1220,22 +1205,17 @@ forward_list<_Tp, _Alloc>::__insert_after_with_sentinel(const_iterator __p, _Inp __node_pointer __first = this->__create_node(/* next = */ nullptr, *__f); __node_pointer __last = __first; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (++__f; __f != __l; ++__f, ((void)(__last = __last->__next_))) { - __last->__next_ = this->__create_node(/* next = */ nullptr, *__f); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (__first != nullptr) { __node_pointer __next = __first->__next_; this->__delete_node(__first); __first = __next; } - throw; + }); + for (++__f; __f != __l; ++__f, ((void)(__last = __last->__next_))) { + __last->__next_ = this->__create_node(/* next = */ nullptr, *__f); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __last->__next_ = __r->__next_; __r->__next_ = __first; diff --git a/lib/libcxx/include/fstream b/lib/libcxx/include/fstream @@ -221,7 +221,7 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -# if _LIBCPP_STD_VER >= 26 && defined(_LIBCPP_WIN32API) +# if _LIBCPP_STD_VER >= 23 && defined(_LIBCPP_WIN32API) _LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept; # endif @@ -254,7 +254,7 @@ public: void swap(basic_filebuf& __rhs); // 27.9.1.4 Members: - _LIBCPP_HIDE_FROM_ABI bool is_open() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const; basic_filebuf* open(const char* __s, ios_base::openmode __mode); # if _LIBCPP_HAS_OPEN_WITH_WCHAR basic_filebuf* open(const wchar_t* __s, ios_base::openmode __mode); @@ -262,15 +262,14 @@ public: _LIBCPP_HIDE_FROM_ABI basic_filebuf* open(const string& __s, ios_base::openmode __mode); # if _LIBCPP_STD_VER >= 17 - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI basic_filebuf* - open(const filesystem::path& __p, ios_base::openmode __mode) { + _LIBCPP_HIDE_FROM_ABI basic_filebuf* open(const filesystem::path& __p, ios_base::openmode __mode) { return open(__p.c_str(), __mode); } # endif _LIBCPP_HIDE_FROM_ABI basic_filebuf* __open(int __fd, ios_base::openmode __mode); basic_filebuf* close(); # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { _LIBCPP_ASSERT_UNCATEGORIZED(this->is_open(), "File must be opened"); # if defined(_LIBCPP_WIN32API) return std::__filebuf_windows_native_handle(__file_); @@ -299,6 +298,16 @@ protected: int sync() override; void imbue(const locale& __loc) override; + _LIBCPP_HIDE_FROM_ABI_VIRTUAL streamsize xsputn(const char_type* __str, streamsize __len) override { + if (__always_noconv_ && __len >= (this->epptr() - this->pbase())) { + if (traits_type::eq_int_type(overflow(), traits_type::eof())) + return 0; + + return std::fwrite(__str, sizeof(char_type), __len, __file_); + } + return basic_streambuf<_CharT, _Traits>::xsputn(__str, __len); + } + private: char* __extbuf_; const char* __extbufnext_; @@ -401,6 +410,14 @@ private: } } } + + _LIBCPP_HIDE_FROM_ABI typename traits_type::int_type __overflow_failed() { + if (this->pptr() == this->epptr() + 1) { + this->pbump(-1); // lose the character we overflowed above -- we don't really have a + // choice since we couldn't commit the contents of the put area + } + return traits_type::eof(); + } }; template <class _CharT, class _Traits> @@ -742,7 +759,12 @@ basic_filebuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::close() { if (fclose(__h.release())) __rt = nullptr; __file_ = nullptr; - setbuf(0, 0); + // Reset the get and the put areas without getting rid of the underlying buffers, + // which might have been configured by the user. Make sure to keep the buffers + // since the user may re-open the stream. + this->setg(nullptr, nullptr, nullptr); + this->setp(nullptr, nullptr); + __cm_ = __no_io_operations; } return __rt; } @@ -821,14 +843,6 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> template <class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits>::overflow(int_type __c) { - auto __failed = [this]() { - if (this->pptr() == this->epptr() + 1) { - this->pbump(-1); // lose the character we overflowed above -- we don't really have a - // choice since we couldn't commit the contents of the put area - } - return traits_type::eof(); - }; - if (__file_ == nullptr) return traits_type::eof(); __write_mode(); @@ -850,7 +864,7 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> if (__always_noconv_) { size_t __n = static_cast<size_t>(this->pptr() - this->pbase()); if (std::fwrite(this->pbase(), sizeof(char_type), __n, __file_) != __n) { - return __failed(); + return __overflow_failed(); } } else { if (!__cv_) @@ -864,14 +878,14 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> do { codecvt_base::result __r = __cv_->out(__st_, __b, __p, __end, __extbuf_, __extbuf_ + __ebs_, __extbuf_end); if (__end == __b) { - return __failed(); + return __overflow_failed(); } // No conversion needed: output characters directly to the file, done. if (__r == codecvt_base::noconv) { size_t __n = static_cast<size_t>(__p - __b); if (std::fwrite(__b, 1, __n, __file_) != __n) { - return __failed(); + return __overflow_failed(); } break; @@ -879,7 +893,7 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> } else if (__r == codecvt_base::ok) { size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_); if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) { - return __failed(); + return __overflow_failed(); } break; @@ -888,13 +902,13 @@ typename basic_filebuf<_CharT, _Traits>::int_type basic_filebuf<_CharT, _Traits> } else if (__r == codecvt_base::partial) { size_t __n = static_cast<size_t>(__extbuf_end - __extbuf_); if (std::fwrite(__extbuf_, 1, __n, __file_) != __n) { - return __failed(); + return __overflow_failed(); } __b = const_cast<char_type*>(__end); continue; } else { - return __failed(); + return __overflow_failed(); } } while (true); } @@ -977,7 +991,7 @@ template <class _CharT, class _Traits> int basic_filebuf<_CharT, _Traits>::__fseek(FILE* __file, pos_type __offset, int __whence) { # if defined(_LIBCPP_MSVCRT_LIKE) return _fseeki64(__file, __offset, __whence); -# elif defined(_NEWLIB_VERSION) +# elif _LIBCPP_LIBC_NEWLIB return fseek(__file, __offset, __whence); # else return ::fseeko(__file, __offset, __whence); @@ -988,7 +1002,7 @@ template <class _CharT, class _Traits> typename basic_filebuf<_CharT, _Traits>::pos_type basic_filebuf<_CharT, _Traits>::__ftell(FILE* __file) { # if defined(_LIBCPP_MSVCRT_LIKE) return _ftelli64(__file); -# elif defined(_NEWLIB_VERSION) +# elif _LIBCPP_LIBC_NEWLIB return ftell(__file); # else return ftello(__file); @@ -1147,27 +1161,27 @@ public: _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const string& __s, ios_base::openmode __mode = ios_base::in); # if _LIBCPP_STD_VER >= 17 template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>> - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY - _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const _Tp& __p, ios_base::openmode __mode = ios_base::in) + _LIBCPP_HIDE_FROM_ABI explicit basic_ifstream(const _Tp& __p, ios_base::openmode __mode = ios_base::in) : basic_ifstream(__p.c_str(), __mode) {} # endif // _LIBCPP_STD_VER >= 17 _LIBCPP_HIDE_FROM_ABI basic_ifstream(basic_ifstream&& __rhs); _LIBCPP_HIDE_FROM_ABI basic_ifstream& operator=(basic_ifstream&& __rhs); _LIBCPP_HIDE_FROM_ABI void swap(basic_ifstream& __rhs); - _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { + return rdbuf()->native_handle(); + } # endif - _LIBCPP_HIDE_FROM_ABI bool is_open() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const; void open(const char* __s, ios_base::openmode __mode = ios_base::in); # if _LIBCPP_HAS_OPEN_WITH_WCHAR void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in); # endif void open(const string& __s, ios_base::openmode __mode = ios_base::in); # if _LIBCPP_STD_VER >= 17 - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI void - open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in) { + _LIBCPP_HIDE_FROM_ABI void open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in) { return open(__p.c_str(), __mode); } # endif // _LIBCPP_STD_VER >= 17 @@ -1304,8 +1318,7 @@ public: # if _LIBCPP_STD_VER >= 17 template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>> - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY - _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const _Tp& __p, ios_base::openmode __mode = ios_base::out) + _LIBCPP_HIDE_FROM_ABI explicit basic_ofstream(const _Tp& __p, ios_base::openmode __mode = ios_base::out) : basic_ofstream(__p.c_str(), __mode) {} # endif // _LIBCPP_STD_VER >= 17 @@ -1313,11 +1326,13 @@ public: _LIBCPP_HIDE_FROM_ABI basic_ofstream& operator=(basic_ofstream&& __rhs); _LIBCPP_HIDE_FROM_ABI void swap(basic_ofstream& __rhs); - _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { + return rdbuf()->native_handle(); + } # endif - _LIBCPP_HIDE_FROM_ABI bool is_open() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const; void open(const char* __s, ios_base::openmode __mode = ios_base::out); # if _LIBCPP_HAS_OPEN_WITH_WCHAR void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out); @@ -1325,8 +1340,7 @@ public: void open(const string& __s, ios_base::openmode __mode = ios_base::out); # if _LIBCPP_STD_VER >= 17 - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI void - open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::out) { + _LIBCPP_HIDE_FROM_ABI void open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::out) { return open(__p.c_str(), __mode); } # endif // _LIBCPP_STD_VER >= 17 @@ -1466,8 +1480,7 @@ public: # if _LIBCPP_STD_VER >= 17 template <class _Tp, class = enable_if_t<is_same_v<_Tp, filesystem::path>>> - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI explicit basic_fstream( - const _Tp& __p, ios_base::openmode __mode = ios_base::in | ios_base::out) + _LIBCPP_HIDE_FROM_ABI explicit basic_fstream(const _Tp& __p, ios_base::openmode __mode = ios_base::in | ios_base::out) : basic_fstream(__p.c_str(), __mode) {} # endif // _LIBCPP_STD_VER >= 17 @@ -1477,11 +1490,13 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(basic_fstream& __rhs); - _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_filebuf<char_type, traits_type>* rdbuf() const; # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { return rdbuf()->native_handle(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() const noexcept { + return rdbuf()->native_handle(); + } # endif - _LIBCPP_HIDE_FROM_ABI bool is_open() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool is_open() const; _LIBCPP_HIDE_FROM_ABI void open(const char* __s, ios_base::openmode __mode = ios_base::in | ios_base::out); # if _LIBCPP_HAS_OPEN_WITH_WCHAR void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in | ios_base::out); @@ -1489,7 +1504,7 @@ public: _LIBCPP_HIDE_FROM_ABI void open(const string& __s, ios_base::openmode __mode = ios_base::in | ios_base::out); # if _LIBCPP_STD_VER >= 17 - _LIBCPP_AVAILABILITY_FILESYSTEM_LIBRARY _LIBCPP_HIDE_FROM_ABI void + _LIBCPP_HIDE_FROM_ABI void open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in | ios_base::out) { return open(__p.c_str(), __mode); } diff --git a/lib/libcxx/include/future b/lib/libcxx/include/future @@ -397,12 +397,14 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>; # include <__type_traits/decay.h> # include <__type_traits/enable_if.h> # include <__type_traits/invoke.h> +# include <__type_traits/is_constructible.h> # include <__type_traits/is_same.h> # include <__type_traits/remove_cvref.h> # include <__type_traits/remove_reference.h> # include <__type_traits/strip_signature.h> # include <__type_traits/underlying_type.h> # include <__utility/auto_cast.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/move.h> # include <__utility/swap.h> @@ -477,13 +479,13 @@ inline _LIBCPP_HIDE_FROM_ABI launch& operator^=(launch& __x, launch __y) { _LIBCPP_DECLARE_STRONG_ENUM(future_status){ready, timeout, deferred}; _LIBCPP_DECLARE_STRONG_ENUM_EPILOG(future_status) -_LIBCPP_EXPORTED_FROM_ABI const error_category& future_category() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& future_category() _NOEXCEPT; -inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(future_errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(future_errc __e) _NOEXCEPT { return error_code(static_cast<int>(__e), future_category()); } -inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(future_errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(future_errc __e) _NOEXCEPT { return error_condition(static_cast<int>(__e), future_category()); } @@ -502,7 +504,7 @@ public: _LIBCPP_HIDE_FROM_ABI explicit future_error(future_errc __ec) : future_error(std::make_error_code(__ec)) {} # endif - _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const error_code& code() const _NOEXCEPT { return __ec_; } _LIBCPP_HIDE_FROM_ABI future_error(const future_error&) _NOEXCEPT = default; ~future_error() _NOEXCEPT override; @@ -583,12 +585,9 @@ inline future_status __assoc_sub_state::wait_for(const chrono::duration<_Rep, _P template <class _Rp> class _LIBCPP_HIDDEN __assoc_state : public __assoc_sub_state { typedef __assoc_sub_state base; - _LIBCPP_SUPPRESS_DEPRECATED_PUSH - typedef typename aligned_storage<sizeof(_Rp), _LIBCPP_ALIGNOF(_Rp)>::type _Up; - _LIBCPP_SUPPRESS_DEPRECATED_POP protected: - _Up __value_; + _ALIGNAS_TYPE(_Rp) char __value_[sizeof(_Rp)]; _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override; @@ -943,15 +942,15 @@ public: } _LIBCPP_HIDE_FROM_ABI ~future(); - _LIBCPP_HIDE_FROM_ABI shared_future<_Rp> share() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_future<_Rp> share() _NOEXCEPT; // retrieving the value - _LIBCPP_HIDE_FROM_ABI _Rp get(); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp get(); _LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> @@ -1014,15 +1013,15 @@ public: } _LIBCPP_HIDE_FROM_ABI ~future(); - _LIBCPP_HIDE_FROM_ABI shared_future<_Rp&> share() _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI shared_future<_Rp&> share() _NOEXCEPT; // retrieving the value - _LIBCPP_HIDE_FROM_ABI _Rp& get(); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp& get(); _LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> @@ -1089,7 +1088,7 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> @@ -1139,7 +1138,7 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // retrieving the result - _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future(); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future(); // setting the result _LIBCPP_HIDE_FROM_ABI void set_value(const _Rp& __r); @@ -1256,7 +1255,7 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // retrieving the result - _LIBCPP_HIDE_FROM_ABI future<_Rp&> get_future(); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp&> get_future(); // setting the result _LIBCPP_HIDE_FROM_ABI void set_value(_Rp& __r); @@ -1366,7 +1365,7 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(promise& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // retrieving the result - future<void> get_future(); + [[__nodiscard__]] future<void> get_future(); // setting the result void set_value(); @@ -1639,10 +1638,10 @@ public: __p_.swap(__other.__p_); } - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; } // result retrieval - _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future() { return __p_.get_future(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<_Rp> get_future() { return __p_.get_future(); } // execution _LIBCPP_HIDE_FROM_ABI void operator()(_ArgTypes... __args); @@ -1728,10 +1727,10 @@ public: __p_.swap(__other.__p_); } - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __p_.__state_ != nullptr; } // result retrieval - _LIBCPP_HIDE_FROM_ABI future<void> get_future() { return __p_.get_future(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<void> get_future() { return __p_.get_future(); } // execution _LIBCPP_HIDE_FROM_ABI void operator()(_ArgTypes... __args); @@ -1815,16 +1814,9 @@ template <class _Rp, class _Fp> _LIBCPP_HIDE_FROM_ABI future<_Rp> __make_async_assoc_state(_Fp&& __f) { unique_ptr<__async_assoc_state<_Rp, _Fp>, __release_shared_count> __h( new __async_assoc_state<_Rp, _Fp>(std::forward<_Fp>(__f))); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif - std::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach(); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __h->__make_ready(); - throw; - } -# endif + auto __guard = std::__make_exception_guard([&] { __h->__make_ready(); }); + std::thread(&__async_assoc_state<_Rp, _Fp>::__execute, __h.get()).detach(); + __guard.__complete(); return future<_Rp>(__h.get()); } @@ -1837,20 +1829,16 @@ class _LIBCPP_HIDDEN __async_func { public: using _Rp _LIBCPP_NODEBUG = __invoke_result_t<_Fp, _Args...>; - _LIBCPP_HIDE_FROM_ABI explicit __async_func(_Fp&& __f, _Args&&... __args) - : __f_(std::move(__f), std::move(__args)...) {} + template <class _Gp, class... _BArgs> + _LIBCPP_HIDE_FROM_ABI explicit __async_func(_Gp&& __g, _BArgs&&... __bargs) + : __f_(std::forward<_Gp>(__g), std::forward<_BArgs>(__bargs)...) {} _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()); - } - -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_))...); + return [&]<size_t... _Indices>(__index_sequence<_Indices...>) -> _Rp { + return std::__invoke(std::move(std::get<_Indices>(__f_))...); + }(__index_sequence_for<_Fp, _Args...>{}); } }; @@ -1861,6 +1849,10 @@ inline _LIBCPP_HIDE_FROM_ABI bool __does_policy_contain(launch __policy, launch template <class _Fp, class... _Args> [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI future<__invoke_result_t<__decay_t<_Fp>, __decay_t<_Args>...> > async(launch __policy, _Fp&& __f, _Args&&... __args) { + static_assert(is_constructible<__decay_t<_Fp>, _Fp>::value, ""); + static_assert(_And<is_constructible<__decay_t<_Args>, _Args>...>::value, ""); + static_assert(__is_invocable_v<__decay_t<_Fp>, __decay_t<_Args>...>, ""); + typedef __async_func<__decay_t<_Fp>, __decay_t<_Args>...> _BF; typedef typename _BF::_Rp _Rp; @@ -1868,8 +1860,7 @@ async(launch __policy, _Fp&& __f, _Args&&... __args) { try { # endif if (__does_policy_contain(__policy, launch::async)) - return std::__make_async_assoc_state<_Rp>( - _BF(_LIBCPP_AUTO_CAST(std::forward<_Fp>(__f)), _LIBCPP_AUTO_CAST(std::forward<_Args>(__args))...)); + return std::__make_async_assoc_state<_Rp>(_BF(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { if (__policy == launch::async) @@ -1878,8 +1869,7 @@ async(launch __policy, _Fp&& __f, _Args&&... __args) { # endif if (__does_policy_contain(__policy, launch::deferred)) - return std::__make_deferred_assoc_state<_Rp>( - _BF(_LIBCPP_AUTO_CAST(std::forward<_Fp>(__f)), _LIBCPP_AUTO_CAST(std::forward<_Args>(__args))...)); + return std::__make_deferred_assoc_state<_Rp>(_BF(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)); return future<_Rp>{}; } @@ -1915,12 +1905,12 @@ public: } // retrieving the value - _LIBCPP_HIDE_FROM_ABI const _Rp& get() const { return __state_->copy(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const _Rp& get() const { return __state_->copy(); } _LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> @@ -1971,12 +1961,12 @@ public: } // retrieving the value - _LIBCPP_HIDE_FROM_ABI _Rp& get() const { return __state_->copy(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _Rp& get() const { return __state_->copy(); } _LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> @@ -2032,7 +2022,7 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(shared_future& __rhs) _NOEXCEPT { std::swap(__state_, __rhs.__state_); } // functions to check state - _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool valid() const _NOEXCEPT { return __state_ != nullptr; } _LIBCPP_HIDE_FROM_ABI void wait() const { __state_->wait(); } template <class _Rep, class _Period> diff --git a/lib/libcxx/include/initializer_list b/lib/libcxx/include/initializer_list @@ -78,11 +78,17 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 initializer_list() _NOEXCEPT : __begin_(nullptr), __size_(0) {} - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t size() const _NOEXCEPT { return __size_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 size_t size() const _NOEXCEPT { + return __size_; + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* begin() const _NOEXCEPT { return __begin_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* begin() const _NOEXCEPT { + return __begin_; + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* end() const _NOEXCEPT { return __begin_ + __size_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const _Ep* end() const _NOEXCEPT { + return __begin_ + __size_; + } }; template <class _Ep> diff --git a/lib/libcxx/include/inttypes.h b/lib/libcxx/include/inttypes.h @@ -236,33 +236,33 @@ uintmax_t wcstoumax(const wchar_t* restrict nptr, wchar_t** restrict endptr, int */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/inttypes.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif /* C99 stdlib (e.g. glibc < 2.18) does not provide format macros needed for C++11 unless __STDC_FORMAT_MACROS is defined */ -# if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) -# define __STDC_FORMAT_MACROS -# endif +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) +# define __STDC_FORMAT_MACROS +#endif -# if __has_include_next(<inttypes.h>) -# include_next <inttypes.h> -# endif +#if __has_include_next(<inttypes.h>) +# include_next <inttypes.h> +#endif -# ifdef __cplusplus +#ifdef __cplusplus -# include <stdint.h> +# include <stdint.h> -# undef imaxabs -# undef imaxdiv +# undef imaxabs +# undef imaxdiv -# endif // __cplusplus -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif // __cplusplus #endif // _LIBCPP_INTTYPES_H diff --git a/lib/libcxx/include/ios b/lib/libcxx/include/ios @@ -305,25 +305,25 @@ public: class _LIBCPP_EXPORTED_FROM_ABI Init; // 27.5.2.2 fmtflags state: - _LIBCPP_HIDE_FROM_ABI fmtflags flags() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI fmtflags flags() const; _LIBCPP_HIDE_FROM_ABI fmtflags flags(fmtflags __fmtfl); _LIBCPP_HIDE_FROM_ABI fmtflags setf(fmtflags __fmtfl); _LIBCPP_HIDE_FROM_ABI fmtflags setf(fmtflags __fmtfl, fmtflags __mask); _LIBCPP_HIDE_FROM_ABI void unsetf(fmtflags __mask); - _LIBCPP_HIDE_FROM_ABI streamsize precision() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI streamsize precision() const; _LIBCPP_HIDE_FROM_ABI streamsize precision(streamsize __prec); - _LIBCPP_HIDE_FROM_ABI streamsize width() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI streamsize width() const; _LIBCPP_HIDE_FROM_ABI streamsize width(streamsize __wide); // 27.5.2.3 locales: locale imbue(const locale& __loc); - locale getloc() const; + [[__nodiscard__]] locale getloc() const; // 27.5.2.5 storage: - static int xalloc(); - long& iword(int __index); - void*& pword(int __index); + [[__nodiscard__]] static int xalloc(); + [[__nodiscard__]] long& iword(int __index); + [[__nodiscard__]] void*& pword(int __index); // destructor virtual ~ios_base(); @@ -338,16 +338,16 @@ public: static bool sync_with_stdio(bool __sync = true); - _LIBCPP_HIDE_FROM_ABI iostate rdstate() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iostate rdstate() const; void clear(iostate __state = goodbit); _LIBCPP_HIDE_FROM_ABI void setstate(iostate __state); - _LIBCPP_HIDE_FROM_ABI bool good() const; - _LIBCPP_HIDE_FROM_ABI bool eof() const; - _LIBCPP_HIDE_FROM_ABI bool fail() const; - _LIBCPP_HIDE_FROM_ABI bool bad() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool good() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool eof() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool fail() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool bad() const; - _LIBCPP_HIDE_FROM_ABI iostate exceptions() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iostate exceptions() const; _LIBCPP_HIDE_FROM_ABI void exceptions(iostate __iostate); void __set_badbit_and_consider_rethrow(); @@ -425,13 +425,13 @@ template <> struct is_error_code_enum<io_errc::__lx> : public true_type {}; # endif -_LIBCPP_EXPORTED_FROM_ABI const error_category& iostream_category() _NOEXCEPT; +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI const error_category& iostream_category() _NOEXCEPT; -inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(io_errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_code make_error_code(io_errc __e) _NOEXCEPT { return error_code(static_cast<int>(__e), iostream_category()); } -inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(io_errc __e) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI error_condition make_error_condition(io_errc __e) _NOEXCEPT { return error_condition(static_cast<int>(__e), iostream_category()); } @@ -580,16 +580,16 @@ public: _LIBCPP_HIDE_FROM_ABI explicit operator bool() const { return !fail(); } # endif - _LIBCPP_HIDE_FROM_ABI bool operator!() const { return fail(); } - _LIBCPP_HIDE_FROM_ABI iostate rdstate() const { return ios_base::rdstate(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool operator!() const { return fail(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iostate rdstate() const { return ios_base::rdstate(); } _LIBCPP_HIDE_FROM_ABI void clear(iostate __state = goodbit) { ios_base::clear(__state); } _LIBCPP_HIDE_FROM_ABI void setstate(iostate __state) { ios_base::setstate(__state); } - _LIBCPP_HIDE_FROM_ABI bool good() const { return ios_base::good(); } - _LIBCPP_HIDE_FROM_ABI bool eof() const { return ios_base::eof(); } - _LIBCPP_HIDE_FROM_ABI bool fail() const { return ios_base::fail(); } - _LIBCPP_HIDE_FROM_ABI bool bad() const { return ios_base::bad(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool good() const { return ios_base::good(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool eof() const { return ios_base::eof(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool fail() const { return ios_base::fail(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool bad() const { return ios_base::bad(); } - _LIBCPP_HIDE_FROM_ABI iostate exceptions() const { return ios_base::exceptions(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iostate exceptions() const { return ios_base::exceptions(); } _LIBCPP_HIDE_FROM_ABI void exceptions(iostate __iostate) { ios_base::exceptions(__iostate); } // 27.5.4.1 Constructor/destructor: @@ -597,21 +597,21 @@ public: ~basic_ios() override; // 27.5.4.2 Members: - _LIBCPP_HIDE_FROM_ABI basic_ostream<char_type, traits_type>* tie() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_ostream<char_type, traits_type>* tie() const; _LIBCPP_HIDE_FROM_ABI basic_ostream<char_type, traits_type>* tie(basic_ostream<char_type, traits_type>* __tiestr); - _LIBCPP_HIDE_FROM_ABI basic_streambuf<char_type, traits_type>* rdbuf() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_streambuf<char_type, traits_type>* rdbuf() const; _LIBCPP_HIDE_FROM_ABI basic_streambuf<char_type, traits_type>* rdbuf(basic_streambuf<char_type, traits_type>* __sb); basic_ios& copyfmt(const basic_ios& __rhs); - _LIBCPP_HIDE_FROM_ABI char_type fill() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type fill() const; _LIBCPP_HIDE_FROM_ABI char_type fill(char_type __ch); _LIBCPP_HIDE_FROM_ABI locale imbue(const locale& __loc); - _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const; - _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char narrow(char_type __c, char __dfault) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char_type widen(char __c) const; protected: _LIBCPP_HIDE_FROM_ABI basic_ios() { diff --git a/lib/libcxx/include/istream b/lib/libcxx/include/istream @@ -70,6 +70,7 @@ public: basic_istream& getline(char_type* s, streamsize n, char_type delim); basic_istream& ignore(streamsize n = 1, int_type delim = traits_type::eof()); + basic_istream& ignore(streamsize n, char_type delim); // Since C++26, implemented as a DR int_type peek(); basic_istream& read (char_type* s, streamsize n); streamsize readsome(char_type* s, streamsize n); @@ -172,6 +173,7 @@ template <class Stream, class T> # include <__type_traits/conjunction.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_base_of.h> +# include <__type_traits/is_same.h> # include <__type_traits/make_unsigned.h> # include <__utility/declval.h> # include <__utility/forward.h> @@ -207,7 +209,7 @@ public: typedef typename traits_type::off_type off_type; // 27.7.1.1.1 Constructor/destructor: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb) + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_istream(basic_streambuf<char_type, traits_type>* __sb) : __gc_(0) { this->init(__sb); } @@ -219,7 +221,7 @@ protected: // 27.7.1.1.2 Assign/swap: inline _LIBCPP_HIDE_FROM_ABI basic_istream& operator=(basic_istream&& __rhs); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_istream& __rhs) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_istream& __rhs) { std::swap(__gc_, __rhs.__gc_); basic_ios<char_type, traits_type>::swap(__rhs); } @@ -232,17 +234,17 @@ public: class sentry; // 27.7.1.2 Formatted input: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(basic_istream& (*__pf)(basic_istream&)) { return __pf(*this); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(basic_ios<char_type, traits_type>& (*__pf)(basic_ios<char_type, traits_type>&)) { __pf(*this); return *this; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& operator>>(ios_base& (*__pf)(ios_base&)) { __pf(*this); return *this; } @@ -263,35 +265,39 @@ public: basic_istream& operator>>(void*& __p); // 27.7.1.3 Unformatted input: - _LIBCPP_HIDE_FROM_ABI streamsize gcount() const { return __gc_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI streamsize gcount() const { return __gc_; } int_type get(); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type& __c) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type& __c) { int_type __ch = get(); if (__ch != traits_type::eof()) __c = traits_type::to_char_type(__ch); return *this; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(char_type* __s, streamsize __n) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(char_type* __s, streamsize __n) { return get(__s, __n, this->widen('\n')); } basic_istream& get(char_type* __s, streamsize __n, char_type __dlm); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& get(basic_streambuf<char_type, traits_type>& __sb) { return get(__sb, this->widen('\n')); } basic_istream& get(basic_streambuf<char_type, traits_type>& __sb, char_type __dlm); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_istream& getline(char_type* __s, streamsize __n) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_istream& getline(char_type* __s, streamsize __n) { return getline(__s, __n, this->widen('\n')); } basic_istream& getline(char_type* __s, streamsize __n, char_type __dlm); basic_istream& ignore(streamsize __n = 1, int_type __dlm = traits_type::eof()); + template <class _Tp = char_type, __enable_if_t<is_same<_Tp, char>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI basic_istream& ignore(streamsize __n, char_type __delim) { + return ignore(__n, traits_type::to_int_type(__delim)); + } int_type peek(); basic_istream& read(char_type* __s, streamsize __n); streamsize readsome(char_type* __s, streamsize __n); @@ -300,7 +306,7 @@ public: basic_istream& unget(); int sync(); - pos_type tellg(); + [[__nodiscard__]] pos_type tellg(); basic_istream& seekg(pos_type __pos); basic_istream& seekg(off_type __off, ios_base::seekdir __dir); }; @@ -1178,7 +1184,7 @@ public: typedef typename traits_type::off_type off_type; // constructor/destructor - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb) + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit basic_iostream(basic_streambuf<char_type, traits_type>* __sb) : basic_istream<_CharT, _Traits>(__sb) {} ~basic_iostream() override; @@ -1189,7 +1195,7 @@ protected: // assign/swap inline _LIBCPP_HIDE_FROM_ABI basic_iostream& operator=(basic_iostream&& __rhs); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void swap(basic_iostream& __rhs) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void swap(basic_iostream& __rhs) { basic_istream<char_type, traits_type>::swap(__rhs); } }; diff --git a/lib/libcxx/include/iterator b/lib/libcxx/include/iterator @@ -737,6 +737,16 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept; # include <compare> # include <concepts> +// [range.access.general] +# if _LIBCPP_STD_VER >= 20 +# include <__ranges/access.h> +# include <__ranges/data.h> +# include <__ranges/empty.h> +# include <__ranges/rbegin.h> +# include <__ranges/rend.h> +# include <__ranges/size.h> +# endif + # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header # endif diff --git a/lib/libcxx/include/latch b/lib/libcxx/include/latch @@ -70,7 +70,9 @@ class latch { atomic<ptrdiff_t> __a_; public: - static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { return numeric_limits<ptrdiff_t>::max(); } + [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI constexpr ptrdiff_t max() noexcept { + return numeric_limits<ptrdiff_t>::max(); + } inline _LIBCPP_HIDE_FROM_ABI constexpr explicit latch(ptrdiff_t __expected) : __a_(__expected) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( @@ -87,7 +89,7 @@ public: latch(const latch&) = delete; latch& operator=(const latch&) = delete; - inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) { + inline _LIBCPP_HIDE_FROM_ABI void count_down(ptrdiff_t __update = 1) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::count_down called with a negative value"); auto const __old = __a_.fetch_sub(__update, memory_order_release); _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( @@ -97,16 +99,16 @@ public: if (__old == __update) __a_.notify_all(); } - inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { + [[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI bool try_wait() const noexcept { auto __value = __a_.load(memory_order_acquire); return try_wait_impl(__value); } - inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void wait() const { + inline _LIBCPP_HIDE_FROM_ABI void wait() const { std::__atomic_wait_unless(__a_, memory_order_acquire, [this](ptrdiff_t& __value) -> bool { return try_wait_impl(__value); }); } - inline _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) { + inline _LIBCPP_HIDE_FROM_ABI void arrive_and_wait(ptrdiff_t __update = 1) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "latch::arrive_and_wait called with a negative value"); // other preconditions on __update are checked in count_down() diff --git a/lib/libcxx/include/limits b/lib/libcxx/include/limits @@ -107,7 +107,7 @@ template<> class numeric_limits<cv long double>; #else # include <__config> # include <__type_traits/is_arithmetic.h> -# include <__type_traits/is_signed.h> +# include <__type_traits/is_same.h> # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -217,10 +217,10 @@ protected: static _LIBCPP_CONSTEXPR const bool is_iec559 = false; static _LIBCPP_CONSTEXPR const bool is_bounded = true; - static _LIBCPP_CONSTEXPR const bool is_modulo = !std::is_signed<_Tp>::value; + static _LIBCPP_CONSTEXPR const bool is_modulo = !is_signed; -# if defined(__i386__) || defined(__x86_64__) || defined(__pnacl__) || defined(__wasm__) - static _LIBCPP_CONSTEXPR const bool traps = true; +# if defined(__i386__) || defined(__x86_64__) || defined(__wasm__) + static _LIBCPP_CONSTEXPR const bool traps = is_same<decltype(+_Tp(0)), _Tp>::value; # else static _LIBCPP_CONSTEXPR const bool traps = false; # endif diff --git a/lib/libcxx/include/list b/lib/libcxx/include/list @@ -228,15 +228,14 @@ template <class T, class Allocator, class Predicate> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> -# include <__type_traits/conditional.h> # include <__type_traits/container_traits.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_allocator.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> -# include <__type_traits/is_pointer.h> # include <__type_traits/is_same.h> # include <__type_traits/type_identity.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/move.h> # include <__utility/swap.h> @@ -275,17 +274,6 @@ template <class _Tp, class _VoidPtr> struct __list_node_pointer_traits { typedef __rebind_pointer_t<_VoidPtr, __list_node<_Tp, _VoidPtr> > __node_pointer; typedef __rebind_pointer_t<_VoidPtr, __list_node_base<_Tp, _VoidPtr> > __base_pointer; - -// TODO(LLVM 22): Remove this check -# ifndef _LIBCPP_ABI_LIST_REMOVE_NODE_POINTER_UB - static_assert(sizeof(__node_pointer) == sizeof(__node_pointer) && _LIBCPP_ALIGNOF(__base_pointer) == - _LIBCPP_ALIGNOF(__node_pointer), - "It looks like you are using std::list with a fancy pointer type that thas a different representation " - "depending on whether it points to a list base pointer or a list node pointer (both of which are " - "implementation details of the standard library). This means that your ABI is being broken between " - "LLVM 19 and LLVM 20. If you don't care about your ABI being broken, define the " - "_LIBCPP_ABI_LIST_REMOVE_NODE_POINTER_UB macro to silence this diagnostic."); -# endif }; template <class _Tp, class _VoidPtr> @@ -724,7 +712,7 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI explicit list(size_type __n, const allocator_type& __a); # endif _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI list(size_type __n, const value_type& __x); - template <__enable_if_t<__is_allocator<_Alloc>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Alloc>, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI list(size_type __n, const value_type& __x, const allocator_type& __a) : __base(__a) { @@ -786,57 +774,71 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void assign(size_type __n, const value_type& __x); - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT; + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT; - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return this->__size_; } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { + return this->__size_; + } [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __base::empty(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return std::min<size_type>(this->__node_alloc_max_size(), numeric_limits<difference_type >::max()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __base::begin(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __base::begin(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __base::end(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __base::end(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { + return __base::begin(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { + return __base::begin(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { + return __base::end(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { + return __base::end(); + } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __base::begin(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __base::end(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { + return __base::end(); + } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + crbegin() const _NOEXCEPT { return const_reverse_iterator(end()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return const_reverse_iterator(begin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference front() { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference front() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::front called on empty list"); return __base::__end_.__next_->__as_node()->__get_value(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference front() const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference front() const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::front called on empty list"); return __base::__end_.__next_->__as_node()->__get_value(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference back() { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI reference back() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::back called on empty list"); return __base::__end_.__prev_->__as_node()->__get_value(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference back() const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference back() const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "list::back called on empty list"); return __base::__end_.__prev_->__as_node()->__get_value(); } @@ -1000,22 +1002,22 @@ private: # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Alloc = allocator<__iter_value_type<_InputIterator>>, + class _Alloc = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -list(_InputIterator, _InputIterator) -> list<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +list(_InputIterator, _InputIterator) -> list<__iterator_value_type<_InputIterator>, _Alloc>; template <class _InputIterator, class _Alloc, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value> > -list(_InputIterator, _InputIterator, _Alloc) -> list<__iter_value_type<_InputIterator>, _Alloc>; + class = enable_if_t<__is_allocator_v<_Alloc>>> +list(_InputIterator, _InputIterator, _Alloc) -> list<__iterator_value_type<_InputIterator>, _Alloc>; # endif # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Alloc = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Alloc>::value> > + class = enable_if_t<__is_allocator_v<_Alloc>>> list(from_range_t, _Range&&, _Alloc = _Alloc()) -> list<ranges::range_value_t<_Range>, _Alloc>; # endif @@ -1233,14 +1235,7 @@ list<_Tp, _Alloc>::insert(const_iterator __p, size_type __n, const value_type& _ ++__ds; __r = iterator(__node->__as_link()); iterator __e = __r; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { - __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, __x)->__as_link(); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (true) { __base_pointer __prev = __e.__ptr_->__prev_; __node_pointer __current = __e.__ptr_->__as_node(); @@ -1249,9 +1244,11 @@ list<_Tp, _Alloc>::insert(const_iterator __p, size_type __n, const value_type& _ break; __e = iterator(__prev); } - throw; + }); + for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { + __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, __x)->__as_link(); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __link_nodes(__p.__ptr_, __r.__ptr_, __e.__ptr_); this->__size_ += __ds; } @@ -1276,14 +1273,7 @@ list<_Tp, _Alloc>::__insert_with_sentinel(const_iterator __p, _Iterator __f, _Se ++__ds; __r = iterator(__node->__as_link()); iterator __e = __r; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (++__f; __f != __l; ++__f, (void)++__e, ++__ds) { - __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, *__f)->__as_link(); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (true) { __base_pointer __prev = __e.__ptr_->__prev_; __node_pointer __current = __e.__ptr_->__as_node(); @@ -1292,9 +1282,11 @@ list<_Tp, _Alloc>::__insert_with_sentinel(const_iterator __p, _Iterator __f, _Se break; __e = iterator(__prev); } - throw; + }); + for (++__f; __f != __l; ++__f, (void)++__e, ++__ds) { + __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, *__f)->__as_link(); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __link_nodes(__p.__ptr_, __r.__ptr_, __e.__ptr_); this->__size_ += __ds; } @@ -1452,14 +1444,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void list<_Tp, _Alloc>::resize(size_type __n) { ++__ds; iterator __r = iterator(__node->__as_link()); iterator __e = __r; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { - __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr)->__as_link(); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (true) { __base_pointer __prev = __e.__ptr_->__prev_; __node_pointer __current = __e.__ptr_->__as_node(); @@ -1468,9 +1453,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void list<_Tp, _Alloc>::resize(size_type __n) { break; __e = iterator(__prev); } - throw; + }); + for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { + __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr)->__as_link(); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __link_nodes_at_back(__r.__ptr_, __e.__ptr_); this->__size_ += __ds; } @@ -1488,14 +1475,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void list<_Tp, _Alloc>::resize(size_type __n, cons __base_pointer __nl = __node->__as_link(); iterator __r = iterator(__nl); iterator __e = __r; -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { - __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, __x)->__as_link(); - } -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { + auto __guard = std::__make_exception_guard([&] { while (true) { __base_pointer __prev = __e.__ptr_->__prev_; __node_pointer __current = __e.__ptr_->__as_node(); @@ -1504,9 +1484,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX26 void list<_Tp, _Alloc>::resize(size_type __n, cons break; __e = iterator(__prev); } - throw; + }); + for (--__n; __n != 0; --__n, (void)++__e, ++__ds) { + __e.__ptr_->__next_ = this->__create_node(/* prev = */ __e.__ptr_, /* next = */ nullptr, __x)->__as_link(); } -# endif // _LIBCPP_HAS_EXCEPTIONS + __guard.__complete(); __link_nodes(__base::__end_as_link(), __r.__ptr_, __e.__ptr_); this->__size_ += __ds; } diff --git a/lib/libcxx/include/map b/lib/libcxx/include/map @@ -577,12 +577,12 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20 # include <__algorithm/equal.h> # include <__algorithm/lexicographical_compare.h> # include <__algorithm/lexicographical_compare_three_way.h> +# include <__algorithm/specialized_algorithms.h> # include <__assert> # include <__config> # include <__functional/binary_function.h> # include <__functional/is_transparent.h> # include <__functional/operations.h> -# include <__fwd/map.h> # include <__iterator/erase_if_container.h> # include <__iterator/iterator_traits.h> # include <__iterator/ranges_iterator_traits.h> @@ -590,19 +590,23 @@ erase_if(multimap<Key, T, Compare, Allocator>& c, Predicate pred); // C++20 # include <__memory/addressof.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> +# include <__memory/compressed_pair.h> # include <__memory/pointer_traits.h> # include <__memory/unique_ptr.h> # include <__memory_resource/polymorphic_allocator.h> # include <__node_handle> +# include <__ranges/access.h> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> # include <__tree> # include <__type_traits/container_traits.h> # include <__type_traits/is_allocator.h> +# include <__type_traits/make_transparent.h> # include <__type_traits/remove_const.h> # include <__type_traits/type_identity.h> # include <__utility/forward.h> +# include <__utility/lazy_synth_three_way_comparator.h> # include <__utility/pair.h> # include <__utility/piecewise_construct.h> # include <__utility/swap.h> @@ -632,47 +636,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Key, - class _CP, - class _Compare, - bool = is_empty<_Compare>::value && !__libcpp_is_final<_Compare>::value> -class __map_value_compare : private _Compare { -public: - _LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value) - : _Compare() {} - _LIBCPP_HIDE_FROM_ABI __map_value_compare(_Compare __c) _NOEXCEPT_(is_nothrow_copy_constructible<_Compare>::value) - : _Compare(__c) {} - _LIBCPP_HIDE_FROM_ABI const _Compare& key_comp() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { - return static_cast<const _Compare&>(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { - return static_cast<const _Compare&>(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { - return static_cast<const _Compare&>(*this)(__x, __y.first); - } - _LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { - using std::swap; - swap(static_cast<_Compare&>(*this), static_cast<_Compare&>(__y)); - } - -# if _LIBCPP_STD_VER >= 14 - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _CP& __y) const { - return static_cast<const _Compare&>(*this)(__x, __y.first); - } - - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _K2& __y) const { - return static_cast<const _Compare&>(*this)(__x.first, __y); - } -# endif -}; - template <class _Key, class _CP, class _Compare> -class __map_value_compare<_Key, _CP, _Compare, false> { - _Compare __comp_; +class __map_value_compare { + _LIBCPP_COMPRESSED_ELEMENT(_Compare, __comp_); public: _LIBCPP_HIDE_FROM_ABI __map_value_compare() _NOEXCEPT_(is_nothrow_default_constructible<_Compare>::value) @@ -684,7 +650,7 @@ public: _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _CP& __y) const { return __comp_(__x.first, __y.first); } _LIBCPP_HIDE_FROM_ABI bool operator()(const _CP& __x, const _Key& __y) const { return __comp_(__x.first, __y); } _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _CP& __y) const { return __comp_(__x, __y.first); } - void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { + _LIBCPP_HIDE_FROM_ABI void swap(__map_value_compare& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Compare>) { using std::swap; swap(__comp_, __y.__comp_); } @@ -702,9 +668,58 @@ public: # endif }; -template <class _Key, class _CP, class _Compare, bool __b> +template <class _Key, class _MapValueT, class _Compare> +struct __make_transparent<_Key, __map_value_compare<_Key, _MapValueT, _Compare> > { + using type _LIBCPP_NODEBUG = __map_value_compare<_Key, _MapValueT, __make_transparent_t<_Key, _Compare> >; +}; + +# if _LIBCPP_STD_VER >= 14 +template <class _MapValueT, class _Key, class _Compare> +struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _MapValueT, _MapValueT> { + __lazy_synth_three_way_comparator<_Compare, _Key, _Key> __comp_; + + __lazy_synth_three_way_comparator( + _LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp) + : __comp_(__comp.key_comp()) {} + + _LIBCPP_HIDE_FROM_ABI auto + operator()(_LIBCPP_LIFETIMEBOUND const _MapValueT& __lhs, _LIBCPP_LIFETIMEBOUND const _MapValueT& __rhs) const { + return __comp_(__lhs.first, __rhs.first); + } +}; + +template <class _MapValueT, class _Key, class _TransparentKey, class _Compare> +struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _TransparentKey, _MapValueT> { + __lazy_synth_three_way_comparator<_Compare, _TransparentKey, _Key> __comp_; + + __lazy_synth_three_way_comparator( + _LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp) + : __comp_(__comp.key_comp()) {} + + _LIBCPP_HIDE_FROM_ABI auto + operator()(_LIBCPP_LIFETIMEBOUND const _TransparentKey& __lhs, _LIBCPP_LIFETIMEBOUND const _MapValueT& __rhs) const { + return __comp_(__lhs, __rhs.first); + } +}; + +template <class _MapValueT, class _Key, class _TransparentKey, class _Compare> +struct __lazy_synth_three_way_comparator<__map_value_compare<_Key, _MapValueT, _Compare>, _MapValueT, _TransparentKey> { + __lazy_synth_three_way_comparator<_Compare, _Key, _TransparentKey> __comp_; + + __lazy_synth_three_way_comparator( + _LIBCPP_CTOR_LIFETIMEBOUND const __map_value_compare<_Key, _MapValueT, _Compare>& __comp) + : __comp_(__comp.key_comp()) {} + + _LIBCPP_HIDE_FROM_ABI auto + operator()(_LIBCPP_LIFETIMEBOUND const _MapValueT& __lhs, _LIBCPP_LIFETIMEBOUND const _TransparentKey& __rhs) const { + return __comp_(__lhs.first, __rhs); + } +}; +# endif // _LIBCPP_STD_VER >= 14 + +template <class _Key, class _CP, class _Compare> inline _LIBCPP_HIDE_FROM_ABI void -swap(__map_value_compare<_Key, _CP, _Compare, __b>& __x, __map_value_compare<_Key, _CP, _Compare, __b>& __y) +swap(__map_value_compare<_Key, _CP, _Compare>& __x, __map_value_compare<_Key, _CP, _Compare>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } @@ -742,9 +757,9 @@ public: _LIBCPP_HIDE_FROM_ABI void operator()(pointer __p) _NOEXCEPT { if (__second_constructed) - __alloc_traits::destroy(__na_, std::addressof(__p->__value_.second)); + __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().second)); if (__first_constructed) - __alloc_traits::destroy(__na_, std::addressof(__p->__value_.first)); + __alloc_traits::destroy(__na_, std::addressof(__p->__get_value().first)); if (__p) __alloc_traits::deallocate(__na_, __p, 1); } @@ -804,7 +819,26 @@ public: friend class multimap; template <class> friend class __map_const_iterator; + + template <class, class...> + friend struct __specialized_algorithm; +}; + +# ifndef _LIBCPP_CXX03_LANG +template <class _Alg, class _TreeIterator> +struct __specialized_algorithm<_Alg, __iterator_pair<__map_iterator<_TreeIterator>, __map_iterator<_TreeIterator>>> { + using __base _LIBCPP_NODEBUG = __specialized_algorithm<_Alg, __iterator_pair<_TreeIterator, _TreeIterator>>; + + static const bool __has_algorithm = __base::__has_algorithm; + + using __iterator _LIBCPP_NODEBUG = __map_iterator<_TreeIterator>; + + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Args&&... __args) { + __base()(__first.__i_, __last.__i_, std::forward<_Args>(__args)...); + } }; +# endif template <class _TreeIterator> class __map_const_iterator { @@ -859,9 +893,33 @@ public: friend class multimap; template <class, class, class> friend class __tree_const_iterator; + + template <class, class...> + friend struct __specialized_algorithm; }; -template <class _Key, class _Tp, class _Compare, class _Allocator> +# ifndef _LIBCPP_CXX03_LANG +template <class _Alg, class _TreeIterator> +struct __specialized_algorithm< + _Alg, + __iterator_pair<__map_const_iterator<_TreeIterator>, __map_const_iterator<_TreeIterator>>> { + using __base _LIBCPP_NODEBUG = __specialized_algorithm<_Alg, __iterator_pair<_TreeIterator, _TreeIterator>>; + + static const bool __has_algorithm = __base::__has_algorithm; + + using __iterator _LIBCPP_NODEBUG = __map_const_iterator<_TreeIterator>; + + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI static void operator()(__iterator __first, __iterator __last, _Args&&... __args) { + __base()(__first.__i_, __last.__i_, std::forward<_Args>(__args)...); + } +}; +# endif + +template <class _Key, class _Tp, class _Compare = less<_Key>, class _Allocator = allocator<pair<const _Key, _Tp> > > +class multimap; + +template <class _Key, class _Tp, class _Compare = less<_Key>, class _Allocator = allocator<pair<const _Key, _Tp> > > class map { public: // types: @@ -970,17 +1028,17 @@ public: : map(from_range, std::forward<_Range>(__range), key_compare(), __a) {} # endif - _LIBCPP_HIDE_FROM_ABI map(const map& __m) : __tree_(__m.__tree_) { insert(__m.begin(), __m.end()); } + _LIBCPP_HIDE_FROM_ABI map(const map& __m) = default; _LIBCPP_HIDE_FROM_ABI map& operator=(const map& __m) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI map(map&& __m) noexcept(is_nothrow_move_constructible<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI map(map&& __m) = default; - _LIBCPP_HIDE_FROM_ABI map(map&& __m, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI map(map&& __m, const allocator_type& __a) : __tree_(std::move(__m.__tree_), __a) {} - _LIBCPP_HIDE_FROM_ABI map& operator=(map&& __m) noexcept(is_nothrow_move_assignable<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI map& operator=(map&& __m) = default; _LIBCPP_HIDE_FROM_ABI map(initializer_list<value_type> __il, const key_compare& __comp = key_compare()) : __tree_(__vc(__comp)) { @@ -998,7 +1056,8 @@ public: # endif _LIBCPP_HIDE_FROM_ABI map& operator=(initializer_list<value_type> __il) { - __tree_.__assign_unique(__il.begin(), __il.end()); + clear(); + insert(__il.begin(), __il.end()); return *this; } @@ -1006,43 +1065,66 @@ public: _LIBCPP_HIDE_FROM_ABI explicit map(const allocator_type& __a) : __tree_(typename __base::allocator_type(__a)) {} - _LIBCPP_HIDE_FROM_ABI map(const map& __m, const allocator_type& __a) - : __tree_(__m.__tree_.value_comp(), typename __base::allocator_type(__a)) { - insert(__m.begin(), __m.end()); - } + _LIBCPP_HIDE_FROM_ABI map(const map& __m, const allocator_type& __alloc) : __tree_(__m.__tree_, __alloc) {} _LIBCPP_HIDE_FROM_ABI ~map() { static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), ""); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.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()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __tree_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](const key_type& __k); # ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](key_type&& __k); # endif - _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; + template <class _Arg, + __enable_if_t<__is_transparently_comparable_v<_Compare, key_type, __remove_cvref_t<_Arg> >, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& at(_Arg&& __arg) { + auto [_, __child] = __tree_.__find_equal(__arg); + if (__child == nullptr) + std::__throw_out_of_range("map::at: key not found"); + return static_cast<__node_pointer>(__child)->__get_value().second; + } + + template <class _Arg, + __enable_if_t<__is_transparently_comparable_v<_Compare, key_type, __remove_cvref_t<_Arg> >, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mapped_type& at(_Arg&& __arg) const { + auto [_, __child] = __tree_.__find_equal(__arg); + if (__child == nullptr) + std::__throw_out_of_range("map::at: key not found"); + return static_cast<__node_pointer>(__child)->__get_value().second; + } - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__tree_.__alloc()); } - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return value_compare(__tree_.value_comp().key_comp()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + return allocator_type(__tree_.__alloc()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { + return value_compare(__tree_.value_comp().key_comp()); + } # ifndef _LIBCPP_CXX03_LANG template <class... _Args> @@ -1052,7 +1134,7 @@ public: template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __p, _Args&&... __args) { - return __tree_.__emplace_hint_unique(__p.__i_, std::forward<_Args>(__args)...); + return __tree_.__emplace_hint_unique(__p.__i_, std::forward<_Args>(__args)...).first; } template <class _Pp, __enable_if_t<is_constructible<value_type, _Pp>::value, int> = 0> @@ -1062,7 +1144,7 @@ public: template <class _Pp, __enable_if_t<is_constructible<value_type, _Pp>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __pos, _Pp&& __p) { - return __tree_.__emplace_hint_unique(__pos.__i_, std::forward<_Pp>(__p)); + return __tree_.__emplace_hint_unique(__pos.__i_, std::forward<_Pp>(__p)).first; } # endif // _LIBCPP_CXX03_LANG @@ -1070,7 +1152,7 @@ public: _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(const value_type& __v) { return __tree_.__emplace_unique(__v); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, const value_type& __v) { - return __tree_.__emplace_hint_unique(__p.__i_, __v); + return __tree_.__emplace_hint_unique(__p.__i_, __v).first; } # ifndef _LIBCPP_CXX03_LANG @@ -1079,25 +1161,21 @@ public: } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, value_type&& __v) { - return __tree_.__emplace_hint_unique(__p.__i_, std::move(__v)); + return __tree_.__emplace_hint_unique(__p.__i_, std::move(__v)).first; } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); } # endif template <class _InputIterator> - _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - insert(__e.__i_, *__f); + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + __tree_.__insert_range_unique(__first, __last); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<value_type> _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - insert(__end.__i_, std::forward<decltype(__element)>(__element)); - } + __tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range)); } # endif @@ -1105,17 +1183,13 @@ public: template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> try_emplace(const key_type& __k, _Args&&... __args) { - return __tree_.__emplace_unique_key_args( - __k, - std::piecewise_construct, - std::forward_as_tuple(__k), - std::forward_as_tuple(std::forward<_Args>(__args)...)); + return __tree_.__emplace_unique( + std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple(std::forward<_Args>(__args)...)); } template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> try_emplace(key_type&& __k, _Args&&... __args) { - return __tree_.__emplace_unique_key_args( - __k, + return __tree_.__emplace_unique( std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple(std::forward<_Args>(__args)...)); @@ -1124,9 +1198,8 @@ public: template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator try_emplace(const_iterator __h, const key_type& __k, _Args&&... __args) { return __tree_ - .__emplace_hint_unique_key_args( + .__emplace_hint_unique( __h.__i_, - __k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple(std::forward<_Args>(__args)...)) @@ -1136,9 +1209,8 @@ public: template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator try_emplace(const_iterator __h, key_type&& __k, _Args&&... __args) { return __tree_ - .__emplace_hint_unique_key_args( + .__emplace_hint_unique( __h.__i_, - __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple(std::forward<_Args>(__args)...)) @@ -1147,27 +1219,25 @@ public: template <class _Vp> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert_or_assign(const key_type& __k, _Vp&& __v) { - iterator __p = lower_bound(__k); - if (__p != end() && !key_comp()(__k, __p->first)) { - __p->second = std::forward<_Vp>(__v); - return std::make_pair(__p, false); - } - return std::make_pair(emplace_hint(__p, __k, std::forward<_Vp>(__v)), true); + auto __result = __tree_.__emplace_unique(__k, std::forward<_Vp>(__v)); + auto& [__iter, __inserted] = __result; + if (!__inserted) + __iter->second = std::forward<_Vp>(__v); + return __result; } template <class _Vp> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert_or_assign(key_type&& __k, _Vp&& __v) { - iterator __p = lower_bound(__k); - if (__p != end() && !key_comp()(__k, __p->first)) { - __p->second = std::forward<_Vp>(__v); - return std::make_pair(__p, false); - } - return std::make_pair(emplace_hint(__p, std::move(__k), std::forward<_Vp>(__v)), true); + auto __result = __tree_.__emplace_unique(std::move(__k), std::forward<_Vp>(__v)); + auto& [__iter, __inserted] = __result; + if (!__inserted) + __iter->second = std::forward<_Vp>(__v); + return __result; } template <class _Vp> _LIBCPP_HIDE_FROM_ABI iterator insert_or_assign(const_iterator __h, const key_type& __k, _Vp&& __v) { - auto [__r, __inserted] = __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, __k, std::forward<_Vp>(__v)); + auto [__r, __inserted] = __tree_.__emplace_hint_unique(__h.__i_, __k, std::forward<_Vp>(__v)); if (!__inserted) __r->second = std::forward<_Vp>(__v); @@ -1177,8 +1247,7 @@ public: template <class _Vp> _LIBCPP_HIDE_FROM_ABI iterator insert_or_assign(const_iterator __h, key_type&& __k, _Vp&& __v) { - auto [__r, __inserted] = - __tree_.__emplace_hint_unique_key_args(__h.__i_, __k, std::move(__k), std::forward<_Vp>(__v)); + auto [__r, __inserted] = __tree_.__emplace_hint_unique(__h.__i_, std::move(__k), std::forward<_Vp>(__v)); if (!__inserted) __r->second = std::forward<_Vp>(__v); @@ -1207,10 +1276,10 @@ public: "node_type with incompatible allocator passed to map::insert()"); return __tree_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __tree_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __tree_.template __node_handle_extract<node_type>(__it.__i_); } template <class _Compare2> @@ -1241,75 +1310,105 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(map& __m) _NOEXCEPT_(__is_nothrow_swappable_v<__base>) { __tree_.swap(__m.__tree_); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } # if _LIBCPP_STD_VER >= 14 - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __tree_.find(__k); } - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __tree_.find(__k); } # endif - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __tree_.__count_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __tree_.__count_unique(__k); + } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __tree_.__count_multi(__k); } # endif # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { + return __tree_.__lower_bound_unique(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { + return __tree_.__lower_bound_unique(__k); + } + + // The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to + // match multiple elements. # if _LIBCPP_STD_VER >= 14 - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { - return __tree_.lower_bound(__k); + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { + return __tree_.__lower_bound_multi(__k); } - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { - return __tree_.lower_bound(__k); + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { + return __tree_.__lower_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); } -# if _LIBCPP_STD_VER >= 14 - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { + return __tree_.__upper_bound_unique(__k); } - template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { - return __tree_.upper_bound(__k); + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { + return __tree_.__upper_bound_unique(__k); + } + +# if _LIBCPP_STD_VER >= 14 + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { + return __tree_.__upper_bound_multi(__k); + } + template <typename _K2, + enable_if_t<__is_transparent_v<_Compare, _K2> || __is_transparently_comparable_v<_Compare, key_type, _K2>, + int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { + return __tree_.__upper_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __tree_.__equal_range_unique(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __tree_.__equal_range_unique(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __tree_.__equal_range_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __tree_.__equal_range_multi(__k); } # endif @@ -1319,7 +1418,6 @@ private: typedef typename __base::__node_allocator __node_allocator; typedef typename __base::__node_pointer __node_pointer; typedef typename __base::__node_base_pointer __node_base_pointer; - typedef typename __base::__parent_pointer __parent_pointer; typedef __map_node_destructor<__node_allocator> _Dp; typedef unique_ptr<__node, _Dp> __node_holder; @@ -1327,6 +1425,8 @@ private: # ifdef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI __node_holder __construct_node_with_key(const key_type& __k); # endif + + friend struct __specialized_algorithm<_Algorithm::__for_each, __single_range<map> >; }; # if _LIBCPP_STD_VER >= 17 @@ -1334,8 +1434,8 @@ template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare, _Allocator>; @@ -1343,8 +1443,8 @@ map(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocat template <ranges::input_range _Range, class _Compare = less<__range_key_type<_Range>>, class _Allocator = allocator<__range_to_alloc_type<_Range>>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> map(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> map<__range_key_type<_Range>, __range_mapped_type<_Range>, _Compare, _Allocator>; # endif @@ -1353,16 +1453,15 @@ template <class _Key, class _Tp, class _Compare = less<remove_const_t<_Key>>, class _Allocator = allocator<pair<const _Key, _Tp>>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> -map(initializer_list<pair<_Key, _Tp>>, - _Compare = _Compare(), - _Allocator = _Allocator()) -> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> +map(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allocator()) + -> map<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>> map(_InputIterator, _InputIterator, _Allocator) -> map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -1370,44 +1469,44 @@ map(_InputIterator, _InputIterator, _Allocator) _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> map(from_range_t, _Range&&, _Allocator) -> map<__range_key_type<_Range>, __range_mapped_type<_Range>, less<__range_key_type<_Range>>, _Allocator>; # endif -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> -map(initializer_list<pair<_Key, _Tp>>, - _Allocator) -> map<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>; +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> +map(initializer_list<pair<_Key, _Tp>>, _Allocator) + -> map<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>; # endif -# ifndef _LIBCPP_CXX03_LANG +# if _LIBCPP_STD_VER >= 14 template <class _Key, class _Tp, class _Compare, class _Allocator> -map<_Key, _Tp, _Compare, _Allocator>::map(map&& __m, const allocator_type& __a) - : __tree_(std::move(__m.__tree_), typename __base::allocator_type(__a)) { - if (__a != __m.get_allocator()) { - const_iterator __e = cend(); - while (!__m.empty()) { - __tree_.__insert_unique_from_orphaned_node(__e.__i_, std::move(__m.__tree_.remove(__m.begin().__i_)->__value_)); - } +struct __specialized_algorithm<_Algorithm::__for_each, __single_range<map<_Key, _Tp, _Compare, _Allocator>>> { + using __map _LIBCPP_NODEBUG = map<_Key, _Tp, _Compare, _Allocator>; + + static const bool __has_algorithm = true; + + template <class _Map, class _Func, class _Proj> + _LIBCPP_HIDE_FROM_ABI static auto operator()(_Map&& __map, _Func __func, _Proj __proj) { + auto [_, __func2] = __specialized_algorithm<_Algorithm::__for_each, __single_range<typename __map::__base>>()( + __map.__tree_, std::move(__func), std::move(__proj)); + return std::make_pair(__map.end(), std::move(__func2)); } -} +}; +# endif +# ifndef _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Compare, class _Allocator> _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) { - return __tree_ - .__emplace_unique_key_args(__k, std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple()) + return __tree_.__emplace_unique(std::piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple()) .first->second; } template <class _Key, class _Tp, class _Compare, class _Allocator> _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](key_type&& __k) { - // TODO investigate this clang-tidy warning. - // NOLINTBEGIN(bugprone-use-after-move) return __tree_ - .__emplace_unique_key_args( - __k, std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple()) + .__emplace_unique(std::piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple()) .first->second; - // NOLINTEND(bugprone-use-after-move) } # else // _LIBCPP_CXX03_LANG @@ -1417,44 +1516,41 @@ typename map<_Key, _Tp, _Compare, _Allocator>::__node_holder map<_Key, _Tp, _Compare, _Allocator>::__construct_node_with_key(const key_type& __k) { __node_allocator& __na = __tree_.__node_alloc(); __node_holder __h(__node_traits::allocate(__na, 1), _Dp(__na)); - __node_traits::construct(__na, std::addressof(__h->__value_.first), __k); + __node_traits::construct(__na, std::addressof(__h->__get_value().first), __k); __h.get_deleter().__first_constructed = true; - __node_traits::construct(__na, std::addressof(__h->__value_.second)); + __node_traits::construct(__na, std::addressof(__h->__get_value().second)); __h.get_deleter().__second_constructed = true; return __h; } template <class _Key, class _Tp, class _Compare, class _Allocator> _Tp& map<_Key, _Tp, _Compare, _Allocator>::operator[](const key_type& __k) { - __parent_pointer __parent; - __node_base_pointer& __child = __tree_.__find_equal(__parent, __k); - __node_pointer __r = static_cast<__node_pointer>(__child); + auto [__parent, __child] = __tree_.__find_equal(__k); + __node_pointer __r = static_cast<__node_pointer>(__child); if (__child == nullptr) { __node_holder __h = __construct_node_with_key(__k); __tree_.__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get())); __r = __h.release(); } - return __r->__value_.second; + return __r->__get_value().second; } # endif // _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Compare, class _Allocator> _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) { - __parent_pointer __parent; - __node_base_pointer& __child = __tree_.__find_equal(__parent, __k); + auto [_, __child] = __tree_.__find_equal(__k); if (__child == nullptr) std::__throw_out_of_range("map::at: key not found"); - return static_cast<__node_pointer>(__child)->__value_.second; + return static_cast<__node_pointer>(__child)->__get_value().second; } template <class _Key, class _Tp, class _Compare, class _Allocator> const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const { - __parent_pointer __parent; - __node_base_pointer __child = __tree_.__find_equal(__parent, __k); + auto [_, __child] = __tree_.__find_equal(__k); if (__child == nullptr) std::__throw_out_of_range("map::at: key not found"); - return static_cast<__node_pointer>(__child)->__value_.second; + return static_cast<__node_pointer>(__child)->__get_value().second; } template <class _Key, class _Tp, class _Compare, class _Allocator> @@ -1637,22 +1733,17 @@ public: : multimap(from_range, std::forward<_Range>(__range), key_compare(), __a) {} # endif - _LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m) - : __tree_(__m.__tree_.value_comp(), - __alloc_traits::select_on_container_copy_construction(__m.__tree_.__alloc())) { - insert(__m.begin(), __m.end()); - } + _LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m) = default; _LIBCPP_HIDE_FROM_ABI multimap& operator=(const multimap& __m) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI multimap(multimap&& __m) noexcept(is_nothrow_move_constructible<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI multimap(multimap&& __m) = default; - _LIBCPP_HIDE_FROM_ABI multimap(multimap&& __m, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI multimap(multimap&& __m, const allocator_type& __a) : __tree_(std::move(__m.__tree_), __a) {} - _LIBCPP_HIDE_FROM_ABI multimap& - operator=(multimap&& __m) noexcept(is_nothrow_move_assignable<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI multimap& operator=(multimap&& __m) = default; _LIBCPP_HIDE_FROM_ABI multimap(initializer_list<value_type> __il, const key_compare& __comp = key_compare()) : __tree_(__vc(__comp)) { @@ -1671,7 +1762,8 @@ public: # endif _LIBCPP_HIDE_FROM_ABI multimap& operator=(initializer_list<value_type> __il) { - __tree_.__assign_multi(__il.begin(), __il.end()); + clear(); + insert(__il.begin(), __il.end()); return *this; } @@ -1679,37 +1771,42 @@ public: _LIBCPP_HIDE_FROM_ABI explicit multimap(const allocator_type& __a) : __tree_(typename __base::allocator_type(__a)) {} - _LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m, const allocator_type& __a) - : __tree_(__m.__tree_.value_comp(), typename __base::allocator_type(__a)) { - insert(__m.begin(), __m.end()); - } + _LIBCPP_HIDE_FROM_ABI multimap(const multimap& __m, const allocator_type& __a) : __tree_(__m.__tree_, __a) {} _LIBCPP_HIDE_FROM_ABI ~multimap() { static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), ""); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.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()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __tree_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__tree_.__alloc()); } - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return value_compare(__tree_.value_comp().key_comp()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + return allocator_type(__tree_.__alloc()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp().key_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { + return value_compare(__tree_.value_comp().key_comp()); + } # ifndef _LIBCPP_CXX03_LANG @@ -1751,17 +1848,13 @@ public: template <class _InputIterator> _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - __tree_.__emplace_hint_multi(__e.__i_, *__f); + __tree_.__insert_range_multi(__f, __l); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<value_type> _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - __tree_.__emplace_hint_multi(__end.__i_, std::forward<decltype(__element)>(__element)); - } + __tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range)); } # endif @@ -1783,10 +1876,10 @@ public: "node_type with incompatible allocator passed to multimap::insert()"); return __tree_.template __node_handle_insert_multi<node_type>(__hint.__i_, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __tree_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __tree_.template __node_handle_extract<node_type>(__it.__i_); } template <class _Compare2> @@ -1821,75 +1914,89 @@ public: __tree_.swap(__m.__tree_); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __tree_.find(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __tree_.find(__k); } # endif - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __tree_.__count_multi(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __tree_.__count_multi(__k); + } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __tree_.__count_multi(__k); } # endif # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { + return __tree_.__lower_bound_multi(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { + return __tree_.__lower_bound_multi(__k); + } + # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { + return __tree_.__lower_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { + return __tree_.__lower_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { + return __tree_.__upper_bound_multi(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { + return __tree_.__upper_bound_multi(__k); + } + # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { + return __tree_.__upper_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { + return __tree_.__upper_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __tree_.__equal_range_multi(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __tree_.__equal_range_multi(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __tree_.__equal_range_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __tree_.__equal_range_multi(__k); } # endif @@ -1901,6 +2008,8 @@ private: typedef __map_node_destructor<__node_allocator> _Dp; typedef unique_ptr<__node, _Dp> __node_holder; + + friend struct __specialized_algorithm<_Algorithm::__for_each, __single_range<multimap> >; }; # if _LIBCPP_STD_VER >= 17 @@ -1908,8 +2017,8 @@ template <class _InputIterator, class _Compare = less<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, _Compare, _Allocator>; @@ -1917,8 +2026,8 @@ multimap(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Al template <ranges::input_range _Range, class _Compare = less<__range_key_type<_Range>>, class _Allocator = allocator<__range_to_alloc_type<_Range>>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> multimap(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> multimap<__range_key_type<_Range>, __range_mapped_type<_Range>, _Compare, _Allocator>; # endif @@ -1927,16 +2036,15 @@ template <class _Key, class _Tp, class _Compare = less<remove_const_t<_Key>>, class _Allocator = allocator<pair<const _Key, _Tp>>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> -multimap(initializer_list<pair<_Key, _Tp>>, - _Compare = _Compare(), - _Allocator = _Allocator()) -> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> +multimap(initializer_list<pair<_Key, _Tp>>, _Compare = _Compare(), _Allocator = _Allocator()) + -> multimap<remove_const_t<_Key>, _Tp, _Compare, _Allocator>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>> multimap(_InputIterator, _InputIterator, _Allocator) -> multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -1944,26 +2052,30 @@ multimap(_InputIterator, _InputIterator, _Allocator) _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> multimap(from_range_t, _Range&&, _Allocator) -> multimap<__range_key_type<_Range>, __range_mapped_type<_Range>, less<__range_key_type<_Range>>, _Allocator>; # endif -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> -multimap(initializer_list<pair<_Key, _Tp>>, - _Allocator) -> multimap<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>; +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> +multimap(initializer_list<pair<_Key, _Tp>>, _Allocator) + -> multimap<remove_const_t<_Key>, _Tp, less<remove_const_t<_Key>>, _Allocator>; # endif -# ifndef _LIBCPP_CXX03_LANG +# if _LIBCPP_STD_VER >= 14 template <class _Key, class _Tp, class _Compare, class _Allocator> -multimap<_Key, _Tp, _Compare, _Allocator>::multimap(multimap&& __m, const allocator_type& __a) - : __tree_(std::move(__m.__tree_), typename __base::allocator_type(__a)) { - if (__a != __m.get_allocator()) { - const_iterator __e = cend(); - while (!__m.empty()) - __tree_.__insert_multi_from_orphaned_node(__e.__i_, std::move(__m.__tree_.remove(__m.begin().__i_)->__value_)); +struct __specialized_algorithm<_Algorithm::__for_each, __single_range<multimap<_Key, _Tp, _Compare, _Allocator>>> { + using __map _LIBCPP_NODEBUG = multimap<_Key, _Tp, _Compare, _Allocator>; + + static const bool __has_algorithm = true; + + template <class _Map, class _Func, class _Proj> + _LIBCPP_HIDE_FROM_ABI static auto operator()(_Map&& __map, _Func __func, _Proj __proj) { + auto [_, __func2] = __specialized_algorithm<_Algorithm::__for_each, __single_range<typename __map::__base>>()( + __map.__tree_, std::move(__func), std::move(__proj)); + return std::make_pair(__map.end(), std::move(__func2)); } -} +}; # endif template <class _Key, class _Tp, class _Compare, class _Allocator> diff --git a/lib/libcxx/include/math.h b/lib/libcxx/include/math.h @@ -429,6 +429,25 @@ using std::__math::isnormal; using std::__math::isunordered; # endif // _LIBCPP_MSVCRT +# if defined(_LIBCPP_MSVCRT) && _LIBCPP_STD_VER >= 20 +// MS UCRT incorrectly defines some functions in a way not working with integer types. Until C++20, this was worked +// around by -fdelayed-template-parsing. Since C++20, we can use standard feature "requires" instead. + +// TODO: Remove the workaround once UCRT fixes these functions. Note that this doesn't seem planned as of 2025-07 per +// https://developercommunity.visualstudio.com/t/10294165. + +using std::__math::__ucrt::isfinite; +using std::__math::__ucrt::isgreater; +using std::__math::__ucrt::isgreaterequal; +using std::__math::__ucrt::isinf; +using std::__math::__ucrt::isless; +using std::__math::__ucrt::islessequal; +using std::__math::__ucrt::islessgreater; +using std::__math::__ucrt::isnan; +using std::__math::__ucrt::isnormal; +using std::__math::__ucrt::isunordered; +# endif // defined(_LIBCPP_MSVCRT) && _LIBCPP_STD_VER >= 20 + // We have to provide double overloads for <math.h> to work on platforms that don't provide the full set of math // functions. To make the overload set work with multiple functions that take the same arguments, we make our overloads // templates. Functions are preferred over function templates during overload resolution, which means that our overload diff --git a/lib/libcxx/include/mdspan b/lib/libcxx/include/mdspan @@ -450,11 +450,7 @@ namespace std { # include <__config> # if _LIBCPP_STD_VER >= 23 -# include <__fwd/mdspan.h> // TODO(boomanaiden154): This is currently a - // non-standard extension to include - // std::dynamic_extent tracked by LWG issue 4275. - // This comment should be deleted or the include - // deleted upon resolution. +# include <__fwd/mdspan.h> # include <__fwd/span.h> # include <__mdspan/default_accessor.h> # include <__mdspan/extents.h> diff --git a/lib/libcxx/include/mutex b/lib/libcxx/include/mutex @@ -229,12 +229,12 @@ public: recursive_mutex& operator=(const recursive_mutex&) = delete; void lock(); - bool try_lock() _NOEXCEPT; + [[__nodiscard__]] bool try_lock() _NOEXCEPT; void unlock() _NOEXCEPT; typedef __libcpp_recursive_mutex_t* native_handle_type; - _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return &__m_; } }; class _LIBCPP_EXPORTED_FROM_ABI timed_mutex { @@ -251,14 +251,14 @@ public: public: void lock(); - bool try_lock() _NOEXCEPT; + [[__nodiscard__]] bool try_lock() _NOEXCEPT; template <class _Rep, class _Period> - _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { return try_lock_until(chrono::steady_clock::now() + __d); } template <class _Clock, class _Duration> - _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; unique_lock<mutex> __lk(__m_); bool __no_timeout = _Clock::now() < __t; @@ -288,14 +288,14 @@ public: recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; void lock(); - bool try_lock() _NOEXCEPT; + [[__nodiscard__]] bool try_lock() _NOEXCEPT; template <class _Rep, class _Period> - _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __d) { return try_lock_until(chrono::steady_clock::now() + __d); } template <class _Clock, class _Duration> - _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool try_lock_until(const chrono::time_point<_Clock, _Duration>& __t) { using namespace chrono; __thread_id __id = this_thread::get_id(); unique_lock<mutex> __lk(__m_); @@ -320,7 +320,7 @@ public: }; template <class _L0, class _L1> -_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { +[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { unique_lock<_L0> __u0(__l0, try_to_lock_t()); if (__u0.owns_lock()) { if (__l1.try_lock()) { @@ -335,7 +335,8 @@ _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1) { # ifndef _LIBCPP_CXX03_LANG template <class _L0, class _L1, class _L2, class... _L3> -_LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { +[[__nodiscard__]] _LIBCPP_NO_THREAD_SAFETY_ANALYSIS + _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { int __r = 0; unique_lock<_L0> __u0(__l0, try_to_lock); if (__u0.owns_lock()) { @@ -350,8 +351,11 @@ _LIBCPP_HIDE_FROM_ABI int try_lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3 # endif // _LIBCPP_CXX03_LANG +// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable +// the analysis inside the function. template <class _L0, class _L1> -_LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) + _LIBCPP_ACQUIRE_CAPABILITY(__l0, __l1) { while (true) { { unique_lock<_L0> __u0(__l0); @@ -375,7 +379,7 @@ _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1) { # ifndef _LIBCPP_CXX03_LANG template <class _L0, class _L1, class _L2, class... _L3> -void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { while (true) { switch (__i) { case 0: { @@ -410,8 +414,14 @@ void __lock_first(int __i, _L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { } } +// We're using unique_lock to implement the functions, which thread annotations don't support. So we have to disable +// the analysis inside the function. template <class _L0, class _L1, class _L2, class... _L3> -inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) { +_LIBCPP_NO_THREAD_SAFETY_ANALYSIS inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) +# if defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 2101 + _LIBCPP_ACQUIRE_CAPABILITY(__l0, __l1, __l2, __l3...) +# endif +{ std::__lock_first(0, __l0, __l1, __l2, __l3...); } @@ -469,17 +479,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(), ...); } @@ -494,6 +501,10 @@ _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS +# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23 +# include <typeinfo> +# endif + # if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20 # include <atomic> # include <concepts> @@ -507,7 +518,6 @@ _LIBCPP_POP_MACROS # include <stdexcept> # include <system_error> # include <type_traits> -# include <typeinfo> # endif #endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) diff --git a/lib/libcxx/include/optional b/lib/libcxx/include/optional @@ -21,6 +21,11 @@ namespace std { class optional; template<class T> + constexpr bool ranges::enable_view<optional<T>> = true; + template<class T> + constexpr auto format_kind<optional<T>> = range_format::disabled; + + template<class T> concept is-derived-from-optional = requires(const T& t) { // exposition only []<class U>(const optional<U>&){ }(t); }; @@ -102,6 +107,8 @@ namespace std { class optional { public: using value_type = T; + using iterator = implementation-defined; // see [optional.iterators] + using const_iterator = implementation-defined; // see [optional.iterators] // [optional.ctor], constructors constexpr optional() noexcept; @@ -112,7 +119,7 @@ namespace std { constexpr explicit optional(in_place_t, Args &&...); template<class U, class... Args> constexpr explicit optional(in_place_t, initializer_list<U>, Args &&...); - template<class U = T> + template<class U = remove_cv_t<T>> constexpr explicit(see-below) optional(U &&); template<class U> explicit(see-below) optional(const optional<U> &); // constexpr in C++20 @@ -126,7 +133,7 @@ namespace std { optional &operator=(nullopt_t) noexcept; // constexpr in C++20 constexpr optional &operator=(const optional &); constexpr optional &operator=(optional &&) noexcept(see below); - template<class U = T> optional &operator=(U &&); // constexpr in C++20 + template<class U = remove_cv_t<T>> optional &operator=(U &&); // constexpr in C++20 template<class U> optional &operator=(const optional<U> &); // constexpr in C++20 template<class U> optional &operator=(optional<U> &&); // constexpr in C++20 template<class... Args> T& emplace(Args &&...); // constexpr in C++20 @@ -135,6 +142,12 @@ namespace std { // [optional.swap], swap void swap(optional &) noexcept(see below ); // constexpr in C++20 + // [optional.iterators], iterator support + constexpr iterator begin() noexcept; + constexpr const_iterator begin() const noexcept; + constexpr iterator end() noexcept; + constexpr const_iterator end() const noexcept; + // [optional.observe], observers constexpr T const *operator->() const noexcept; constexpr T *operator->() noexcept; @@ -148,8 +161,8 @@ namespace std { constexpr T &value() &; constexpr T &&value() &&; constexpr const T &&value() const &&; - template<class U> constexpr T value_or(U &&) const &; - template<class U> constexpr T value_or(U &&) &&; + template<class U = remove_cv_t<T>> constexpr T value_or(U &&) const &; + template<class U = remove_cv_t<T>> constexpr T value_or(U &&) &&; // [optional.monadic], monadic operations template<class F> constexpr auto and_then(F&& f) &; // since C++23 @@ -173,6 +186,71 @@ namespace std { template<class T> optional(T) -> optional<T>; + template<class T> + class optional<T&> { // since C++26 + public: + using value_type = T; + using iterator = implementation-defined; // see [optional.ref.iterators] + + public: + // [optional.ref.ctor], constructors + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept : optional() {} + constexpr optional(const optional& rhs) noexcept = default; + + template<class Arg> + constexpr explicit optional(in_place_t, Arg&& arg); + template<class U> + constexpr explicit(see below) optional(U&& u) noexcept(see below); + template<class U> + constexpr explicit(see below) optional(optional<U>& rhs) noexcept(see below); + template<class U> + constexpr explicit(see below) optional(const optional<U>& rhs) noexcept(see below); + template<class U> + constexpr explicit(see below) optional(optional<U>&& rhs) noexcept(see below); + template<class U> + constexpr explicit(see below) optional(const optional<U>&& rhs) noexcept(see below); + + constexpr ~optional() = default; + + // [optional.ref.assign], assignment + constexpr optional& operator=(nullopt_t) noexcept; + constexpr optional& operator=(const optional& rhs) noexcept = default; + + template<class U> constexpr T& emplace(U&& u) noexcept(see below); + + // [optional.ref.swap], swap + constexpr void swap(optional& rhs) noexcept; + + // [optional.ref.iterators], iterator support + constexpr iterator begin() const noexcept; + constexpr iterator end() const noexcept; + + // [optional.ref.observe], observers + constexpr T* operator->() const noexcept; + constexpr T& operator*() const noexcept; + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr T& value() const; // freestanding-deleted + template<class U = remove_cv_t<T>> + constexpr remove_cv_t<T> value_or(U&& u) const; + + // [optional.ref.monadic], monadic operations + template<class F> constexpr auto and_then(F&& f) const; + template<class F> constexpr optional<invoke_result_t<F, T&>> transform(F&& f) const; + template<class F> constexpr optional or_else(F&& f) const; + + // [optional.ref.mod], modifiers + constexpr void reset() noexcept; + + private: + T* val = nullptr; // exposition only + + // [optional.ref.expos], exposition only helper functions + template<class U> + constexpr void convert-ref-init-val(U&& u); // exposition only + }; + } // namespace std */ @@ -186,13 +264,19 @@ namespace std { # include <__compare/three_way_comparable.h> # include <__concepts/invocable.h> # include <__config> +# include <__cstddef/ptrdiff_t.h> # include <__exception/exception.h> +# include <__format/range_format.h> # include <__functional/hash.h> # include <__functional/invoke.h> # include <__functional/unary_function.h> # include <__fwd/functional.h> +# include <__iterator/bounded_iter.h> +# include <__iterator/wrap_iter.h> # include <__memory/addressof.h> # include <__memory/construct_at.h> +# include <__ranges/enable_borrowed_range.h> +# include <__ranges/enable_view.h> # include <__tuple/sfinae_helpers.h> # include <__type_traits/add_pointer.h> # include <__type_traits/conditional.h> @@ -200,6 +284,7 @@ namespace std { # include <__type_traits/decay.h> # include <__type_traits/disjunction.h> # include <__type_traits/enable_if.h> +# include <__type_traits/integral_constant.h> # include <__type_traits/invoke.h> # include <__type_traits/is_array.h> # include <__type_traits/is_assignable.h> @@ -207,11 +292,11 @@ namespace std { # include <__type_traits/is_convertible.h> # include <__type_traits/is_core_convertible.h> # include <__type_traits/is_destructible.h> +# include <__type_traits/is_function.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_object.h> # include <__type_traits/is_reference.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_scalar.h> # include <__type_traits/is_swappable.h> @@ -220,6 +305,7 @@ namespace std { # include <__type_traits/is_trivially_destructible.h> # include <__type_traits/is_trivially_relocatable.h> # include <__type_traits/negation.h> +# include <__type_traits/reference_constructs_from_temporary.h> # include <__type_traits/remove_const.h> # include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> @@ -255,7 +341,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_optional_access& operator=(const bad_optional_access&) _NOEXCEPT = default; // Get the key function ~bad_optional_access() into the dylib ~bad_optional_access() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; } // namespace std @@ -358,7 +444,7 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> { using value_type = _Tp; using __base::__base; - _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return this->__engaged_; } _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() & noexcept { return this->__val_; } _LIBCPP_HIDE_FROM_ABI constexpr const value_type& __get() const& noexcept { return this->__val_; } @@ -390,58 +476,60 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> { __construct(std::forward<_That>(__opt).__get()); } } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void + __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) { + using std::swap; + if (this->has_value() == __rhs.has_value()) { + if (this->has_value()) + swap(this->__get(), __rhs.__get()); + } else { + if (this->has_value()) { + __rhs.__construct(std::move(this->__get())); + this->reset(); + } else { + this->__construct(std::move(__rhs.__get())); + __rhs.reset(); + } + } + } }; -// optional<T&> is currently required to be ill-formed. However, it may -// be allowed in the future. For this reason, it has already been implemented -// to ensure we can make the change in an ABI-compatible manner. template <class _Tp> struct __optional_storage_base<_Tp, true> { using value_type = _Tp; using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>; __raw_type* __value_; + _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {} + template <class _Up> - static _LIBCPP_HIDE_FROM_ABI constexpr bool __can_bind_reference() { - using _RawUp = __libcpp_remove_reference_t<_Up>; - using _UpPtr = _RawUp*; - using _RawTp = __libcpp_remove_reference_t<_Tp>; - using _TpPtr = _RawTp*; - using _CheckLValueArg = - integral_constant<bool, - (is_lvalue_reference<_Up>::value && is_convertible<_UpPtr, _TpPtr>::value) || - is_same<_RawUp, reference_wrapper<_RawTp>>::value || - is_same<_RawUp, reference_wrapper<__remove_const_t<_RawTp>>>::value >; - return (is_lvalue_reference<_Tp>::value && _CheckLValueArg::value) || - (is_rvalue_reference<_Tp>::value && !is_lvalue_reference<_Up>::value && - is_convertible<_UpPtr, _TpPtr>::value); + _LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) noexcept { + _Tp& __r(std::forward<_Up>(__val)); + __value_ = std::addressof(__r); } - _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {} - template <class _UArg> - _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) - : __value_(std::addressof(__uarg)) { - static_assert(__can_bind_reference<_UArg>(), - "Attempted to construct a reference element in tuple from a " + _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) { + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, + "Attempted to construct a reference element in optional from a " "possible temporary"); + __convert_init_ref_val(std::forward<_UArg>(__uarg)); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; } - _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; } - - _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const& noexcept { return *__value_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; } - _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() const&& noexcept { return std::forward<value_type>(*__value_); } + _LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; } template <class _UArg> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) { _LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage"); - static_assert(__can_bind_reference<_UArg>(), + static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>, "Attempted to construct a reference element in tuple from a " "possible temporary"); - __value_ = std::addressof(__val); + __convert_init_ref_val(std::forward<_UArg>(__val)); } template <class _That> @@ -462,9 +550,13 @@ struct __optional_storage_base<_Tp, true> { __construct(std::forward<_That>(__opt).__get()); } } + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept { + std::swap(__value_, __rhs.__value_); + } }; -template <class _Tp, bool = is_trivially_copy_constructible<_Tp>::value> +template <class _Tp, bool = is_trivially_copy_constructible_v<_Tp> || is_lvalue_reference_v<_Tp>> struct __optional_copy_base : __optional_storage_base<_Tp> { using __optional_storage_base<_Tp>::__optional_storage_base; }; @@ -484,7 +576,7 @@ struct __optional_copy_base<_Tp, false> : __optional_storage_base<_Tp> { _LIBCPP_HIDE_FROM_ABI __optional_copy_base& operator=(__optional_copy_base&&) = default; }; -template <class _Tp, bool = is_trivially_move_constructible<_Tp>::value> +template <class _Tp, bool = is_trivially_move_constructible_v<_Tp> || is_lvalue_reference_v<_Tp>> struct __optional_move_base : __optional_copy_base<_Tp> { using __optional_copy_base<_Tp>::__optional_copy_base; }; @@ -507,8 +599,9 @@ struct __optional_move_base<_Tp, false> : __optional_copy_base<_Tp> { }; template <class _Tp, - bool = is_trivially_destructible<_Tp>::value && is_trivially_copy_constructible<_Tp>::value && - is_trivially_copy_assignable<_Tp>::value> + bool = (is_trivially_destructible_v<_Tp> && is_trivially_copy_constructible_v<_Tp> && + is_trivially_copy_assignable_v<_Tp>) || + is_lvalue_reference_v<_Tp>> struct __optional_copy_assign_base : __optional_move_base<_Tp> { using __optional_move_base<_Tp>::__optional_move_base; }; @@ -531,8 +624,9 @@ struct __optional_copy_assign_base<_Tp, false> : __optional_move_base<_Tp> { }; template <class _Tp, - bool = is_trivially_destructible<_Tp>::value && is_trivially_move_constructible<_Tp>::value && - is_trivially_move_assignable<_Tp>::value> + bool = (is_trivially_destructible_v<_Tp> && is_trivially_move_constructible_v<_Tp> && + is_trivially_move_assignable_v<_Tp>) || + is_lvalue_reference_v<_Tp>> struct __optional_move_assign_base : __optional_copy_assign_base<_Tp> { using __optional_copy_assign_base<_Tp>::__optional_copy_assign_base; }; @@ -561,12 +655,24 @@ using __optional_sfinae_ctor_base_t _LIBCPP_NODEBUG = template <class _Tp> using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG = - __sfinae_assign_base< (is_copy_constructible<_Tp>::value && is_copy_assignable<_Tp>::value), - (is_move_constructible<_Tp>::value && is_move_assignable<_Tp>::value) >; + __sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>) || is_lvalue_reference_v<_Tp>, + (is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>) || is_lvalue_reference_v<_Tp>>; template <class _Tp> class optional; +# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR +template <class _Tp> +constexpr bool ranges::enable_view<optional<_Tp>> = true; + +template <class _Tp> +constexpr range_format format_kind<optional<_Tp>> = range_format::disabled; + +template <class _Tp> +constexpr bool ranges::enable_borrowed_range<optional<_Tp&>> = true; + +# endif + # if _LIBCPP_STD_VER >= 20 template <class _Tp> @@ -579,29 +685,150 @@ struct __is_std_optional : false_type {}; template <class _Tp> struct __is_std_optional<optional<_Tp>> : true_type {}; +template <class _Tp, class... _Args> +inline constexpr bool __is_constructible_for_optional_v = is_constructible_v<_Tp, _Args...>; + +template <class _Tp, class... _Args> +struct __is_constructible_for_optional : bool_constant<__is_constructible_for_optional_v<_Tp, _Args...>> {}; + +template <class _Tp, class _Up, class... _Args> +inline constexpr bool __is_constructible_for_optional_initializer_list_v = + is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>; + +# if _LIBCPP_STD_VER >= 26 +template <class _Tp, class... _Args> +inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Args...> = false; +template <class _Tp, class _Arg> +inline constexpr bool __is_constructible_for_optional_v<_Tp&, _Arg> = + is_constructible_v<_Tp&, _Arg> && !reference_constructs_from_temporary_v<_Tp&, _Arg>; + +template <class _Tp, class _Up, class... _Args> +inline constexpr bool __is_constructible_for_optional_initializer_list_v<_Tp&, _Up, _Args...> = false; +# endif + +template <class _Tp, class = void> +struct __optional_iterator {}; + +# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + +template <class _Tp> +struct __optional_iterator<_Tp, enable_if_t<is_object_v<_Tp>>> { +private: + using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; + using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>; + +public: +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + using iterator = __bounded_iter<__wrap_iter<__pointer>>; + using const_iterator = __bounded_iter<__wrap_iter<__const_pointer>>; +# else + using iterator = __wrap_iter<__pointer>; + using const_iterator = __wrap_iter<__const_pointer>; +# endif + + // [optional.iterators], iterator support + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept { + auto& __derived_self = static_cast<optional<_Tp>&>(*this); + auto* __ptr = std::addressof(__derived_self.__get()); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter( + __wrap_iter<__pointer>(__ptr), + __wrap_iter<__pointer>(__ptr), + __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)); +# else + return iterator(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept { + auto& __derived_self = static_cast<const optional<_Tp>&>(*this); + auto* __ptr = std::addressof(__derived_self.__get()); + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter( + __wrap_iter<__const_pointer>(__ptr), + __wrap_iter<__const_pointer>(__ptr), + __wrap_iter<__const_pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)); +# else + return const_iterator(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept { + return begin() + (static_cast<optional<_Tp>&>(*this).has_value() ? 1 : 0); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept { + return begin() + (static_cast<const optional<_Tp>&>(*this).has_value() ? 1 : 0); + } +}; + +template <class _Tp> +struct __optional_iterator<_Tp&, enable_if_t<is_object_v<_Tp> && !__is_unbounded_array_v<_Tp> >> { +private: + using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>; + +public: +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + using iterator = __bounded_iter<__wrap_iter<__pointer>>; +# else + using iterator = __wrap_iter<__pointer>; +# endif + + // [optional.ref.iterators], iterator support + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept { + auto& __derived_self = static_cast<const optional<_Tp&>&>(*this); + auto* __ptr = __derived_self.has_value() ? std::addressof(__derived_self.__get()) : nullptr; + +# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL + return std::__make_bounded_iter( + __wrap_iter<__pointer>(__ptr), + __wrap_iter<__pointer>(__ptr), + __wrap_iter<__pointer>(__ptr) + (__derived_self.has_value() ? 1 : 0)); +# else + return iterator(__ptr); +# endif + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept { + return begin() + (static_cast<const optional<_Tp&>&>(*this).has_value() ? 1 : 0); + } +}; + +# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR + template <class _Tp> class _LIBCPP_DECLSPEC_EMPTY_BASES optional : private __optional_move_assign_base<_Tp>, private __optional_sfinae_ctor_base_t<_Tp>, - private __optional_sfinae_assign_base_t<_Tp> { + private __optional_sfinae_assign_base_t<_Tp>, + public __optional_iterator<_Tp> { using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>; public: - using value_type = _Tp; + using value_type = __libcpp_remove_reference_t<_Tp>; using __trivially_relocatable _LIBCPP_NODEBUG = conditional_t<__libcpp_is_trivially_relocatable<_Tp>::value, optional, void>; - using __replaceable _LIBCPP_NODEBUG = conditional_t<__is_replaceable_v<_Tp>, optional, void>; private: - // Disable the reference extension using this static assert. - static_assert(!is_same_v<__remove_cvref_t<value_type>, in_place_t>, + static_assert(!is_same_v<__remove_cvref_t<_Tp>, in_place_t>, "instantiation of optional with in_place_t is ill-formed"); - static_assert(!is_same_v<__remove_cvref_t<value_type>, nullopt_t>, - "instantiation of optional with nullopt_t is ill-formed"); - static_assert(!is_reference_v<value_type>, "instantiation of optional with a reference type is ill-formed"); - static_assert(is_destructible_v<value_type>, "instantiation of optional with a non-destructible type is ill-formed"); - static_assert(!is_array_v<value_type>, "instantiation of optional with an array type is ill-formed"); + static_assert(!is_same_v<__remove_cvref_t<_Tp>, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed"); +# if _LIBCPP_STD_VER >= 26 + static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed"); +# else + static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed"); +# endif + static_assert(is_destructible_v<_Tp>, "instantiation of optional with a non-destructible type is ill-formed"); + static_assert(!is_array_v<_Tp>, "instantiation of optional with an array type is ill-formed"); + +# if _LIBCPP_STD_VER >= 26 + template <class _Up> + constexpr static bool __libcpp_opt_ref_ctor_deleted = + is_lvalue_reference_v<_Tp> && reference_constructs_from_temporary_v<_Tp, _Up>; +# endif // LWG2756: conditionally explicit conversion from _Up struct _CheckOptionalArgsConstructor { @@ -674,45 +901,131 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr optional(optional&&) = default; _LIBCPP_HIDE_FROM_ABI constexpr optional(nullopt_t) noexcept {} - template <class _InPlaceT, - class... _Args, - enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, is_constructible<value_type, _Args...>>::value, int> = 0> + template < + class _InPlaceT, + class... _Args, + enable_if_t<_And<_IsSame<_InPlaceT, in_place_t>, __is_constructible_for_optional<_Tp, _Args...>>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_InPlaceT, _Args&&... __args) : __base(in_place, std::forward<_Args>(__args)...) {} template <class _Up, class... _Args, - enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _Args...>, int> = 0> + enable_if_t<__is_constructible_for_optional_initializer_list_v<_Tp, _Up, _Args...>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args) : __base(in_place, __il, std::forward<_Args>(__args)...) {} - template <class _Up = value_type, - enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {} + template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>) +# endif + : __base(in_place, std::forward<_Up>(__v)) { + } - template <class _Up, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {} + template <class _Up = remove_cv_t<_Tp>, + enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> + _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>) +# endif + : __base(in_place, std::forward<_Up>(__v)) { + } // LWG2756: conditionally explicit conversion from const optional<_Up>& template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) +# endif + { this->__construct_from(__v); } template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) +# endif + { this->__construct_from(__v); } // LWG2756: conditionally explicit conversion from optional<_Up>&& template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>) +# endif + { this->__construct_from(std::move(__v)); } template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>) +# endif + { this->__construct_from(std::move(__v)); } + // deleted optional<T&> constructors and additional optional<T&> constructors +# if _LIBCPP_STD_VER >= 26 + // optional(U&&) + template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + optional(_Up&&) = delete; + + template <class _Up = remove_cv_t<_Tp>, + enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + explicit optional(_Up&&) = delete; + + // optional(optional<U>& rhs) + template <class _Up> + requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> + _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up&, _Tp&>) + optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { + this->__construct_from(__rhs); + } + + template <class _Up> + requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> + constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete; + + // optional(const optional<U>&) + template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + optional(const optional<_Up>&) = delete; + + template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + explicit optional(const optional<_Up>&) = delete; + + // optional(optional<U>&&) + template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + optional(optional<_Up>&&) = delete; + + template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0> + requires __libcpp_opt_ref_ctor_deleted<_Up> + explicit optional(optional<_Up>&&) = delete; + + // optional(const optional<U>&&) + template <class _Up> + requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<const _Up, _Tp&>) + optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { + this->__construct_from(std::move(__v)); + } + + template <class _Up> + requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v<remove_cvref_t<_Tp>, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete; +# endif + # if _LIBCPP_STD_VER >= 23 template <class _Tag, class _Fp, @@ -731,11 +1044,12 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr optional& operator=(optional&&) = default; // LWG2756 - template <class _Up = value_type, + template <class _Up = remove_cv_t<_Tp>, enable_if_t<_And<_IsNotSame<__remove_cvref_t<_Up>, optional>, - _Or<_IsNotSame<__remove_cvref_t<_Up>, value_type>, _Not<is_scalar<value_type>>>, - is_constructible<value_type, _Up>, - is_assignable<value_type&, _Up>>::value, + _Or<_IsNotSame<__remove_cvref_t<_Up>, _Tp>, _Not<is_scalar<_Tp>>>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + is_object<_Tp>>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(_Up&& __v) { if (this->has_value()) @@ -759,8 +1073,12 @@ public: return *this; } - template <class... _Args, enable_if_t<is_constructible_v<value_type, _Args...>, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) { + template <class... _Args, enable_if_t<__is_constructible_for_optional_v<_Tp, _Args...>, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) +# if _LIBCPP_STD_VER >= 26 + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp, _Args...>) +# endif + { reset(); this->__construct(std::forward<_Args>(__args)...); return this->__get(); @@ -768,56 +1086,72 @@ public: template <class _Up, class... _Args, - enable_if_t<is_constructible_v<value_type, initializer_list<_Up>&, _Args...>, int> = 0> + enable_if_t<__is_constructible_for_optional_initializer_list_v<_Tp, _Up, _Args...>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) { reset(); this->__construct(__il, std::forward<_Args>(__args)...); return this->__get(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void - swap(optional& __opt) noexcept(is_nothrow_move_constructible_v<value_type> && is_nothrow_swappable_v<value_type>) { - if (this->has_value() == __opt.has_value()) { - using std::swap; - if (this->has_value()) - swap(this->__get(), __opt.__get()); - } else { - if (this->has_value()) { - __opt.__construct(std::move(this->__get())); - reset(); - } else { - this->__construct(std::move(__opt.__get())); - __opt.reset(); - } - } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional& __opt) noexcept( + (is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) +# if _LIBCPP_STD_VER >= 26 + || is_lvalue_reference_v<_Tp> +# endif + ) { + this->__swap(__opt); } - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type const> operator->() const noexcept { + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); return std::addressof(this->__get()); } - _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<value_type> operator->() noexcept { + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); return std::addressof(this->__get()); } - _LIBCPP_HIDE_FROM_ABI constexpr const value_type& operator*() const& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); return this->__get(); } - _LIBCPP_HIDE_FROM_ABI constexpr value_type& operator*() & noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); return this->__get(); } - _LIBCPP_HIDE_FROM_ABI constexpr value_type&& operator*() && noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); return std::move(this->__get()); } - _LIBCPP_HIDE_FROM_ABI constexpr const value_type&& operator*() const&& noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); return std::move(this->__get()); } @@ -827,48 +1161,73 @@ public: using __base::__get; using __base::has_value; - _LIBCPP_HIDE_FROM_ABI constexpr value_type const& value() const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { if (!this->has_value()) std::__throw_bad_optional_access(); return this->__get(); } - _LIBCPP_HIDE_FROM_ABI constexpr value_type& value() & { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { if (!this->has_value()) std::__throw_bad_optional_access(); return this->__get(); } - _LIBCPP_HIDE_FROM_ABI constexpr value_type&& value() && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { if (!this->has_value()) std::__throw_bad_optional_access(); return std::move(this->__get()); } - _LIBCPP_HIDE_FROM_ABI constexpr value_type const&& value() const&& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + { if (!this->has_value()) std::__throw_bad_optional_access(); return std::move(this->__get()); } - template <class _Up> - _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) const& { - static_assert(is_copy_constructible_v<value_type>, "optional<T>::value_or: T must be copy constructible"); - static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T"); - return this->has_value() ? this->__get() : static_cast<value_type>(std::forward<_Up>(__v)); + template <class _Up = remove_cv_t<_Tp>> +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& { + static_assert(is_copy_constructible_v<_Tp>, "optional<T>::value_or: T must be copy constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T"); + return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v)); } - template <class _Up> - _LIBCPP_HIDE_FROM_ABI constexpr value_type value_or(_Up&& __v) && { - static_assert(is_move_constructible_v<value_type>, "optional<T>::value_or: T must be move constructible"); - static_assert(is_convertible_v<_Up, value_type>, "optional<T>::value_or: U must be convertible to T"); - return this->has_value() ? std::move(this->__get()) : static_cast<value_type>(std::forward<_Up>(__v)); + template <class _Up = remove_cv_t<_Tp>> +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && { + static_assert(is_move_constructible_v<_Tp>, "optional<T>::value_or: T must be move constructible"); + static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T"); + return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(std::forward<_Up>(__v)); } # if _LIBCPP_STD_VER >= 23 template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { - using _Up = invoke_result_t<_Func, value_type&>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & { + using _Up = invoke_result_t<_Func, _Tp&>; static_assert(__is_std_optional<remove_cvref_t<_Up>>::value, "Result of f(value()) must be a specialization of std::optional"); if (*this) @@ -877,8 +1236,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { - using _Up = invoke_result_t<_Func, const value_type&>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& { + using _Up = invoke_result_t<_Func, const _Tp&>; static_assert(__is_std_optional<remove_cvref_t<_Up>>::value, "Result of f(value()) must be a specialization of std::optional"); if (*this) @@ -887,8 +1249,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { - using _Up = invoke_result_t<_Func, value_type&&>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && { + using _Up = invoke_result_t<_Func, _Tp&&>; static_assert(__is_std_optional<remove_cvref_t<_Up>>::value, "Result of f(std::move(value())) must be a specialization of std::optional"); if (*this) @@ -897,8 +1262,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { - using _Up = invoke_result_t<_Func, const value_type&&>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& { + using _Up = invoke_result_t<_Func, const _Tp&&>; static_assert(__is_std_optional<remove_cvref_t<_Up>>::value, "Result of f(std::move(value())) must be a specialization of std::optional"); if (*this) @@ -907,8 +1275,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { - using _Up = remove_cv_t<invoke_result_t<_Func, value_type&>>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & { + using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>; static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); @@ -919,8 +1290,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { - using _Up = remove_cv_t<invoke_result_t<_Func, const value_type&>>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& { + using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>; static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); @@ -931,8 +1305,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { - using _Up = remove_cv_t<invoke_result_t<_Func, value_type&&>>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && { + using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>; static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); @@ -943,8 +1320,11 @@ public: } template <class _Func> - _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { - using _Up = remove_cvref_t<invoke_result_t<_Func, const value_type&&>>; +# if _LIBCPP_STD_VER >= 26 + requires(is_object_v<_Tp>) +# endif + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& { + using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>; static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array"); static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t"); static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t"); @@ -955,8 +1335,11 @@ public: } template <invocable _Func> - _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const& - requires is_copy_constructible_v<value_type> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const& + requires is_copy_constructible_v<_Tp> +# if _LIBCPP_STD_VER >= 26 + && (is_object_v<_Tp>) +# endif { static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>, "Result of f() should be the same type as this optional"); @@ -966,8 +1349,11 @@ public: } template <invocable _Func> - _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) && - requires is_move_constructible_v<value_type> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) && + requires is_move_constructible_v<_Tp> +# if _LIBCPP_STD_VER >= 26 + && (is_object_v<_Tp>) +# endif { static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>, "Result of f() should be the same type as this optional"); @@ -978,6 +1364,78 @@ public: # endif // _LIBCPP_STD_VER >= 23 using __base::reset; + +// optional<T&> overloads +# if _LIBCPP_STD_VER >= 26 + + _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept + requires(is_lvalue_reference_v<_Tp>) + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value"); + return std::addressof(this->__get()); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept + requires(is_lvalue_reference_v<_Tp>) + { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value"); + return this->__get(); + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const + requires(is_lvalue_reference_v<_Tp>) + { + if (!this->has_value()) + std::__throw_bad_optional_access(); + return this->__get(); + } + + template <class _Up = remove_cvref_t<_Tp>> + requires(is_lvalue_reference_v<_Tp> && is_object_v<__libcpp_remove_reference_t<_Tp>> && + !is_array_v<__libcpp_remove_reference_t<_Tp>>) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decay_t<_Tp> value_or(_Up&& __v) const { + static_assert( + is_constructible_v<remove_cvref_t<_Tp>, _Tp&>, "optional<T&>::value_or: remove_cv_t<T> must be constructible"); + static_assert( + is_convertible_v<_Up, remove_cvref_t<_Tp>>, "optional<T&>::value_or: U must be convertible to remove_cv_t<T>"); + return this->has_value() ? this->__get() : static_cast<remove_cvref_t<_Tp>>(std::forward<_Up>(__v)); + } + + template <class _Func> + requires(is_lvalue_reference_v<_Tp>) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const { + using _Up = invoke_result_t<_Func, _Tp&>; + static_assert(__is_std_optional<remove_cvref_t<_Up>>::value, + "Result of f(value()) must be a specialization of std::optional"); + if (*this) + return std::invoke(std::forward<_Func>(__f), value()); + return remove_cvref_t<_Up>(); + } + + template <class _Func> + requires(is_lvalue_reference_v<_Tp>) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<remove_cv_t<invoke_result_t<_Func, _Tp&>>> + transform(_Func&& __f) const { + using _Up = remove_cvref_t<invoke_result_t<_Func, _Tp&>>; + static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array"); + static_assert(!is_same_v<_Up, in_place_t>, "Result of f(value()) should not be std::in_place_t"); + static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(value()) should not be std::nullopt_t"); + static_assert(is_object_v<_Up>, "Result of f(value()) should be an object type"); + if (*this) + return optional<_Up>(__optional_construct_from_invoke_tag{}, std::forward<_Func>(__f), value()); + return optional<_Up>(); + } + + template <invocable _Func> + requires(is_lvalue_reference_v<_Tp>) + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const { + static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>, + "Result of f() should be the same type as this optional"); + if (*this) + return *this; + return std::forward<_Func>(__f)(); + } +# endif }; template <class _Tp> @@ -1154,7 +1612,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x == __v : false; + if (__x.has_value()) + return *__x == __v; + return false; } template < @@ -1163,7 +1623,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v == *__x : false; + if (__x.has_value()) + return __v == *__x; + return false; } template < @@ -1172,7 +1634,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x != __v : true; + if (__x.has_value()) + return *__x != __v; + return true; } template < @@ -1181,7 +1645,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v != *__x : true; + if (__x.has_value()) + return __v != *__x; + return true; } template < class _Tp, @@ -1189,7 +1655,9 @@ template < class _Tp, enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x < __v : true; + if (__x.has_value()) + return *__x < __v; + return true; } template < class _Tp, @@ -1197,7 +1665,9 @@ template < class _Tp, enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v < *__x : false; + if (__x.has_value()) + return __v < *__x; + return false; } template < @@ -1206,7 +1676,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x <= __v : true; + if (__x.has_value()) + return *__x <= __v; + return true; } template < @@ -1215,7 +1687,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v <= *__x : false; + if (__x.has_value()) + return __v <= *__x; + return false; } template < class _Tp, @@ -1223,7 +1697,9 @@ template < class _Tp, enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x > __v : false; + if (__x.has_value()) + return *__x > __v; + return false; } template < class _Tp, @@ -1231,7 +1707,9 @@ template < class _Tp, enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v > *__x : true; + if (__x.has_value()) + return __v > *__x; + return true; } template < @@ -1240,7 +1718,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) { - return static_cast<bool>(__x) ? *__x >= __v : false; + if (__x.has_value()) + return *__x >= __v; + return false; } template < @@ -1249,7 +1729,9 @@ template < enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>, int> = 0> _LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) { - return static_cast<bool>(__x) ? __v >= *__x : true; + if (__x.has_value()) + return __v >= *__x; + return true; } # if _LIBCPP_STD_VER >= 20 @@ -1264,23 +1746,36 @@ operator<=>(const optional<_Tp>& __x, const _Up& __v) { # endif // _LIBCPP_STD_VER >= 20 template <class _Tp, enable_if_t< is_move_constructible_v<_Tp> && is_swappable_v<_Tp>, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) { +inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional<_Tp>& __x, optional<_Tp>& __y) noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } -template <class _Tp> -_LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) { +struct __make_optional_barrier_tag { + explicit __make_optional_barrier_tag() = default; +}; + +template < +# if _LIBCPP_STD_VER >= 26 + __make_optional_barrier_tag = __make_optional_barrier_tag{}, +# endif + class _Tp, + enable_if_t<is_constructible_v<decay_t<_Tp>, _Tp>, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<decay_t<_Tp>> make_optional(_Tp&& __v) { return optional<decay_t<_Tp>>(std::forward<_Tp>(__v)); } -template <class _Tp, class... _Args> -_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) { +template <class _Tp, class... _Args, enable_if_t<__is_constructible_for_optional_v<_Tp, _Args...>, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(_Args&&... __args) { return optional<_Tp>(in_place, std::forward<_Args>(__args)...); } -template <class _Tp, class _Up, class... _Args> -_LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> make_optional(initializer_list<_Up> __il, _Args&&... __args) { +template <class _Tp, + class _Up, + class... _Args, + enable_if_t<__is_constructible_for_optional_initializer_list_v<_Tp, _Up, _Args...>, int> = 0> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional<_Tp> +make_optional(initializer_list<_Up> __il, _Args&&... __args) { return optional<_Tp>(in_place, __il, std::forward<_Args>(__args)...); } @@ -1291,7 +1786,7 @@ struct hash< __enable_hash_helper<optional<_Tp>, remove_const_t<_Tp>> > { _LIBCPP_DEPRECATED_IN_CXX17 typedef size_t result_type; # endif - _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const optional<_Tp>& __opt) const { return static_cast<bool>(__opt) ? hash<remove_const_t<_Tp>>()(*__opt) : 0; } }; diff --git a/lib/libcxx/include/print b/lib/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/lib/libcxx/include/queue b/lib/libcxx/include/queue @@ -376,12 +376,12 @@ public: # endif // _LIBCPP_CXX03_LANG [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const { return c.empty(); } - _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } - _LIBCPP_HIDE_FROM_ABI reference front() { return c.front(); } - _LIBCPP_HIDE_FROM_ABI const_reference front() const { return c.front(); } - _LIBCPP_HIDE_FROM_ABI reference back() { return c.back(); } - _LIBCPP_HIDE_FROM_ABI const_reference back() const { return c.back(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference front() { return c.front(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference front() const { return c.front(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference back() { return c.back(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference back() const { return c.back(); } _LIBCPP_HIDE_FROM_ABI void push(const value_type& __v) { c.push_back(__v); } # ifndef _LIBCPP_CXX03_LANG @@ -437,19 +437,19 @@ public: }; # if _LIBCPP_STD_VER >= 17 -template <class _Container, class = enable_if_t<!__is_allocator<_Container>::value> > +template <class _Container, class = enable_if_t<!__is_allocator_v<_Container>>> queue(_Container) -> queue<typename _Container::value_type, _Container>; template <class _Container, class _Alloc, - class = enable_if_t<!__is_allocator<_Container>::value>, + class = enable_if_t<!__is_allocator_v<_Container>>, class = enable_if_t<uses_allocator<_Container, _Alloc>::value> > queue(_Container, _Alloc) -> queue<typename _Container::value_type, _Container>; # endif # if _LIBCPP_STD_VER >= 23 template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0> -queue(_InputIterator, _InputIterator) -> queue<__iter_value_type<_InputIterator>>; +queue(_InputIterator, _InputIterator) -> queue<__iterator_value_type<_InputIterator>>; template <ranges::input_range _Range> queue(from_range_t, _Range&&) -> queue<ranges::range_value_t<_Range>>; @@ -457,11 +457,11 @@ queue(from_range_t, _Range&&) -> queue<ranges::range_value_t<_Range>>; template <class _InputIterator, class _Alloc, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0, - __enable_if_t<__is_allocator<_Alloc>::value, int> = 0> + __enable_if_t<__is_allocator_v<_Alloc>, int> = 0> queue(_InputIterator, _InputIterator, _Alloc) - -> queue<__iter_value_type<_InputIterator>, deque<__iter_value_type<_InputIterator>, _Alloc>>; + -> queue<__iterator_value_type<_InputIterator>, deque<__iterator_value_type<_InputIterator>, _Alloc>>; -template <ranges::input_range _Range, class _Alloc, __enable_if_t<__is_allocator<_Alloc>::value, int> = 0> +template <ranges::input_range _Range, class _Alloc, __enable_if_t<__is_allocator_v<_Alloc>, int> = 0> queue(from_range_t, _Range&&, _Alloc) -> queue<ranges::range_value_t<_Range>, deque<ranges::range_value_t<_Range>, _Alloc>>; # endif @@ -664,8 +664,10 @@ public: # endif [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI bool empty() const { return c.empty(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } - _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference top() const { return c.front(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI const_reference top() const { + return c.front(); + } _LIBCPP_CONSTEXPR_SINCE_CXX26 _LIBCPP_HIDE_FROM_ABI void push(const value_type& __v); # ifndef _LIBCPP_CXX03_LANG @@ -700,45 +702,45 @@ public: # if _LIBCPP_STD_VER >= 17 template <class _Compare, class _Container, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<!__is_allocator<_Container>::value> > + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<!__is_allocator_v<_Container>>> priority_queue(_Compare, _Container) -> priority_queue<typename _Container::value_type, _Container, _Compare>; template <class _InputIterator, - class _Compare = less<__iter_value_type<_InputIterator>>, - class _Container = vector<__iter_value_type<_InputIterator>>, + class _Compare = less<__iterator_value_type<_InputIterator>>, + class _Container = vector<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<!__is_allocator<_Container>::value> > + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<!__is_allocator_v<_Container>>> priority_queue(_InputIterator, _InputIterator, _Compare = _Compare(), _Container = _Container()) - -> priority_queue<__iter_value_type<_InputIterator>, _Container, _Compare>; + -> priority_queue<__iterator_value_type<_InputIterator>, _Container, _Compare>; template <class _Compare, class _Container, class _Alloc, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<!__is_allocator<_Container>::value>, - class = enable_if_t<uses_allocator<_Container, _Alloc>::value> > + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<!__is_allocator_v<_Container>>, + class = enable_if_t<uses_allocator<_Container, _Alloc>::value>> priority_queue(_Compare, _Container, _Alloc) -> priority_queue<typename _Container::value_type, _Container, _Compare>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value> > + class = enable_if_t<__is_allocator_v<_Allocator>>> priority_queue(_InputIterator, _InputIterator, _Allocator) - -> priority_queue<__iter_value_type<_InputIterator>, - vector<__iter_value_type<_InputIterator>, _Allocator>, - less<__iter_value_type<_InputIterator>>>; + -> priority_queue<__iterator_value_type<_InputIterator>, + vector<__iterator_value_type<_InputIterator>, _Allocator>, + less<__iterator_value_type<_InputIterator>>>; template <class _InputIterator, class _Compare, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value> > + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> priority_queue(_InputIterator, _InputIterator, _Compare, _Allocator) - -> priority_queue<__iter_value_type<_InputIterator>, - vector<__iter_value_type<_InputIterator>, _Allocator>, + -> priority_queue<__iterator_value_type<_InputIterator>, + vector<__iterator_value_type<_InputIterator>, _Allocator>, _Compare>; template <class _InputIterator, @@ -746,8 +748,8 @@ template <class _InputIterator, class _Container, class _Alloc, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<!__is_allocator<_Container>::value>, + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<!__is_allocator_v<_Container>>, class = enable_if_t<uses_allocator<_Container, _Alloc>::value> > priority_queue(_InputIterator, _InputIterator, _Compare, _Container, _Alloc) -> priority_queue<typename _Container::value_type, _Container, _Compare>; @@ -757,19 +759,19 @@ priority_queue(_InputIterator, _InputIterator, _Compare, _Container, _Alloc) template <ranges::input_range _Range, class _Compare = less<ranges::range_value_t<_Range>>, - class = enable_if_t<!__is_allocator<_Compare>::value>> + class = enable_if_t<!__is_allocator_v<_Compare>>> priority_queue(from_range_t, _Range&&, _Compare = _Compare()) -> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>>, _Compare>; template <ranges::input_range _Range, class _Compare, class _Alloc, - class = enable_if_t<!__is_allocator<_Compare>::value>, - class = enable_if_t<__is_allocator<_Alloc>::value>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Alloc>>> priority_queue(from_range_t, _Range&&, _Compare, _Alloc) -> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>, _Alloc>, _Compare>; -template <ranges::input_range _Range, class _Alloc, class = enable_if_t<__is_allocator<_Alloc>::value>> +template <ranges::input_range _Range, class _Alloc, class = enable_if_t<__is_allocator_v<_Alloc>>> priority_queue(from_range_t, _Range&&, _Alloc) -> priority_queue<ranges::range_value_t<_Range>, vector<ranges::range_value_t<_Range>, _Alloc>>; diff --git a/lib/libcxx/include/ranges b/lib/libcxx/include/ranges @@ -116,6 +116,10 @@ namespace std::ranges { // [range.dangling], dangling iterator handling struct dangling; + // [range.elementsof], class template elements_of + template<range R, class Allocator = allocator<byte>> + struct elements_of; + template<range R> using borrowed_iterator_t = see below; @@ -267,6 +271,11 @@ namespace std::ranges { template<class W, class Bound> inline constexpr bool enable_borrowed_range<iota_view<W, Bound>> = true; + namespace views { + inline constexpr unspecified iota = unspecified; + inline constexpr unspecified indices = unspecified; // Since C++26 + } + // [range.repeat], repeat view template<class T> concept integer-like-with-usable-difference-type = // exposition only @@ -339,6 +348,41 @@ 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.adjacent], adjacent view + template<forward_range V, size_t N> + requires view<V> && (N > 0) + class adjacent_view; + + template<class V, size_t N> + constexpr bool enable_borrowed_range<adjacent_view<V, N>> = + enable_borrowed_range<V>; + + namespace views { + template<size_t N> + constexpr unspecified adjacent = unspecified; + inline constexpr auto pairwise = adjacent<2>; + } + + // [range.adjacent.transform], adjacent transform view + template<forward_range V, move_constructible F, size_t N> + requires see below + class adjacent_transform_view; + + namespace views { + template<size_t N> + constexpr unspecified adjacent_transform = unspecified; + inline constexpr auto pairwise_transform = adjacent_transform<2>; + } + // [range.as.rvalue] template <view V> requires input_range<V> @@ -404,6 +448,7 @@ namespace std { # include <__ranges/data.h> # include <__ranges/drop_view.h> # include <__ranges/drop_while_view.h> +# include <__ranges/elements_of.h> # include <__ranges/elements_view.h> # include <__ranges/empty.h> # include <__ranges/empty_view.h> @@ -433,12 +478,15 @@ namespace std { # endif # if _LIBCPP_STD_VER >= 23 +# include <__ranges/adjacent_transform_view.h> +# include <__ranges/adjacent_view.h> # include <__ranges/as_rvalue_view.h> # include <__ranges/chunk_by_view.h> # include <__ranges/from_range.h> # 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/lib/libcxx/include/regex b/lib/libcxx/include/regex @@ -986,7 +986,7 @@ public: explicit regex_error(regex_constants::error_type __ecode); _LIBCPP_HIDE_FROM_ABI regex_error(const regex_error&) _NOEXCEPT = default; ~regex_error() _NOEXCEPT override; - _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI regex_constants::error_type code() const { return __code_; } }; template <regex_constants::error_type _Ev> @@ -1004,7 +1004,7 @@ public: typedef _CharT char_type; typedef basic_string<char_type> string_type; typedef locale locale_type; -# if defined(__BIONIC__) || defined(_NEWLIB_VERSION) +# if defined(__BIONIC__) || _LIBCPP_LIBC_NEWLIB // Originally bionic's ctype_base used its own ctype masks because the // builtin ctype implementation wasn't in libc++ yet. Bionic's ctype mask // was only 8 bits wide and already saturated, so it used a wider type here @@ -1013,9 +1013,7 @@ public: // implementation, but this was not updated to match. Since then Android has // needed to maintain a stable libc++ ABI, and this can't be changed without // an ABI break. - // We also need this workaround for newlib since _NEWLIB_VERSION is not - // defined yet inside __config, so we can't set the - // _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE macro. Additionally, newlib is + // We also need this workaround for newlib since newlib is // often used for space constrained environments, so it makes sense not to // duplicate the ctype table. typedef uint16_t char_class_type; @@ -2120,7 +2118,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]); @@ -2414,8 +2412,8 @@ public: # endif // _LIBCPP_CXX03_LANG // const operations: - _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; } - _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI unsigned mark_count() const { return __marked_count_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI flag_type flags() const { return __flags_; } // locale: _LIBCPP_HIDE_FROM_ABI locale_type imbue(locale_type __loc) { @@ -2423,7 +2421,7 @@ public: __start_.reset(); return __traits_.imbue(__loc); } - _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI locale_type getloc() const { return __traits_.getloc(); } // swap: void swap(basic_regex& __r); @@ -4208,17 +4206,17 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR sub_match() : matched() {} - _LIBCPP_HIDE_FROM_ABI difference_type length() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type length() const { return matched ? std::distance(this->first, this->second) : 0; } - _LIBCPP_HIDE_FROM_ABI string_type str() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return matched ? string_type(this->first, this->second) : string_type(); } _LIBCPP_HIDE_FROM_ABI operator string_type() const { return str(); } - _LIBCPP_HIDE_FROM_ABI int compare(const sub_match& __s) const { return str().compare(__s.str()); } - _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return str().compare(__s); } - _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return str().compare(__s); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const sub_match& __s) const { return str().compare(__s.str()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const string_type& __s) const { return str().compare(__s); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int compare(const value_type* __s) const { return str().compare(__s); } _LIBCPP_HIDE_FROM_ABI void swap(sub_match& __s) _NOEXCEPT_(__is_nothrow_swappable_v<_BidirectionalIterator>) { this->pair<_BidirectionalIterator, _BidirectionalIterator>::swap(__s); @@ -4583,49 +4581,53 @@ public: _LIBCPP_HIDE_FROM_ABI bool ready() const { return __ready_; } // size: - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __matches_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __matches_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __matches_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __matches_.max_size(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return size() == 0; } // element access: - _LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const { // If the match results are not ready, this will return `0`. _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::length() called when not ready"); return (*this)[__sub].length(); } - _LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const { // If the match results are not ready, this will return the result of subtracting two default-constructed iterators // (which is typically a well-defined operation). _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::position() called when not ready"); return std::distance(__position_start_, (*this)[__sub].first); } - _LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const { // If the match results are not ready, this will return an empty string. _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::str() called when not ready"); return (*this)[__sub].str(); } - _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const { // If the match results are not ready, this call will be equivalent to calling this function with `__n >= size()`, // returning an empty subrange. _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::operator[]() called when not ready"); return __n < __matches_.size() ? __matches_[__n] : __unmatched_; } - _LIBCPP_HIDE_FROM_ABI const_reference prefix() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference prefix() const { // If the match results are not ready, this will return a default-constructed empty `__suffix_`. _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::prefix() called when not ready"); return __prefix_; } - _LIBCPP_HIDE_FROM_ABI const_reference suffix() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference suffix() const { // If the match results are not ready, this will return a default-constructed empty `__suffix_`. _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::suffix() called when not ready"); return __suffix_; } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const { return empty() ? __matches_.end() : __matches_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const { return __matches_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const { return empty() ? __matches_.end() : __matches_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const { return __matches_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const { + return empty() ? __matches_.end() : __matches_.begin(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const { return __matches_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const { + return empty() ? __matches_.end() : __matches_.begin(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const { return __matches_.end(); } // format: template <class _OutputIter> @@ -4641,14 +4643,14 @@ public: return format(__output_iter, __fmt.data(), __fmt.data() + __fmt.size(), __flags); } template <class _ST, class _SA> - _LIBCPP_HIDE_FROM_ABI basic_string<char_type, _ST, _SA> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, _ST, _SA> format(const basic_string<char_type, _ST, _SA>& __fmt, regex_constants::match_flag_type __flags = regex_constants::format_default) const { basic_string<char_type, _ST, _SA> __r; format(std::back_inserter(__r), __fmt.data(), __fmt.data() + __fmt.size(), __flags); return __r; } - _LIBCPP_HIDE_FROM_ABI string_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type format(const char_type* __fmt, regex_constants::match_flag_type __flags = regex_constants::format_default) const { string_type __r; format(std::back_inserter(__r), __fmt, __fmt + char_traits<char_type>::length(__fmt), __flags); @@ -4656,7 +4658,7 @@ public: } // allocator: - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const { return __matches_.get_allocator(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const { return __matches_.get_allocator(); } // swap: void swap(match_results& __m); @@ -5377,7 +5379,7 @@ public: _LIBCPP_HIDE_FROM_ABI bool operator!=(const regex_iterator& __x) const { return !(*this == __x); } # endif - _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __match_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference operator*() const { return __match_; } _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return std::addressof(__match_); } regex_iterator& operator++(); @@ -5558,7 +5560,7 @@ public: _LIBCPP_HIDE_FROM_ABI bool operator!=(const regex_token_iterator& __x) const { return !(*this == __x); } # endif - _LIBCPP_HIDE_FROM_ABI const value_type& operator*() const { return *__result_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const value_type& operator*() const { return *__result_; } _LIBCPP_HIDE_FROM_ABI const value_type* operator->() const { return __result_; } regex_token_iterator& operator++(); diff --git a/lib/libcxx/include/scoped_allocator b/lib/libcxx/include/scoped_allocator @@ -382,13 +382,17 @@ public: // scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; // ~scoped_allocator_adaptor() = default; - _LIBCPP_HIDE_FROM_ABI inner_allocator_type& inner_allocator() _NOEXCEPT { return _Base::inner_allocator(); } - _LIBCPP_HIDE_FROM_ABI const inner_allocator_type& inner_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI inner_allocator_type& inner_allocator() _NOEXCEPT { + return _Base::inner_allocator(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const inner_allocator_type& inner_allocator() const _NOEXCEPT { return _Base::inner_allocator(); } - _LIBCPP_HIDE_FROM_ABI outer_allocator_type& outer_allocator() _NOEXCEPT { return _Base::outer_allocator(); } - _LIBCPP_HIDE_FROM_ABI const outer_allocator_type& outer_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI outer_allocator_type& outer_allocator() _NOEXCEPT { + return _Base::outer_allocator(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const outer_allocator_type& outer_allocator() const _NOEXCEPT { return _Base::outer_allocator(); } @@ -403,7 +407,7 @@ public: allocator_traits<outer_allocator_type>::deallocate(outer_allocator(), __p, __n); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const { return allocator_traits<outer_allocator_type>::max_size(outer_allocator()); } @@ -434,10 +438,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{}), + __index_sequence_for<_Args1...>()), __transform_tuple(typename __uses_alloc_ctor< _T2, inner_allocator_type&, _Args2... >::type(), std::move(__y), - typename __make_tuple_indices<sizeof...(_Args2)>::type{})); + __index_sequence_for<_Args2...>())); } template <class _T1, class _T2> @@ -473,7 +477,8 @@ public: allocator_traits<typename _OM::type>::destroy(_OM()(outer_allocator()), __p); } - _LIBCPP_HIDE_FROM_ABI scoped_allocator_adaptor select_on_container_copy_construction() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI scoped_allocator_adaptor + select_on_container_copy_construction() const _NOEXCEPT { return _Base::select_on_container_copy_construction(); } @@ -503,20 +508,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/lib/libcxx/include/semaphore b/lib/libcxx/include/semaphore @@ -55,12 +55,11 @@ using binary_semaphore = counting_semaphore<1>; // since C++20 # include <__assert> # include <__atomic/atomic.h> # include <__atomic/atomic_sync.h> +# include <__atomic/atomic_sync_timed.h> # include <__atomic/memory_order.h> # include <__chrono/time_point.h> # include <__cstddef/ptrdiff_t.h> -# include <__thread/poll_with_backoff.h> # include <__thread/support.h> -# include <__thread/timed_backoff_policy.h> # include <limits> # include <version> @@ -90,7 +89,7 @@ class __atomic_semaphore_base { public: _LIBCPP_HIDE_FROM_ABI constexpr explicit __atomic_semaphore_base(ptrdiff_t __count) : __a_(__count) {} - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) { + _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) { auto __old = __a_.fetch_add(__update, memory_order_release); _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( __update <= _LIBCPP_SEMAPHORE_MAX - __old, "update is greater than the expected value"); @@ -98,26 +97,26 @@ public: __a_.notify_all(); } } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() { + _LIBCPP_HIDE_FROM_ABI void acquire() { std::__atomic_wait_unless(__a_, memory_order_relaxed, [this](ptrdiff_t& __old) { return __try_acquire_impl(__old); }); } template <class _Rep, class _Period> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool - try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) { + _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) { if (__rel_time == chrono::duration<_Rep, _Period>::zero()) return try_acquire(); - auto const __poll_fn = [this]() { return try_acquire(); }; - return std::__libcpp_thread_poll_with_backoff(__poll_fn, __libcpp_timed_backoff_policy(), __rel_time); + + return std::__atomic_wait_unless_with_timeout( + __a_, memory_order_relaxed, [this](ptrdiff_t& __old) { return __try_acquire_impl(__old); }, __rel_time); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() { + _LIBCPP_HIDE_FROM_ABI bool try_acquire() { auto __old = __a_.load(memory_order_relaxed); return __try_acquire_impl(__old); } private: - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool __try_acquire_impl(ptrdiff_t& __old) { + _LIBCPP_HIDE_FROM_ABI bool __try_acquire_impl(ptrdiff_t& __old) { while (true) { if (__old == 0) return false; @@ -134,7 +133,7 @@ class counting_semaphore { public: static_assert(__least_max_value >= 0, "The least maximum value must be a positive number"); - static constexpr ptrdiff_t max() noexcept { return __least_max_value; } + [[nodiscard]] static constexpr ptrdiff_t max() noexcept { return __least_max_value; } _LIBCPP_HIDE_FROM_ABI constexpr explicit counting_semaphore(ptrdiff_t __count) : __semaphore_(__count) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( @@ -151,20 +150,18 @@ public: counting_semaphore(const counting_semaphore&) = delete; counting_semaphore& operator=(const counting_semaphore&) = delete; - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) { + _LIBCPP_HIDE_FROM_ABI void release(ptrdiff_t __update = 1) { _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__update >= 0, "counting_semaphore:release called with a negative value"); __semaphore_.release(__update); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI void acquire() { __semaphore_.acquire(); } + _LIBCPP_HIDE_FROM_ABI void acquire() { __semaphore_.acquire(); } template <class _Rep, class _Period> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool - try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_for(chrono::duration<_Rep, _Period> const& __rel_time) { return __semaphore_.try_acquire_for(chrono::duration_cast<chrono::nanoseconds>(__rel_time)); } - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire() { return __semaphore_.try_acquire(); } template <class _Clock, class _Duration> - _LIBCPP_AVAILABILITY_SYNC _LIBCPP_HIDE_FROM_ABI bool - try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool try_acquire_until(chrono::time_point<_Clock, _Duration> const& __abs_time) { auto const __current = _Clock::now(); if (__current >= __abs_time) return try_acquire(); diff --git a/lib/libcxx/include/set b/lib/libcxx/include/set @@ -518,19 +518,19 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); // C++20 # include <__algorithm/equal.h> # include <__algorithm/lexicographical_compare.h> # include <__algorithm/lexicographical_compare_three_way.h> +# include <__algorithm/specialized_algorithms.h> # include <__assert> # include <__config> # include <__functional/is_transparent.h> # include <__functional/operations.h> -# include <__fwd/set.h> # include <__iterator/erase_if_container.h> # include <__iterator/iterator_traits.h> -# include <__iterator/ranges_iterator_traits.h> # include <__iterator/reverse_iterator.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> # include <__memory_resource/polymorphic_allocator.h> # include <__node_handle> +# include <__ranges/access.h> # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> @@ -538,7 +538,6 @@ erase_if(multiset<Key, Compare, Allocator>& c, Predicate pred); // C++20 # include <__type_traits/container_traits.h> # include <__type_traits/enable_if.h> # include <__type_traits/is_allocator.h> -# include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> @@ -570,7 +569,10 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Key, class _Compare, class _Allocator> +template <class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key> > +class multiset; + +template <class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key> > class set { public: // types: @@ -660,22 +662,20 @@ public: : set(from_range, std::forward<_Range>(__range), key_compare(), __a) {} # endif - _LIBCPP_HIDE_FROM_ABI set(const set& __s) : __tree_(__s.__tree_) { insert(__s.begin(), __s.end()); } + _LIBCPP_HIDE_FROM_ABI set(const set& __s) = default; _LIBCPP_HIDE_FROM_ABI set& operator=(const set& __s) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI set(set&& __s) noexcept(is_nothrow_move_constructible<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI set(set&& __s) = default; # endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI explicit set(const allocator_type& __a) : __tree_(__a) {} - _LIBCPP_HIDE_FROM_ABI set(const set& __s, const allocator_type& __a) : __tree_(__s.__tree_.value_comp(), __a) { - insert(__s.begin(), __s.end()); - } + _LIBCPP_HIDE_FROM_ABI set(const set& __s, const allocator_type& __alloc) : __tree_(__s.__tree_, __alloc) {} # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI set(set&& __s, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI set(set&& __s, const allocator_type& __alloc) : __tree_(std::move(__s.__tree_), __alloc) {} _LIBCPP_HIDE_FROM_ABI set(initializer_list<value_type> __il, const value_compare& __comp = value_compare()) : __tree_(__comp) { @@ -693,36 +693,38 @@ public: # endif _LIBCPP_HIDE_FROM_ABI set& operator=(initializer_list<value_type> __il) { - __tree_.__assign_unique(__il.begin(), __il.end()); + clear(); + insert(__il.begin(), __il.end()); return *this; } - _LIBCPP_HIDE_FROM_ABI set& operator=(set&& __s) noexcept(is_nothrow_move_assignable<__base>::value) { - __tree_ = std::move(__s.__tree_); - return *this; - } + _LIBCPP_HIDE_FROM_ABI set& operator=(set&& __s) = default; # endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI ~set() { static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), ""); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.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()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __tree_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } // modifiers: # ifndef _LIBCPP_CXX03_LANG @@ -732,28 +734,24 @@ public: } template <class... _Args> _LIBCPP_HIDE_FROM_ABI iterator emplace_hint(const_iterator __p, _Args&&... __args) { - return __tree_.__emplace_hint_unique(__p, std::forward<_Args>(__args)...); + return __tree_.__emplace_hint_unique(__p, std::forward<_Args>(__args)...).first; } # endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(const value_type& __v) { return __tree_.__emplace_unique(__v); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, const value_type& __v) { - return __tree_.__emplace_hint_unique(__p, __v); + return __tree_.__emplace_hint_unique(__p, __v).first; } template <class _InputIterator> - _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - __tree_.__emplace_hint_unique(__e, *__f); + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + __tree_.__insert_range_unique(__first, __last); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<value_type> _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - __tree_.__emplace_hint_unique(__end, std::forward<decltype(__element)>(__element)); - } + __tree_.__insert_range_unique(ranges::begin(__range), ranges::end(__range)); } # endif @@ -763,7 +761,7 @@ public: } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __p, value_type&& __v) { - return __tree_.__emplace_hint_unique(__p, std::move(__v)); + return __tree_.__emplace_hint_unique(__p, std::move(__v)).first; } _LIBCPP_HIDE_FROM_ABI void insert(initializer_list<value_type> __il) { insert(__il.begin(), __il.end()); } @@ -785,10 +783,10 @@ public: "node_type with incompatible allocator passed to set::insert()"); return __tree_.template __node_handle_insert_unique<node_type>(__hint, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __tree_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __tree_.template __node_handle_extract<node_type>(__it); } template <class _Compare2> @@ -819,101 +817,120 @@ public: _LIBCPP_HIDE_FROM_ABI void swap(set& __s) _NOEXCEPT_(__is_nothrow_swappable_v<__base>) { __tree_.swap(__s.__tree_); } - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return __tree_.__alloc(); } - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp(); } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __tree_.value_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return __tree_.__alloc(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __tree_.value_comp(); } // set operations: - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __tree_.find(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __tree_.find(__k); } # endif - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __tree_.__count_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __tree_.__count_unique(__k); + } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __tree_.__count_multi(__k); } # endif # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { + return __tree_.__lower_bound_unique(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { + return __tree_.__lower_bound_unique(__k); + } + + // The transparent versions of the lookup functions use the _multi version, since a non-element key is allowed to + // match multiple elements. # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { + return __tree_.__lower_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { + return __tree_.__lower_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { + return __tree_.__upper_bound_unique(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { + return __tree_.__upper_bound_unique(__k); + } + # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { + return __tree_.__upper_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { + return __tree_.__upper_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __tree_.__equal_range_unique(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __tree_.__equal_range_unique(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __tree_.__equal_range_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __tree_.__equal_range_multi(__k); } # endif + + template <class, class...> + friend struct __specialized_algorithm; }; # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Compare = less<__iter_value_type<_InputIterator>>, - class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class _Compare = less<__iterator_value_type<_InputIterator>>, + class _Allocator = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>, + class = enable_if_t<!__is_allocator_v<_Compare>>> set(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) - -> set<__iter_value_type<_InputIterator>, _Compare, _Allocator>; + -> set<__iterator_value_type<_InputIterator>, _Compare, _Allocator>; # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Compare = less<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>, + class = enable_if_t<!__is_allocator_v<_Compare>>> set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> set<ranges::range_value_t<_Range>, _Compare, _Allocator>; # endif @@ -921,41 +938,43 @@ set(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) template <class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<!__is_allocator_v<_Compare>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> set(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator()) -> set<_Key, _Compare, _Allocator>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> -set(_InputIterator, - _InputIterator, - _Allocator) -> set<__iter_value_type<_InputIterator>, less<__iter_value_type<_InputIterator>>, _Allocator>; + class = enable_if_t<__is_allocator_v<_Allocator>>> +set(_InputIterator, _InputIterator, _Allocator) + -> set<__iterator_value_type<_InputIterator>, less<__iterator_value_type<_InputIterator>>, _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> -set(from_range_t, - _Range&&, - _Allocator) -> set<ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, _Allocator>; +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> +set(from_range_t, _Range&&, _Allocator) + -> set<ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, _Allocator>; # endif -template <class _Key, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> +template <class _Key, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> set(initializer_list<_Key>, _Allocator) -> set<_Key, less<_Key>, _Allocator>; # endif -# ifndef _LIBCPP_CXX03_LANG +# if _LIBCPP_STD_VER >= 14 +template <class _Alg, class _Key, class _Compare, class _Allocator> +struct __specialized_algorithm<_Alg, __single_range<set<_Key, _Compare, _Allocator>>> { + using __set _LIBCPP_NODEBUG = set<_Key, _Compare, _Allocator>; -template <class _Key, class _Compare, class _Allocator> -set<_Key, _Compare, _Allocator>::set(set&& __s, const allocator_type& __a) : __tree_(std::move(__s.__tree_), __a) { - if (__a != __s.get_allocator()) { - const_iterator __e = cend(); - while (!__s.empty()) - insert(__e, std::move(__s.__tree_.remove(__s.begin())->__value_)); - } -} + static const bool __has_algorithm = + __specialized_algorithm<_Alg, __single_range<typename __set::__base>>::__has_algorithm; -# endif // _LIBCPP_CXX03_LANG + // set's begin() and end() are identical with and without const qualification + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI static auto operator()(const __set& __set, _Args&&... __args) { + return __specialized_algorithm<_Alg, __single_range<typename __set::__base>>()( + __set.__tree_, std::forward<_Args>(__args)...); + } +}; +# endif template <class _Key, class _Compare, class _Allocator> inline _LIBCPP_HIDE_FROM_ABI bool @@ -1119,24 +1138,17 @@ public: : multiset(from_range, std::forward<_Range>(__range), key_compare(), __a) {} # endif - _LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s) - : __tree_(__s.__tree_.value_comp(), - __alloc_traits::select_on_container_copy_construction(__s.__tree_.__alloc())) { - insert(__s.begin(), __s.end()); - } + _LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s) = default; _LIBCPP_HIDE_FROM_ABI multiset& operator=(const multiset& __s) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI multiset(multiset&& __s) noexcept(is_nothrow_move_constructible<__base>::value) = default; + _LIBCPP_HIDE_FROM_ABI multiset(multiset&& __s) = default; - _LIBCPP_HIDE_FROM_ABI multiset(multiset&& __s, const allocator_type& __a); + _LIBCPP_HIDE_FROM_ABI multiset(multiset&& __s, const allocator_type& __a) : __tree_(std::move(__s.__tree_), __a) {} # endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI explicit multiset(const allocator_type& __a) : __tree_(__a) {} - _LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s, const allocator_type& __a) - : __tree_(__s.__tree_.value_comp(), __a) { - insert(__s.begin(), __s.end()); - } + _LIBCPP_HIDE_FROM_ABI multiset(const multiset& __s, const allocator_type& __a) : __tree_(__s.__tree_, __a) {} # ifndef _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI multiset(initializer_list<value_type> __il, const value_compare& __comp = value_compare()) @@ -1156,38 +1168,40 @@ public: # endif _LIBCPP_HIDE_FROM_ABI multiset& operator=(initializer_list<value_type> __il) { - __tree_.__assign_multi(__il.begin(), __il.end()); + clear(); + insert(__il.begin(), __il.end()); return *this; } - _LIBCPP_HIDE_FROM_ABI multiset& operator=(multiset&& __s) _NOEXCEPT_(is_nothrow_move_assignable<__base>::value) { - __tree_ = std::move(__s.__tree_); - return *this; - } + _LIBCPP_HIDE_FROM_ABI multiset& operator=(multiset&& __s) = default; # endif // _LIBCPP_CXX03_LANG _LIBCPP_HIDE_FROM_ABI ~multiset() { static_assert(sizeof(std::__diagnose_non_const_comparator<_Key, _Compare>()), ""); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __tree_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __tree_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __tree_.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()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() _NOEXCEPT { return reverse_iterator(end()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + return const_reverse_iterator(end()); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reverse_iterator rend() _NOEXCEPT { return reverse_iterator(begin()); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + return const_reverse_iterator(begin()); + } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } - _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { return rbegin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return rend(); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __tree_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __tree_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __tree_.max_size(); } // modifiers: # ifndef _LIBCPP_CXX03_LANG @@ -1207,18 +1221,14 @@ public: } template <class _InputIterator> - _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __f, _InputIterator __l) { - for (const_iterator __e = cend(); __f != __l; ++__f) - __tree_.__emplace_hint_multi(__e, *__f); + _LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) { + __tree_.__insert_range_multi(__first, __last); } # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<value_type> _Range> _LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) { - const_iterator __end = cend(); - for (auto&& __element : __range) { - __tree_.__emplace_hint_multi(__end, std::forward<decltype(__element)>(__element)); - } + __tree_.__insert_range_multi(ranges::begin(__range), ranges::end(__range)); } # endif @@ -1248,10 +1258,10 @@ public: "node_type with incompatible allocator passed to multiset::insert()"); return __tree_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __tree_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __tree_.template __node_handle_extract<node_type>(__it); } template <class _Compare2> @@ -1284,101 +1294,118 @@ public: __tree_.swap(__s.__tree_); } - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return __tree_.__alloc(); } - _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp(); } - _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __tree_.value_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return __tree_.__alloc(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __tree_.value_comp(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __tree_.value_comp(); } // set operations: - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __tree_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __tree_.find(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __tree_.find(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __tree_.find(__k); } # endif - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __tree_.__count_multi(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __tree_.__count_multi(__k); + } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __tree_.__count_multi(__k); } # endif # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { return __tree_.lower_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { return __tree_.lower_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __k) { + return __tree_.__lower_bound_multi(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __k) const { + return __tree_.__lower_bound_multi(__k); + } + # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _K2& __k) { + return __tree_.__lower_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { - return __tree_.lower_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _K2& __k) const { + return __tree_.__lower_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { return __tree_.upper_bound(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { return __tree_.upper_bound(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __k) { + return __tree_.__upper_bound_multi(__k); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __k) const { + return __tree_.__upper_bound_multi(__k); + } + # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _K2& __k) { + return __tree_.__upper_bound_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { - return __tree_.upper_bound(__k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _K2& __k) const { + return __tree_.__upper_bound_multi(__k); } # endif - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __tree_.__equal_range_multi(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __tree_.__equal_range_multi(__k); } # if _LIBCPP_STD_VER >= 14 template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __tree_.__equal_range_multi(__k); } template <typename _K2, enable_if_t<__is_transparent_v<_Compare, _K2>, int> = 0> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __tree_.__equal_range_multi(__k); } # endif + + template <class, class...> + friend struct __specialized_algorithm; }; # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Compare = less<__iter_value_type<_InputIterator>>, - class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class _Compare = less<__iterator_value_type<_InputIterator>>, + class _Allocator = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>, + class = enable_if_t<!__is_allocator_v<_Compare>>> multiset(_InputIterator, _InputIterator, _Compare = _Compare(), _Allocator = _Allocator()) - -> multiset<__iter_value_type<_InputIterator>, _Compare, _Allocator>; + -> multiset<__iterator_value_type<_InputIterator>, _Compare, _Allocator>; # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Compare = less<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>, + class = enable_if_t<!__is_allocator_v<_Compare>>> multiset(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator()) -> multiset<ranges::range_value_t<_Range>, _Compare, _Allocator>; # endif @@ -1386,43 +1413,44 @@ multiset(from_range_t, _Range&&, _Compare = _Compare(), _Allocator = _Allocator( template <class _Key, class _Compare = less<_Key>, class _Allocator = allocator<_Key>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>, - class = enable_if_t<!__is_allocator<_Compare>::value, void>> -multiset(initializer_list<_Key>, - _Compare = _Compare(), - _Allocator = _Allocator()) -> multiset<_Key, _Compare, _Allocator>; + class = enable_if_t<__is_allocator_v<_Allocator>>, + class = enable_if_t<!__is_allocator_v<_Compare>>> +multiset(initializer_list<_Key>, _Compare = _Compare(), _Allocator = _Allocator()) + -> multiset<_Key, _Compare, _Allocator>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value, void>, - class = enable_if_t<__is_allocator<_Allocator>::value, void>> + class = enable_if_t<__is_allocator_v<_Allocator>>> multiset(_InputIterator, _InputIterator, _Allocator) - -> multiset<__iter_value_type<_InputIterator>, less<__iter_value_type<_InputIterator>>, _Allocator>; + -> multiset<__iterator_value_type<_InputIterator>, less<__iterator_value_type<_InputIterator>>, _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> -multiset(from_range_t, - _Range&&, - _Allocator) -> multiset<ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, _Allocator>; +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> +multiset(from_range_t, _Range&&, _Allocator) + -> multiset<ranges::range_value_t<_Range>, less<ranges::range_value_t<_Range>>, _Allocator>; # endif -template <class _Key, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value, void>> +template <class _Key, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> multiset(initializer_list<_Key>, _Allocator) -> multiset<_Key, less<_Key>, _Allocator>; # endif -# ifndef _LIBCPP_CXX03_LANG +# if _LIBCPP_STD_VER >= 14 +template <class _Alg, class _Key, class _Compare, class _Allocator> +struct __specialized_algorithm<_Alg, __single_range<multiset<_Key, _Compare, _Allocator>>> { + using __set _LIBCPP_NODEBUG = multiset<_Key, _Compare, _Allocator>; -template <class _Key, class _Compare, class _Allocator> -multiset<_Key, _Compare, _Allocator>::multiset(multiset&& __s, const allocator_type& __a) - : __tree_(std::move(__s.__tree_), __a) { - if (__a != __s.get_allocator()) { - const_iterator __e = cend(); - while (!__s.empty()) - insert(__e, std::move(__s.__tree_.remove(__s.begin())->__value_)); - } -} + static const bool __has_algorithm = + __specialized_algorithm<_Alg, __single_range<typename __set::__base>>::__has_algorithm; -# endif // _LIBCPP_CXX03_LANG + // set's begin() and end() are identical with and without const qualification + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI static auto operator()(const __set& __set, _Args&&... __args) { + return __specialized_algorithm<_Alg, __single_range<typename __set::__base>>()( + __set.__tree_, std::forward<_Args>(__args)...); + } +}; +# endif template <class _Key, class _Compare, class _Allocator> inline _LIBCPP_HIDE_FROM_ABI bool diff --git a/lib/libcxx/include/shared_mutex b/lib/libcxx/include/shared_mutex @@ -138,6 +138,7 @@ template <class Mutex> # include <__mutex/tag_types.h> # include <__mutex/unique_lock.h> # include <__system_error/throw_system_error.h> +# include <__utility/move.h> # include <__utility/swap.h> # include <cerrno> # include <version> @@ -340,14 +341,8 @@ public: } _LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT { - if (__owns_) - __m_->unlock_shared(); - __m_ = nullptr; - __owns_ = false; - __m_ = __u.__m_; - __owns_ = __u.__owns_; - __u.__m_ = nullptr; - __u.__owns_ = false; + if (this != std::addressof(__u)) + shared_lock(std::move(__u)).swap(*this); return *this; } diff --git a/lib/libcxx/include/span b/lib/libcxx/include/span @@ -310,30 +310,32 @@ public: } template <size_t _Count> - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept { static_assert(_Count <= _Extent, "span<T, N>::first<Count>(): Count out of range"); return span<element_type, _Count>{data(), _Count}; } template <size_t _Count> - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept { static_assert(_Count <= _Extent, "span<T, N>::last<Count>(): Count out of range"); return span<element_type, _Count>{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T, N>::last(count): count out of range"); return {data() + size() - __count, __count}; } template <size_t _Offset, size_t _Count = dynamic_extent> - _LIBCPP_HIDE_FROM_ABI constexpr auto - subspan() const noexcept -> span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset> { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto subspan() const noexcept + -> span<element_type, _Count != dynamic_extent ? _Count : _Extent - _Offset> { static_assert(_Offset <= _Extent, "span<T, N>::subspan<Offset, Count>(): Offset out of range"); static_assert(_Count == dynamic_extent || _Count <= _Extent - _Offset, "span<T, N>::subspan<Offset, Count>(): Offset + Count out of range"); @@ -342,7 +344,7 @@ public: return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span<T, N>::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -352,52 +354,58 @@ public: return {data() + __offset, __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return _Extent; } - _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return _Extent * sizeof(element_type); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return _Extent; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { + return _Extent * sizeof(element_type); + } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return _Extent == 0; } - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span<T, N>::operator[](index): index out of range"); return __data_[__idx]; } # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const { if (__index >= size()) std::__throw_out_of_range("span"); return __data_[__index]; } # endif - _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::front() on empty span"); return __data_[0]; } - _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T, N>::back() on empty span"); return __data_[size() - 1]; } - _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; } // [span.iter], span iterator support - _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data(), data(), data() + size()); # else return iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data() + size(), data(), data() + size()); # else return iterator(data() + size()); # endif } - _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { + return reverse_iterator(begin()); + } _LIBCPP_HIDE_FROM_ABI span<const byte, _Extent * sizeof(element_type)> __as_bytes() const noexcept { return span<const byte, _Extent * sizeof(element_type)>{reinterpret_cast<const byte*>(data()), size_bytes()}; @@ -478,36 +486,38 @@ public: : __data_{__other.data()}, __size_{__other.size()} {} template <size_t _Count> - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> first() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::first<Count>(): Count out of range"); return span<element_type, _Count>{data(), _Count}; } template <size_t _Count> - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> last() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span<T>::last<Count>(): Count out of range"); return span<element_type, _Count>{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> first(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> last(size_type __count) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, dynamic_extent> + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span<T>::last(count): count out of range"); return {data() + size() - __count, __count}; } template <size_t _Offset, size_t _Count = dynamic_extent> - _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> subspan() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr span<element_type, _Count> subspan() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Offset <= size(), "span<T>::subspan<Offset, Count>(): Offset out of range"); _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset, "span<T>::subspan<Offset, Count>(): Offset + Count out of range"); return span<element_type, _Count>{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } - constexpr span<element_type, dynamic_extent> _LIBCPP_HIDE_FROM_ABI + [[nodiscard]] constexpr span<element_type, dynamic_extent> _LIBCPP_HIDE_FROM_ABI subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span<T>::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -517,52 +527,58 @@ public: return {data() + __offset, __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return __size_; } - _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return __size_ * sizeof(element_type); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept { return __size_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { + return __size_ * sizeof(element_type); + } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return __size_ == 0; } - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span<T>::operator[](index): index out of range"); return __data_[__idx]; } # if _LIBCPP_STD_VER >= 26 - _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference at(size_type __index) const { if (__index >= size()) std::__throw_out_of_range("span"); return __data_[__index]; } # endif - _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::front() on empty span"); return __data_[0]; } - _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span<T>::back() on empty span"); return __data_[size() - 1]; } - _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr pointer data() const noexcept { return __data_; } // [span.iter], span iterator support - _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() const noexcept { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data(), data(), data() + size()); # else return iterator(data()); # endif } - _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() const noexcept { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data() + size(), data(), data() + size()); # else return iterator(data() + size()); # endif } - _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } - _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator(end()); + } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr reverse_iterator rend() const noexcept { + return reverse_iterator(begin()); + } _LIBCPP_HIDE_FROM_ABI span<const byte, dynamic_extent> __as_bytes() const noexcept { return {reinterpret_cast<const byte*>(data()), size_bytes()}; @@ -585,13 +601,13 @@ inline constexpr bool ranges::enable_view<span<_ElementType, _Extent>> = true; // as_bytes & as_writable_bytes template <class _Tp, size_t _Extent> -_LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_bytes(span<_Tp, _Extent> __s) noexcept { return __s.__as_bytes(); } template <class _Tp, size_t _Extent> requires(!is_const_v<_Tp>) -_LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI auto as_writable_bytes(span<_Tp, _Extent> __s) noexcept { return __s.__as_writable_bytes(); } diff --git a/lib/libcxx/include/sstream b/lib/libcxx/include/sstream @@ -461,15 +461,15 @@ public: // [stringbuf.members] Member functions: # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } # endif # if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY) - string_type str() const; + [[__nodiscard__]] string_type str() const; # else - _LIBCPP_HIDE_FROM_ABI string_type str() const& { return str(__str_.get_allocator()); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return str(__str_.get_allocator()); } - _LIBCPP_HIDE_FROM_ABI string_type str() && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { const basic_string_view<_CharT, _Traits> __view = view(); typename string_type::size_type __pos = __view.empty() ? 0 : __view.data() - __str_.data(); // In C++23, this is just string_type(std::move(__str_), __pos, __view.size(), __str_.get_allocator()); @@ -484,12 +484,12 @@ public: # if _LIBCPP_STD_VER >= 20 template <class _SAlloc> - requires __is_allocator<_SAlloc>::value - _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { + requires __is_allocator_v<_SAlloc> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { return basic_string<_CharT, _Traits, _SAlloc>(view(), __sa); } - _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept; + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept; # endif // _LIBCPP_STD_VER >= 20 void str(const string_type& __s) { @@ -949,26 +949,28 @@ public: } // [istringstream.members] Member functions: - _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_)); } # if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY) - _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } # else - _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } - _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } # endif # if _LIBCPP_STD_VER >= 20 template <class _SAlloc> - requires __is_allocator<_SAlloc>::value - _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { + requires __is_allocator_v<_SAlloc> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { return __sb_.str(__sa); } - _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { + return __sb_.view(); + } # endif // _LIBCPP_STD_VER >= 20 _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); } @@ -1087,26 +1089,28 @@ public: } // [ostringstream.members] Member functions: - _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_)); } # if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY) - _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } # else - _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } - _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } # endif # if _LIBCPP_STD_VER >= 20 template <class _SAlloc> - requires __is_allocator<_SAlloc>::value - _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { + requires __is_allocator_v<_SAlloc> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { return __sb_.str(__sa); } - _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { + return __sb_.view(); + } # endif // _LIBCPP_STD_VER >= 20 _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); } @@ -1227,26 +1231,28 @@ public: } // [stringstream.members] Member functions: - _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const { return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(std::addressof(__sb_)); } # if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_BUILDING_LIBRARY) - _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI string_type str() const { return __sb_.str(); } # else - _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() const& { return __sb_.str(); } - _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_type str() && { return std::move(__sb_).str(); } # endif # if _LIBCPP_STD_VER >= 20 template <class _SAlloc> - requires __is_allocator<_SAlloc>::value - _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { + requires __is_allocator_v<_SAlloc> + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string<char_type, traits_type, _SAlloc> str(const _SAlloc& __sa) const { return __sb_.str(__sa); } - _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { return __sb_.view(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI basic_string_view<char_type, traits_type> view() const noexcept { + return __sb_.view(); + } # endif // _LIBCPP_STD_VER >= 20 _LIBCPP_HIDE_FROM_ABI void str(const string_type& __s) { __sb_.str(__s); } diff --git a/lib/libcxx/include/stack b/lib/libcxx/include/stack @@ -235,9 +235,9 @@ public: # endif [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const { return c.empty(); } - _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } - _LIBCPP_HIDE_FROM_ABI reference top() { return c.back(); } - _LIBCPP_HIDE_FROM_ABI const_reference top() const { return c.back(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const { return c.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI reference top() { return c.back(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_reference top() const { return c.back(); } _LIBCPP_HIDE_FROM_ABI void push(const value_type& __v) { c.push_back(__v); } # ifndef _LIBCPP_CXX03_LANG @@ -294,19 +294,19 @@ public: }; # if _LIBCPP_STD_VER >= 17 -template <class _Container, class = enable_if_t<!__is_allocator<_Container>::value> > +template <class _Container, class = enable_if_t<!__is_allocator_v<_Container>>> stack(_Container) -> stack<typename _Container::value_type, _Container>; template <class _Container, class _Alloc, - class = enable_if_t<!__is_allocator<_Container>::value>, + class = enable_if_t<!__is_allocator_v<_Container>>, class = enable_if_t<uses_allocator<_Container, _Alloc>::value> > stack(_Container, _Alloc) -> stack<typename _Container::value_type, _Container>; # endif # if _LIBCPP_STD_VER >= 23 template <class _InputIterator, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0> -stack(_InputIterator, _InputIterator) -> stack<__iter_value_type<_InputIterator>>; +stack(_InputIterator, _InputIterator) -> stack<__iterator_value_type<_InputIterator>>; template <ranges::input_range _Range> stack(from_range_t, _Range&&) -> stack<ranges::range_value_t<_Range>>; @@ -314,15 +314,13 @@ stack(from_range_t, _Range&&) -> stack<ranges::range_value_t<_Range>>; template <class _InputIterator, class _Alloc, __enable_if_t<__has_input_iterator_category<_InputIterator>::value, int> = 0, - __enable_if_t<__is_allocator<_Alloc>::value, int> = 0> -stack(_InputIterator, - _InputIterator, - _Alloc) -> stack<__iter_value_type<_InputIterator>, deque<__iter_value_type<_InputIterator>, _Alloc>>; - -template <ranges::input_range _Range, class _Alloc, __enable_if_t<__is_allocator<_Alloc>::value, int> = 0> -stack(from_range_t, - _Range&&, - _Alloc) -> stack<ranges::range_value_t<_Range>, deque<ranges::range_value_t<_Range>, _Alloc>>; + __enable_if_t<__is_allocator_v<_Alloc>, int> = 0> +stack(_InputIterator, _InputIterator, _Alloc) + -> stack<__iterator_value_type<_InputIterator>, deque<__iterator_value_type<_InputIterator>, _Alloc>>; + +template <ranges::input_range _Range, class _Alloc, __enable_if_t<__is_allocator_v<_Alloc>, int> = 0> +stack(from_range_t, _Range&&, _Alloc) + -> stack<ranges::range_value_t<_Range>, deque<ranges::range_value_t<_Range>, _Alloc>>; # endif diff --git a/lib/libcxx/include/stddef.h b/lib/libcxx/include/stddef.h @@ -25,24 +25,24 @@ Types: */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/stddef.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif // Note: This include is outside of header guards because we sometimes get included multiple times // with different defines and the underlying <stddef.h> will know how to deal with that. -# include_next <stddef.h> +#include_next <stddef.h> -# ifndef _LIBCPP_STDDEF_H -# define _LIBCPP_STDDEF_H +#ifndef _LIBCPP_STDDEF_H +# define _LIBCPP_STDDEF_H -# ifdef __cplusplus +# ifdef __cplusplus typedef decltype(nullptr) nullptr_t; -# endif -# endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# endif #endif // _LIBCPP_STDDEF_H diff --git a/lib/libcxx/include/stdexcept b/lib/libcxx/include/stdexcept @@ -91,7 +91,7 @@ public: ~logic_error() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; # else public: @@ -115,7 +115,7 @@ public: ~runtime_error() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; # else public: diff --git a/lib/libcxx/include/stdio.h b/lib/libcxx/include/stdio.h @@ -88,35 +88,34 @@ void perror(const char* s); */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/stdio.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif // The inclusion of the system's <stdio.h> is intentionally done once outside of any include // guards because some code expects to be able to include the underlying system header multiple // times to get different definitions based on the macros that are set before inclusion. -# if __has_include_next(<stdio.h>) -# include_next <stdio.h> -# endif +#if __has_include_next(<stdio.h>) +# include_next <stdio.h> +#endif -# ifndef _LIBCPP_STDIO_H -# define _LIBCPP_STDIO_H +#ifndef _LIBCPP_STDIO_H +# define _LIBCPP_STDIO_H -# ifdef __cplusplus +# ifdef __cplusplus -# undef getc -# undef putc -# undef clearerr -# undef feof -# undef ferror -# undef putchar -# undef getchar +# undef getc +# undef putc +# undef clearerr +# undef feof +# undef ferror +# undef putchar +# undef getchar -# endif // __cplusplus -# endif // _LIBCPP_STDIO_H - -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +# endif // __cplusplus +#endif // _LIBCPP_STDIO_H diff --git a/lib/libcxx/include/streambuf b/lib/libcxx/include/streambuf @@ -119,6 +119,7 @@ protected: # include <__locale> # include <__type_traits/is_same.h> # include <__utility/is_valid_range.h> +# include <__utility/scope_guard.h> # include <climits> # include <ios> # include <iosfwd> @@ -149,47 +150,56 @@ public: virtual ~basic_streambuf() {} // 27.6.2.2.1 locales: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale pubimbue(const locale& __loc) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale pubimbue(const locale& __loc) { imbue(__loc); locale __r = __loc_; __loc_ = __loc; return __r; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 locale getloc() const { return __loc_; } + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 locale getloc() const { return __loc_; } // 27.6.2.2.2 buffer and positioning: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 basic_streambuf* pubsetbuf(char_type* __s, streamsize __n) { return setbuf(__s, __n); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type pubseekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __which = ios_base::in | ios_base::out) { return seekoff(__off, __way, __which); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 pos_type + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 pos_type pubseekpos(pos_type __sp, ios_base::openmode __which = ios_base::in | ios_base::out) { return seekpos(__sp, __which); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int pubsync() { return sync(); } + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int pubsync() { return sync(); } // Get and put areas: // 27.6.2.2.3 Get area: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize in_avail() { + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize in_avail() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (gptr() < egptr()) return static_cast<streamsize>(egptr() - gptr()); return showmanyc(); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type snextc() { + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type snextc() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (sbumpc() == traits_type::eof()) return traits_type::eof(); return sgetc(); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sbumpc() { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sbumpc() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (gptr() == egptr()) return uflow(); int_type __c = traits_type::to_int_type(*gptr()); @@ -197,23 +207,32 @@ public: return __c; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sgetc() { + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sgetc() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (gptr() == egptr()) return underflow(); return traits_type::to_int_type(*gptr()); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); } + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sgetn(char_type* __s, streamsize __n) { return xsgetn(__s, __n); } // 27.6.2.2.4 Putback: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputbackc(char_type __c) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputbackc(char_type __c) { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (eback() == gptr() || !traits_type::eq(__c, *(gptr() - 1))) return pbackfail(traits_type::to_int_type(__c)); this->gbump(-1); return traits_type::to_int_type(*gptr()); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sungetc() { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sungetc() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (eback() == gptr()) return pbackfail(); this->gbump(-1); @@ -221,7 +240,10 @@ public: } // 27.6.2.2.5 Put area: - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 int_type sputc(char_type __c) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 int_type sputc(char_type __c) { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (pptr() == epptr()) return overflow(traits_type::to_int_type(__c)); *pptr() = __c; @@ -229,7 +251,7 @@ public: return traits_type::to_int_type(__c); } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 streamsize sputn(const char_type* __s, streamsize __n) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 streamsize sputn(const char_type* __s, streamsize __n) { return xsputn(__s, __n); } @@ -270,12 +292,12 @@ protected: _LIBCPP_HIDE_FROM_ABI char_type* gptr() const { return __ninp_; } _LIBCPP_HIDE_FROM_ABI char_type* egptr() const { return __einp_; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void gbump(int __n) { __ninp_ += __n; } + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void gbump(int __n) { __ninp_ += __n; } // gbump takes an int, so it might not be able to represent the offset we want to add. _LIBCPP_HIDE_FROM_ABI void __gbump_ptrdiff(ptrdiff_t __n) { __ninp_ += __n; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setg(char_type* __gbeg, char_type* __gnext, char_type* __gend) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gnext), "[gbeg, gnext) must be a valid range"); _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gbeg, __gend), "[gbeg, gend) must be a valid range"); _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__gnext, __gend), "[gnext, gend) must be a valid range"); @@ -289,11 +311,11 @@ protected: _LIBCPP_HIDE_FROM_ABI char_type* pptr() const { return __nout_; } _LIBCPP_HIDE_FROM_ABI char_type* epptr() const { return __eout_; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void pbump(int __n) { __nout_ += __n; } + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void pbump(int __n) { __nout_ += __n; } _LIBCPP_HIDE_FROM_ABI void __pbump(streamsize __n) { __nout_ += __n; } - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 void setp(char_type* __pbeg, char_type* __pend) { + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 void setp(char_type* __pbeg, char_type* __pend) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(std::__is_valid_range(__pbeg, __pend), "[pbeg, pend) must be a valid range"); __bout_ = __nout_ = __pbeg; __eout_ = __pend; @@ -317,6 +339,9 @@ protected: virtual streamsize showmanyc() { return 0; } virtual streamsize xsgetn(char_type* __s, streamsize __n) { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + int_type __c; streamsize __i = 0; while (__i < __n) { @@ -338,6 +363,9 @@ protected: virtual int_type underflow() { return traits_type::eof(); } virtual int_type uflow() { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + if (underflow() == traits_type::eof()) return traits_type::eof(); int_type __c = traits_type::to_int_type(*gptr()); @@ -350,6 +378,9 @@ protected: // 27.6.2.4.5 Put area: virtual streamsize xsputn(const char_type* __s, streamsize __n) { + __check_invariants(); + auto __guard = std::__make_scope_guard([this] { this->__check_invariants(); }); + streamsize __i = 0; while (__i < __n) { if (pptr() >= epptr()) { @@ -370,6 +401,15 @@ protected: virtual int_type overflow(int_type = traits_type::eof()) { return traits_type::eof(); } + // This function checks some invariants of the class (it isn't exhaustive). + _LIBCPP_HIDE_FROM_ABI void __check_invariants() const { + _LIBCPP_ASSERT_INTERNAL(pbase() <= pptr(), "this is an invariant of the class"); + _LIBCPP_ASSERT_INTERNAL(pptr() <= epptr(), "this is an invariant of the class"); + + _LIBCPP_ASSERT_INTERNAL(eback() <= gptr(), "this is an invariant of the class"); + _LIBCPP_ASSERT_INTERNAL(gptr() <= egptr(), "this is an invariant of the class"); + } + private: locale __loc_; char_type* __binp_ = nullptr; diff --git a/lib/libcxx/include/string b/lib/libcxx/include/string @@ -280,6 +280,8 @@ public: basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23 basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23 constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23 + constexpr basic_string_view<charT, traits> subview(size_type pos = 0, + size_type n = npos) const; // since C++26 void swap(basic_string& str) noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value || allocator_traits<allocator_type>::is_always_equal::value); // C++17, constexpr since C++20 @@ -598,9 +600,9 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); # include <__debug_utils/sanitizers.h> # include <__format/enable_insertable.h> # include <__functional/hash.h> +# include <__functional/is_transparent.h> # include <__functional/unary_function.h> # include <__fwd/string.h> -# include <__ios/fpos.h> # include <__iterator/bounded_iter.h> # include <__iterator/distance.h> # include <__iterator/iterator_traits.h> @@ -620,7 +622,6 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); # include <__ranges/concepts.h> # include <__ranges/container_compatible_range.h> # include <__ranges/from_range.h> -# include <__ranges/size.h> # include <__string/char_traits.h> # include <__string/extern_template_lists.h> # include <__type_traits/conditional.h> @@ -628,24 +629,23 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len ); # include <__type_traits/is_allocator.h> # include <__type_traits/is_array.h> # include <__type_traits/is_convertible.h> +# include <__type_traits/is_generic_transparent_comparator.h> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_standard_layout.h> # include <__type_traits/is_trivially_constructible.h> # include <__type_traits/is_trivially_copyable.h> # include <__type_traits/is_trivially_relocatable.h> # include <__type_traits/remove_cvref.h> -# include <__type_traits/void_t.h> -# include <__utility/auto_cast.h> -# include <__utility/declval.h> +# include <__utility/default_three_way_comparator.h> +# include <__utility/exception_guard.h> # include <__utility/forward.h> # include <__utility/is_pointer_in_range.h> # include <__utility/move.h> +# include <__utility/no_destroy.h> # include <__utility/scope_guard.h> # include <__utility/swap.h> -# include <__utility/unreachable.h> # include <climits> # include <cstdio> // EOF # include <cstring> @@ -700,18 +700,18 @@ __concatenate_strings(const _Allocator& __alloc, __type_identity_t<basic_string_view<_CharT, _Traits> > __str2); template <class _Iter> -struct __string_is_trivial_iterator : public false_type {}; +inline const bool __string_is_trivial_iterator_v = false; template <class _Tp> -struct __string_is_trivial_iterator<_Tp*> : public is_arithmetic<_Tp> {}; +inline const bool __string_is_trivial_iterator_v<_Tp*> = is_arithmetic<_Tp>::value; template <class _Iter> -struct __string_is_trivial_iterator<__wrap_iter<_Iter> > : public __string_is_trivial_iterator<_Iter> {}; +inline const bool __string_is_trivial_iterator_v<__wrap_iter<_Iter> > = __string_is_trivial_iterator_v<_Iter>; template <class _CharT, class _Traits, class _Tp> -struct __can_be_converted_to_string_view - : public _BoolConstant< is_convertible<const _Tp&, basic_string_view<_CharT, _Traits> >::value && - !is_convertible<const _Tp&, const _CharT*>::value > {}; +inline const bool __can_be_converted_to_string_view_v = + is_convertible<const _Tp&, basic_string_view<_CharT, _Traits> >::value && + !is_convertible<const _Tp&, const _CharT*>::value; struct __uninitialized_size_tag {}; struct __init_with_sentinel_tag {}; @@ -756,20 +756,13 @@ public: // external memory. In such cases, the destructor is responsible for unpoisoning // the memory to avoid triggering false positives. // Therefore it's crucial to ensure the destructor is called. - // - // However, it is replaceable since implementing move-assignment as a destroy + move-construct - // will maintain the right ASAN state. - using __trivially_relocatable = void; + using __trivially_relocatable _LIBCPP_NODEBUG = void; # else using __trivially_relocatable _LIBCPP_NODEBUG = __conditional_t< __libcpp_is_trivially_relocatable<allocator_type>::value && __libcpp_is_trivially_relocatable<pointer>::value, basic_string, void>; # endif - using __replaceable _LIBCPP_NODEBUG = - __conditional_t<__is_replaceable_v<pointer> && __container_allocator_is_replaceable<__alloc_traits>::value, - basic_string, - void>; # if __has_feature(address_sanitizer) && _LIBCPP_INSTRUMENTED_WITH_ASAN _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __asan_volatile_wrapper(pointer const& __ptr) const { @@ -819,12 +812,21 @@ public: using reverse_iterator = std::reverse_iterator<iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>; + using __alloc_result _LIBCPP_NODEBUG = __allocation_result<pointer, size_type>; + private: static_assert(CHAR_BIT == 8, "This implementation assumes that one byte contains 8 bits"); # ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT struct __long { + __long() = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size) + : __data_(__alloc.ptr), __size_(__size), __cap_(__alloc.count / __endian_factor), __is_long_(true) { + _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO"); + } + pointer __data_; size_type __size_; size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; @@ -872,6 +874,13 @@ private: // some platforms bit fields have a default size rather than the actual // size used, e.g., it is 4 bytes on AIX. See D128285 for details. struct __long { + __long() = default; + + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __long(__alloc_result __alloc, size_type __size) + : __is_long_(true), __cap_(__alloc.count / __endian_factor), __size_(__size), __data_(__alloc.ptr) { + _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__alloc.count), "Long capacity should always be larger than the SSO"); + } + struct _LIBCPP_PACKED { size_type __is_long_ : 1; size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; @@ -898,6 +907,11 @@ private: union __rep { __short __s; __long __l; + + __rep() = default; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep(__short __r) : __s(__r) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep(__long __r) : __l(__r) {} + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __rep(__uninitialized_tag) {} }; _LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_); @@ -917,20 +931,7 @@ private: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string( __uninitialized_size_tag, size_type __size, const allocator_type& __a) : __alloc_(__a) { - if (__size > max_size()) - this->__throw_length_error(); - if (__fits_in_sso(__size)) { - __rep_ = __rep(); - __set_short_size(__size); - } else { - auto __capacity = __recommend(__size) + 1; - auto __allocation = __alloc_traits::allocate(__alloc_, __capacity); - __begin_lifetime(__allocation, __capacity); - __set_long_cap(__capacity); - __set_long_pointer(__allocation); - __set_long_size(__size); - } - __annotate_new(__size); + __init_internal_buffer(__size); } template <class _Iter, class _Sent> @@ -966,7 +967,7 @@ private: std::__wrap_iter<const_pointer>(__get_pointer() + size())); # else return const_iterator(__p); -# endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING +# endif // _LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING } public: @@ -1057,13 +1058,13 @@ public: } # endif // _LIBCPP_CXX03_LANG - template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s) { _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "basic_string(const char*) detected nullptr"); __init(__s, traits_type::length(__s)); } - template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(const _CharT* _LIBCPP_DIAGNOSE_NULLPTR __s, const _Allocator& __a) : __alloc_(__a) { @@ -1075,13 +1076,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); @@ -1110,7 +1113,7 @@ public: } # endif - template <__enable_if_t<__is_allocator<_Allocator>::value, int> = 0> + template <__enable_if_t<__is_allocator_v<_Allocator>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c, const _Allocator& __a) : __alloc_(__a) { __init(__n, __c); @@ -1135,7 +1138,7 @@ public: } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 @@ -1147,7 +1150,7 @@ public: } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t) { @@ -1156,7 +1159,7 @@ public: } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit basic_string(const _Tp& __t, const allocator_type& __a) @@ -1201,11 +1204,10 @@ public: } # endif // _LIBCPP_CXX03_LANG - inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { - __annotate_delete(); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - } + // TODO(boomanaiden154): Once we mark this in destructors as dead on return, + // we can use a normal call to __reset_internal_buffer and remove the extra + // __rep constructor. + inline _LIBCPP_CONSTEXPR_SINCE_CXX20 ~basic_string() { __reset_internal_buffer(__rep(__uninitialized_tag())); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 operator __self_view() const _NOEXCEPT { return __self_view(typename __self_view::__assume_valid(), data(), size()); @@ -1215,7 +1217,7 @@ public: operator=(const basic_string& __str); template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(const _Tp& __t) { @@ -1243,45 +1245,55 @@ public: # endif _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator=(value_type __c); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator begin() _NOEXCEPT { return __make_iterator(__get_pointer()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator begin() const _NOEXCEPT { return __make_const_iterator(__get_pointer()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator end() _NOEXCEPT { return __make_iterator(__get_pointer() + size()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator end() const _NOEXCEPT { return __make_const_iterator(__get_pointer() + 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 begin(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT { return end(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cbegin() const _NOEXCEPT { + return begin(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_iterator cend() const _NOEXCEPT { + return end(); + } + [[__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 size_type size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type size() const _NOEXCEPT { return __is_long() ? __get_long_size() : __get_short_size(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type length() const _NOEXCEPT { return size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type length() const _NOEXCEPT { + return size(); + } - _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 max_size() const _NOEXCEPT { if (size_type __m = __alloc_traits::max_size(__alloc_); __m <= std::numeric_limits<size_type>::max() / 2) { size_type __res = __m - __alignment; @@ -1299,7 +1311,7 @@ public: } } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type capacity() const _NOEXCEPT { return (__is_long() ? __get_long_cap() : static_cast<size_type>(__min_cap)) - 1; } @@ -1311,13 +1323,19 @@ public: # if _LIBCPP_STD_VER >= 23 template <class _Op> _LIBCPP_HIDE_FROM_ABI constexpr void resize_and_overwrite(size_type __n, _Op __op) { - __resize_default_init(__n); - __erase_to_end(std::move(__op)(data(), _LIBCPP_AUTO_CAST(__n))); + using __result_type = decltype(std::move(__op)(data(), auto(__n))); + static_assert(__integer_like<__result_type>, "Operation return type must be integer-like"); + size_type __sz = size(); + size_type __cap = capacity(); + if (__n > __cap) + __grow_by_without_replace(__cap, __n - __cap, __sz, __sz, 0); + __annotate_delete(); + __set_size(__n); + __annotate_new(__n); + __erase_to_end(std::move(__op)(data(), auto(__n))); } # endif - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __resize_default_init(size_type __n); - # if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_STRING_RESERVE) _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void reserve() _NOEXCEPT { shrink_to_fit(); } # endif @@ -1328,7 +1346,8 @@ public: return size() == 0; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference + operator[](size_type __pos) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { return *(__get_long_pointer() + __pos); @@ -1336,7 +1355,8 @@ public: return *(data() + __pos); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference + operator[](size_type __pos) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { return *(__get_long_pointer() + __pos); @@ -1344,15 +1364,15 @@ public: return *(__get_pointer() + __pos); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const; - _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n); + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference at(size_type __n) const; + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 reference at(size_type __n); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator+=(const basic_string& __str) { return append(__str); } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& operator+=(const _Tp& __t) { @@ -1381,7 +1401,7 @@ public: } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const _Tp& __t) { @@ -1392,7 +1412,7 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(const basic_string& __str, size_type __pos, size_type __n = npos); template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& @@ -1404,12 +1424,11 @@ 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); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __append_default_init(size_type __n); - template <class _InputIterator, __enable_if_t<__has_exactly_input_iterator_category<_InputIterator>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& append(_InputIterator __first, _InputIterator __last) { @@ -1424,20 +1443,21 @@ public: size_type __sz = size(); size_type __cap = capacity(); size_type __n = static_cast<size_type>(std::distance(__first, __last)); - if (__n) { - if (__string_is_trivial_iterator<_ForwardIterator>::value && !__addr_in_range(*__first)) { - if (__cap - __sz < __n) - __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); - __annotate_increase(__n); - auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__get_pointer() + __sz)); - traits_type::assign(*__end, value_type()); - __set_size(__sz + __n); - } else { - const basic_string __temp(__first, __last, __alloc_); - append(__temp.data(), __temp.size()); - } + if (__n == 0) + return *this; + + if (__string_is_trivial_iterator_v<_ForwardIterator> && !__addr_in_range(*__first)) { + if (__cap - __sz < __n) + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); + auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__get_pointer() + __sz)); + traits_type::assign(*__end, value_type()); + __set_size(__sz + __n); + return *this; + } else { + const basic_string __temp(__first, __last, __alloc_); + return append(__temp.data(), __temp.size()); } - return *this; } # if _LIBCPP_STD_VER >= 23 @@ -1457,27 +1477,27 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 void push_back(value_type __c); _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back(); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty"); return *__get_pointer(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty"); return *data(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty"); return *(__get_pointer() + size() - 1); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty"); return *(data() + size() - 1); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const _Tp& __t) { __self_view __sv = __t; return assign(__sv.data(), __sv.size()); @@ -1519,7 +1539,7 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(const basic_string& __str, size_type __pos, size_type __n = npos); template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& @@ -1531,8 +1551,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> @@ -1545,7 +1566,7 @@ public: template <class _ForwardIterator, __enable_if_t<__has_forward_iterator_category<_ForwardIterator>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& assign(_ForwardIterator __first, _ForwardIterator __last) { - if (__string_is_trivial_iterator<_ForwardIterator>::value) { + if (__string_is_trivial_iterator_v<_ForwardIterator>) { size_type __n = static_cast<size_type>(std::distance(__first, __last)); __assign_trivial(__first, __last, __n); } else { @@ -1558,7 +1579,7 @@ public: # if _LIBCPP_STD_VER >= 23 template <_ContainerCompatibleRange<_CharT> _Range> _LIBCPP_HIDE_FROM_ABI constexpr basic_string& assign_range(_Range&& __range) { - if constexpr (__string_is_trivial_iterator<ranges::iterator_t<_Range>>::value && + if constexpr (__string_is_trivial_iterator_v<ranges::iterator_t<_Range>> && (ranges::forward_range<_Range> || ranges::sized_range<_Range>)) { size_type __n = static_cast<size_type>(ranges::distance(__range)); __assign_trivial(ranges::begin(__range), ranges::end(__range), __n); @@ -1582,14 +1603,14 @@ public: return insert(__pos1, __str.data(), __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& insert(size_type __pos1, const _Tp& __t) { __self_view __sv = __t; return insert(__pos1, __sv.data(), __sv.size()); } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& @@ -1603,7 +1624,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); @@ -1659,7 +1681,7 @@ public: return replace(__pos1, __n1, __str.data(), __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(size_type __pos1, size_type __n1, const _Tp& __t) { __self_view __sv = __t; @@ -1670,7 +1692,7 @@ public: replace(size_type __pos1, size_type __n1, const basic_string& __str, size_type __pos2, size_type __n2 = npos); template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& @@ -1683,8 +1705,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& @@ -1693,7 +1717,7 @@ public: static_cast<size_type>(__i1 - begin()), static_cast<size_type>(__i2 - __i1), __str.data(), __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string& replace(const_iterator __i1, const_iterator __i2, const _Tp& __t) { __self_view __sv = __t; @@ -1741,19 +1765,24 @@ public: _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type copy(value_type* __s, size_type __n, size_type __pos = 0) const; # if _LIBCPP_STD_VER <= 20 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string - substr(size_type __pos = 0, size_type __n = npos) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string substr(size_type __pos = 0, size_type __n = npos) const { return basic_string(*this, __pos, __n); } # else - _LIBCPP_HIDE_FROM_ABI constexpr basic_string substr(size_type __pos = 0, size_type __n = npos) const& { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr basic_string substr(size_type __pos = 0, size_type __n = npos) const& { return basic_string(*this, __pos, __n); } - _LIBCPP_HIDE_FROM_ABI constexpr basic_string substr(size_type __pos = 0, size_type __n = npos) && { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr basic_string substr(size_type __pos = 0, size_type __n = npos) && { return basic_string(std::move(*this), __pos, __n); } # endif +# if _LIBCPP_STD_VER >= 26 + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __self_view subview(size_type __pos = 0, size_type __n = npos) const { + return __self_view(*this).subview(__pos, __n); + } +# endif _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(basic_string& __str) # if _LIBCPP_STD_VER >= 14 @@ -1765,225 +1794,238 @@ public: // [string.ops] // ------------ - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const value_type* c_str() const _NOEXCEPT { return data(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const value_type* data() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const value_type* c_str() const _NOEXCEPT { + return data(); + } + + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const value_type* data() const _NOEXCEPT { return std::__to_address(__get_pointer()); } # if _LIBCPP_STD_VER >= 17 - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 value_type* data() _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 value_type* data() _NOEXCEPT { return std::__to_address(__get_pointer()); } # 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 __alloc_; } // find - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT { return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(const _Tp& __t, size_type __pos = 0) const _NOEXCEPT { __self_view __sv = __t; 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 { + [[__nodiscard__]] _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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::find(): received nullptr"); return std::__str_find<value_type, size_type, traits_type, npos>( data(), size(), __s, __pos, traits_type::length(__s)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(value_type __c, size_type __pos = 0) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find(value_type __c, size_type __pos = 0) const _NOEXCEPT { return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } // rfind - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT { return std::__str_rfind<value_type, size_type, traits_type, npos>( data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(const _Tp& __t, size_type __pos = npos) const _NOEXCEPT { __self_view __sv = __t; 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 { + [[__nodiscard__]] _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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::rfind(): received nullptr"); return std::__str_rfind<value_type, size_type, traits_type, npos>( data(), size(), __s, __pos, traits_type::length(__s)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type rfind(value_type __c, size_type __pos = npos) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + rfind(value_type __c, size_type __pos = npos) const _NOEXCEPT { return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } // find_first_of - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_of(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT { return std::__str_find_first_of<value_type, size_type, traits_type, npos>( data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_of(const _Tp& __t, size_type __pos = 0) const _NOEXCEPT { __self_view __sv = __t; return std::__str_find_first_of<value_type, size_type, traits_type, npos>( data(), size(), __sv.data(), __pos, __sv.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type - find_first_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + 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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_of(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__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, traits_type::length(__s)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_of(value_type __c, size_type __pos = 0) const _NOEXCEPT { return find(__c, __pos); } // find_last_of - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_of(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT { return std::__str_find_last_of<value_type, size_type, traits_type, npos>( data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_of(const _Tp& __t, size_type __pos = npos) const _NOEXCEPT { __self_view __sv = __t; return std::__str_find_last_of<value_type, size_type, traits_type, npos>( data(), size(), __sv.data(), __pos, __sv.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type - find_last_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + 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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_of(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__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, traits_type::length(__s)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_of(value_type __c, size_type __pos = npos) const _NOEXCEPT { return rfind(__c, __pos); } // find_first_not_of - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_not_of(const basic_string& __str, size_type __pos = 0) const _NOEXCEPT { return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>( data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_not_of(const _Tp& __t, size_type __pos = 0) const _NOEXCEPT { __self_view __sv = __t; return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>( data(), size(), __sv.data(), __pos, __sv.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type - find_first_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + 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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_not_of(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = 0) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__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, traits_type::length(__s)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_first_not_of(value_type __c, size_type __pos = 0) const _NOEXCEPT { return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } // find_last_not_of - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_not_of(const basic_string& __str, size_type __pos = npos) const _NOEXCEPT { return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>( data(), size(), __str.data(), __pos, __str.size()); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_not_of(const _Tp& __t, size_type __pos = npos) const _NOEXCEPT { __self_view __sv = __t; return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>( data(), size(), __sv.data(), __pos, __sv.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type - find_last_not_of(const value_type* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + 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); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_not_of(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s, size_type __pos = npos) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__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, traits_type::length(__s)); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type find_last_not_of(value_type __c, size_type __pos = npos) const _NOEXCEPT { return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } // compare - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(const basic_string& __str) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int + compare(const basic_string& __str) const _NOEXCEPT { return compare(__self_view(__str)); } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(const _Tp& __t) const _NOEXCEPT { + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(const _Tp& __t) const _NOEXCEPT { __self_view __sv = __t; size_t __lhs_sz = size(); size_t __rhs_sz = __sv.size(); @@ -1997,73 +2039,77 @@ public: return 0; } - template <class _Tp, __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int + template <class _Tp, __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp>, int> = 0> + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(size_type __pos1, size_type __n1, const _Tp& __t) const { __self_view __sv = __t; return compare(__pos1, __n1, __sv.data(), __sv.size()); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(size_type __pos1, size_type __n1, const basic_string& __str) const { return compare(__pos1, __n1, __str.data(), __str.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 int + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(size_type __pos1, size_type __n1, const basic_string& __str, size_type __pos2, size_type __n2 = npos) const { return compare(__pos1, __n1, __self_view(__str), __pos2, __n2); } template <class _Tp, - __enable_if_t<__can_be_converted_to_string_view<_CharT, _Traits, _Tp>::value && + __enable_if_t<__can_be_converted_to_string_view_v<_CharT, _Traits, _Tp> && !is_same<__remove_cvref_t<_Tp>, basic_string>::value, int> = 0> - inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int + [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(size_type __pos1, size_type __n1, const _Tp& __t, size_type __pos2, size_type __n2 = npos) const { __self_view __sv = __t; return __self_view(*this).substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 int + compare(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const _NOEXCEPT { _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::compare(): received nullptr"); return compare(0, npos, __s, traits_type::length(__s)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 int + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 int compare(size_type __pos1, size_type __n1, const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const { _LIBCPP_ASSERT_NON_NULL(__s != nullptr, "string::compare(): received nullptr"); return compare(__pos1, __n1, __s, traits_type::length(__s)); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 int - compare(size_type __pos1, size_type __n1, const value_type* __s, size_type __n2) const; + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX20 int + 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 # if _LIBCPP_STD_VER >= 20 - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(__self_view __sv) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(__self_view __sv) const noexcept { return __self_view(typename __self_view::__assume_valid(), data(), size()).starts_with(__sv); } - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(value_type __c) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(value_type __c) const noexcept { return !empty() && _Traits::eq(front(), __c); } - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool + starts_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept { return starts_with(__self_view(__s)); } // ends_with - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(__self_view __sv) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(__self_view __sv) const noexcept { return __self_view(typename __self_view::__assume_valid(), data(), size()).ends_with(__sv); } - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(value_type __c) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(value_type __c) const noexcept { return !empty() && _Traits::eq(back(), __c); } - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool + ends_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept { return ends_with(__self_view(__s)); } # endif @@ -2071,15 +2117,16 @@ public: // contains # if _LIBCPP_STD_VER >= 23 - constexpr _LIBCPP_HIDE_FROM_ABI bool contains(__self_view __sv) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool contains(__self_view __sv) const noexcept { return __self_view(typename __self_view::__assume_valid(), data(), size()).contains(__sv); } - constexpr _LIBCPP_HIDE_FROM_ABI bool contains(value_type __c) const noexcept { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool contains(value_type __c) const noexcept { return __self_view(typename __self_view::__assume_valid(), data(), size()).contains(__c); } - constexpr _LIBCPP_HIDE_FROM_ABI bool contains(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const { + [[__nodiscard__]] constexpr _LIBCPP_HIDE_FROM_ABI bool + contains(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const { return __self_view(typename __self_view::__assume_valid(), data(), size()).contains(__s); } # endif @@ -2095,18 +2142,6 @@ private: return __rep_.__s.__is_long_; } - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __begin_lifetime(pointer __begin, size_type __n) { -# if _LIBCPP_STD_VER >= 20 - if (__libcpp_is_constant_evaluated()) { - for (size_type __i = 0; __i != __n; ++__i) - std::construct_at(std::addressof(__begin[__i])); - } -# else - (void)__begin; - (void)__n; -# endif // _LIBCPP_STD_VER >= 20 - } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI static bool __fits_in_sso(size_type __sz) { return __sz < __min_cap; } template <class _Iterator, class _Sentinel> @@ -2165,6 +2200,9 @@ private: _LIBCPP_CONSTEXPR_SINCE_CXX20 iterator __insert_with_size(const_iterator __pos, _Iterator __first, _Sentinel __last, size_type __n); + // internal buffer accessors + // ------------------------- + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_STRING_INTERNAL_MEMORY_ACCESS void __set_short_size(size_type __s) _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__s < __min_cap, "__s should never be greater than or equal to the short string capacity"); @@ -2194,21 +2232,11 @@ private: __set_short_size(__s); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_cap(size_type __s) _NOEXCEPT { - _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__s), "Long capacity should always be larger than the SSO"); - __rep_.__l.__cap_ = __s / __endian_factor; - __rep_.__l.__is_long_ = true; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __get_long_cap() const _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long capacity"); return __rep_.__l.__cap_ * __endian_factor; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __set_long_pointer(pointer __p) _NOEXCEPT { - __rep_.__l.__data_ = __p; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __get_long_pointer() _NOEXCEPT { _LIBCPP_ASSERT_INTERNAL(__rep_.__l.__is_long_, "String has to be long when trying to get the long pointer"); return _LIBCPP_ASAN_VOLATILE_WRAPPER(__rep_.__l.__data_); @@ -2236,6 +2264,58 @@ private: return __is_long() ? __get_long_pointer() : __get_short_pointer(); } + // Internal buffer management + // -------------------------- + // + // These functions are only responsible for managing the buffer itself, not the value inside the buffer. As such, + // none of these facilities ensure that there is a null terminator at `data()[size()]`. + + // Allocate a buffer of __capacity size with __alloc and return it + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 __long + __allocate_long_buffer(_Allocator& __alloc, size_type __capacity) { + _LIBCPP_ASSERT_INTERNAL(!__fits_in_sso(__capacity), + "Trying to allocate long buffer for a capacity what would fit into the small buffer"); + auto __buffer = std::__allocate_at_least(__alloc, __align_allocation_size(__capacity)); + + if (__libcpp_is_constant_evaluated()) { + for (size_type __i = 0; __i != __buffer.count; ++__i) + std::__construct_at(std::addressof(__buffer.ptr[__i])); + } + + return __long(__buffer, __capacity); + } + + // Replace the current buffer with __new_rep. Deallocate the old long buffer if it exists. + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __reset_internal_buffer(__rep __new_rep = __short()) { + __annotate_delete(); + if (__is_long()) + __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __rep_ = __new_rep; + } + + // Initialize the internal buffer to hold __size elements + // The elements and null terminator have to be set by the caller + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pointer __init_internal_buffer(size_type __size) { + if (__libcpp_is_constant_evaluated()) + __rep_ = __rep(); + + if (__size > max_size()) + __throw_length_error(); + + if (__fits_in_sso(__size)) { + __set_short_size(__size); + __annotate_new(__size); + return __get_short_pointer(); + } else { + __rep_.__l = __allocate_long_buffer(__alloc_, __size); + __annotate_new(__size); + return __get_long_pointer(); + } + } + + // ASan annotation helpers + // ----------------------- + // The following functions are no-ops outside of AddressSanitizer mode. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __annotate_contiguous_container(const void* __old_mid, const void* __new_mid) const { @@ -2243,7 +2323,7 @@ private: (void)__new_mid; # if _LIBCPP_INSTRUMENTED_WITH_ASAN # if defined(__APPLE__) - // TODO: remove after addressing issue #96099 (https://github.com/llvm/llvm-project/issues/96099) + // TODO: remove after addressing issue #96099 (https://llvm.org/PR96099) if (!__is_long()) return; # endif @@ -2287,19 +2367,36 @@ private: return (__s + (__a - 1)) & ~(__a - 1); } enum { __alignment = 8 }; - static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type __recommend(size_type __s) _NOEXCEPT { - if (__s < __min_cap) { - return static_cast<size_type>(__min_cap) - 1; - } + + // This makes sure that we're using a capacity with some extra alignment, since allocators almost always over-align + // the allocations anyways, improving memory usage. More importantly, this ensures that the lowest bit is never set + // if __endian_factor == 2, allowing us to store whether we're in the long string inside the lowest bit. + _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + __align_allocation_size(size_type __size) _NOEXCEPT { + _LIBCPP_ASSERT_INTERNAL( + !__fits_in_sso(__size), "Trying to align allocation of a size which would fit into the SSO"); const size_type __boundary = sizeof(value_type) < __alignment ? __alignment / sizeof(value_type) : __endian_factor; - size_type __guess = __align_it<__boundary>(__s + 1) - 1; - if (__guess == __min_cap) + size_type __guess = __align_it<__boundary>(__size + 1); + if (__guess == __min_cap + 1) __guess += __endian_factor; - _LIBCPP_ASSERT_INTERNAL(__guess >= __s, "recommendation is below the requested size"); + _LIBCPP_ASSERT_INTERNAL(__guess >= __size, "aligned allocation size is below the requested size"); return __guess; } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 size_type + __get_amortized_growth_capacity(size_type __required_capacity) { + size_type __max_size = max_size(); + if (__required_capacity > __max_size) + __throw_length_error(); + size_type __current_cap = capacity(); + _LIBCPP_ASSERT_INTERNAL( + __current_cap < __required_capacity, "Trying to grow string even though there is enough capacity already?"); + if (__current_cap > __max_size / 2 - __alignment) + return __max_size; + return std::max(__required_capacity, 2 * __current_cap); + } + inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init(const value_type* __s, size_type __sz); inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void __init(size_type __n, value_type __c); @@ -2366,7 +2463,8 @@ private: // __erase_external_with_move is invoked for erase() invocations where // `n ~= npos`, likely requiring memory moves on the string data. - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void __erase_external_with_move(size_type __pos, size_type __n); + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void + __erase_external_with_move(size_type __pos, size_type __n) _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __copy_assign_alloc(const basic_string& __str) { __copy_assign_alloc( @@ -2378,24 +2476,14 @@ private: __alloc_ = __str.__alloc_; else { if (!__str.__is_long()) { - if (__is_long()) { - __annotate_delete(); - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __rep_ = __rep(); - } + __reset_internal_buffer(); __alloc_ = __str.__alloc_; } else { __annotate_delete(); - auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); - allocator_type __a = __str.__alloc_; - auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap()); - __begin_lifetime(__allocation.ptr, __allocation.count); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __alloc_ = std::move(__a); - __set_long_pointer(__allocation.ptr); - __set_long_cap(__allocation.count); - __set_long_size(__str.__get_long_size()); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); + auto __alloc = __str.__alloc_; + __reset_internal_buffer(__allocate_long_buffer(__alloc, __str.size())); + __alloc_ = std::move(__alloc); } } } @@ -2507,26 +2595,55 @@ _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_DECLARE, wchar_t) # endif # undef _LIBCPP_DECLARE +# if _LIBCPP_STD_VER <= 17 || !__has_builtin(__builtin_lt_synthesizes_from_spaceship) +template <class _CharT, class _Traits, class _Alloc> +struct __default_three_way_comparator<basic_string<_CharT, _Traits, _Alloc>, basic_string<_CharT, _Traits, _Alloc> > { + using __string_t _LIBCPP_NODEBUG = basic_string<_CharT, _Traits, _Alloc>; + + _LIBCPP_HIDE_FROM_ABI static int operator()(const __string_t& __lhs, const __string_t& __rhs) { + auto __min_len = std::min(__lhs.size(), __rhs.size()); + auto __ret = _Traits::compare(__lhs.data(), __rhs.data(), __min_len); + if (__ret == 0) + return __lhs.size() == __rhs.size() ? 0 : __lhs.size() < __rhs.size() ? -1 : 1; + return __ret; + } +}; +# endif + +template <class _Comparator, class _CharT, class _Traits, class _Alloc> +inline const bool __is_transparently_comparable_v<_Comparator, + basic_string<_CharT, _Traits, _Alloc>, + const _CharT*, + __enable_if_t<__is_generic_transparent_comparator_v<_Comparator> > > = + true; + +template <class _Comparator, class _CharT, class _Traits, class _Alloc, size_t _Np> +inline const bool __is_transparently_comparable_v<_Comparator, + basic_string<_CharT, _Traits, _Alloc>, + _CharT[_Np], + __enable_if_t<__is_generic_transparent_comparator_v<_Comparator> > > = + true; + # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _CharT = __iter_value_type<_InputIterator>, + class _CharT = __iterator_value_type<_InputIterator>, class _Allocator = allocator<_CharT>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value> > + class = enable_if_t<__is_allocator_v<_Allocator>>> basic_string(_InputIterator, _InputIterator, _Allocator = _Allocator()) -> basic_string<_CharT, char_traits<_CharT>, _Allocator>; template <class _CharT, class _Traits, class _Allocator = allocator<_CharT>, - class = enable_if_t<__is_allocator<_Allocator>::value> > + class = enable_if_t<__is_allocator_v<_Allocator>>> explicit basic_string(basic_string_view<_CharT, _Traits>, const _Allocator& = _Allocator()) -> basic_string<_CharT, _Traits, _Allocator>; template <class _CharT, class _Traits, class _Allocator = allocator<_CharT>, - class = enable_if_t<__is_allocator<_Allocator>::value>, + class = enable_if_t<__is_allocator_v<_Allocator>>, class _Sz = typename allocator_traits<_Allocator>::size_type > basic_string(basic_string_view<_CharT, _Traits>, _Sz, _Sz, const _Allocator& = _Allocator()) -> basic_string<_CharT, _Traits, _Allocator>; @@ -2535,7 +2652,7 @@ basic_string(basic_string_view<_CharT, _Traits>, _Sz, _Sz, const _Allocator& = _ # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<__is_allocator<_Allocator>::value> > + class = enable_if_t<__is_allocator_v<_Allocator>>> basic_string(from_range_t, _Range&&, _Allocator = _Allocator()) -> basic_string<ranges::range_value_t<_Range>, char_traits<ranges::range_value_t<_Range>>, _Allocator>; # endif @@ -2543,73 +2660,23 @@ basic_string(from_range_t, _Range&&, _Allocator = _Allocator()) template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - if (__sz > max_size()) - this->__throw_length_error(); - pointer __p; - if (__fits_in_sso(__sz)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__sz); traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); - __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void basic_string<_CharT, _Traits, _Allocator>::__init_copy_ctor_external(const value_type* __s, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - - pointer __p; - if (__fits_in_sso(__sz)) { - __p = __get_short_pointer(); - __set_short_size(__sz); - } else { - if (__sz > max_size()) - this->__throw_length_error(); - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__sz); traits_type::copy(std::__to_address(__p), __s, __sz + 1); - __annotate_new(__sz); } template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init(size_type __n, value_type __c) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - - if (__n > max_size()) - this->__throw_length_error(); - pointer __p; - if (__fits_in_sso(__n)) { - __set_short_size(__n); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__n) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__n); - } + pointer __p = __init_internal_buffer(__n); traits_type::assign(std::__to_address(__p), __n, __c); traits_type::assign(__p[__n], value_type()); - __annotate_new(__n); } template <class _CharT, class _Traits, class _Allocator> @@ -2626,19 +2693,10 @@ basic_string<_CharT, _Traits, _Allocator>::__init_with_sentinel(_InputIterator _ __rep_ = __rep(); __annotate_new(0); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (; __first != __last; ++__first) - push_back(*__first); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __annotate_delete(); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([this] { __reset_internal_buffer(); }); + for (; __first != __last; ++__first) + push_back(*__first); + __guard.__complete(); } template <class _CharT, class _Traits, class _Allocator> @@ -2653,39 +2711,12 @@ template <class _CharT, class _Traits, class _Allocator> template <class _InputIterator, class _Sentinel> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __first, _Sentinel __last, size_type __sz) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); + pointer __p = __init_internal_buffer(__sz); - if (__sz > max_size()) - this->__throw_length_error(); - - pointer __p; - if (__fits_in_sso(__sz)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__sz) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } - -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - auto __end = __copy_non_overlapping_range(std::move(__first), std::move(__last), std::__to_address(__p)); - traits_type::assign(*__end, value_type()); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS - __annotate_new(__sz); + auto __guard = std::__make_exception_guard([this] { __reset_internal_buffer(); }); + auto __end = __copy_non_overlapping_range(std::move(__first), std::move(__last), std::__to_address(__p)); + traits_type::assign(*__end, value_type()); + __guard.__complete(); } template <class _CharT, class _Traits, class _Allocator> @@ -2697,32 +2728,22 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__ size_type __n_del, size_type __n_add, const value_type* __p_new_stuff) { - size_type __ms = max_size(); - if (__delta_cap > __ms - __old_cap) - __throw_length_error(); + __long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__old_cap + __delta_cap)); pointer __old_p = __get_pointer(); - size_type __cap = - __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; __annotate_delete(); - auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); - auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); - pointer __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); if (__n_copy != 0) - traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy); + traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__old_p), __n_copy); if (__n_add != 0) - traits_type::copy(std::__to_address(__p) + __n_copy, __p_new_stuff, __n_add); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy, __p_new_stuff, __n_add); size_type __sec_cp_sz = __old_sz - __n_del - __n_copy; if (__sec_cp_sz != 0) - traits_type::copy( - std::__to_address(__p) + __n_copy + __n_add, std::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz); - if (__old_cap + 1 != __min_cap) - __alloc_traits::deallocate(__alloc_, __old_p, __old_cap + 1); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __old_sz = __n_copy + __n_add + __sec_cp_sz; - __set_long_size(__old_sz); - traits_type::assign(__p[__old_sz], value_type()); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy + __n_add, + std::__to_address(__old_p) + __n_copy + __n_del, + __sec_cp_sz); + __buffer.__size_ = __n_copy + __n_add + __sec_cp_sz; + traits_type::assign(__buffer.__data_[__buffer.__size_], value_type()); + __reset_internal_buffer(__buffer); } // __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it @@ -2740,25 +2761,20 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait size_type __n_copy, size_type __n_del, size_type __n_add) { - size_type __ms = max_size(); - if (__delta_cap > __ms - __old_cap) - this->__throw_length_error(); + __long __buffer = __allocate_long_buffer(__alloc_, __get_amortized_growth_capacity(__old_cap + __delta_cap)); pointer __old_p = __get_pointer(); - size_type __cap = - __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms; - auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1); - pointer __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); if (__n_copy != 0) - traits_type::copy(std::__to_address(__p), std::__to_address(__old_p), __n_copy); + traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__old_p), __n_copy); size_type __sec_cp_sz = __old_sz - __n_del - __n_copy; if (__sec_cp_sz != 0) - traits_type::copy( - std::__to_address(__p) + __n_copy + __n_add, std::__to_address(__old_p) + __n_copy + __n_del, __sec_cp_sz); - if (__old_cap + 1 != __min_cap) - __alloc_traits::deallocate(__alloc_, __old_p, __old_cap + 1); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); + traits_type::copy(std::__to_address(__buffer.__data_) + __n_copy + __n_add, + std::__to_address(__old_p) + __n_copy + __n_del, + __sec_cp_sz); + + // This is -1 to make sure the caller sets the size properly, since old versions of this function didn't set the size + // at all. + __buffer.__size_ = -1; + __reset_internal_buffer(__buffer); } template <class _CharT, class _Traits, class _Allocator> @@ -2775,6 +2791,7 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace( _LIBCPP_SUPPRESS_DEPRECATED_PUSH __grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add); _LIBCPP_SUPPRESS_DEPRECATED_POP + // Due to the ABI of __grow_by we have to set the size after calling it. __set_long_size(__old_sz - __n_del + __n_add); } @@ -2786,24 +2803,23 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE basic_string<_CharT, _Traits, _Al basic_string<_CharT, _Traits, _Allocator>::__assign_no_alias(const value_type* __s, size_type __n) { const auto __cap = __is_short ? static_cast<size_type>(__min_cap) : __get_long_cap(); const auto __size = __is_short ? __get_short_size() : __get_long_size(); - if (__n < __cap) { - if (__n > __size) - __annotate_increase(__n - __size); - pointer __p; - if (__is_short) { - __p = __get_short_pointer(); - __set_short_size(__n); - } else { - __p = __get_long_pointer(); - __set_long_size(__n); - } - traits_type::copy(std::__to_address(__p), __s, __n); - traits_type::assign(__p[__n], value_type()); - if (__size > __n) - __annotate_shrink(__size); - } else { + if (__n >= __cap) { __grow_by_and_replace(__cap - 1, __n - __cap + 1, __size, 0, __size, __n, __s); + return *this; } + + __annotate_delete(); + auto __guard = std::__make_scope_guard(__annotate_new_size(*this)); + pointer __p; + if (__is_short) { + __p = __get_short_pointer(); + __set_short_size(__n); + } else { + __p = __get_long_pointer(); + __set_long_size(__n); + } + traits_type::copy(std::__to_address(__p), __s, __n); + traits_type::assign(__p[__n], value_type()); return *this; } @@ -2910,7 +2926,7 @@ basic_string<_CharT, _Traits, _Allocator>::__move_assign(basic_string& __str, tr { __annotate_delete(); if (__is_long()) { - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); + __reset_internal_buffer(); # if _LIBCPP_STD_VER <= 14 if (!is_nothrow_move_assignable<allocator_type>::value) { __set_short_size(0); @@ -2961,7 +2977,7 @@ template <class _Iterator, class _Sentinel> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void basic_string<_CharT, _Traits, _Allocator>::__assign_trivial(_Iterator __first, _Sentinel __last, size_type __n) { _LIBCPP_ASSERT_INTERNAL( - __string_is_trivial_iterator<_Iterator>::value, "The iterator type given to `__assign_trivial` must be trivial"); + __string_is_trivial_iterator_v<_Iterator>, "The iterator type given to `__assign_trivial` must be trivial"); size_type __old_size = size(); size_type __cap = capacity(); @@ -3017,52 +3033,40 @@ basic_string<_CharT, _Traits, _Allocator>::append(const value_type* __s, size_ty _LIBCPP_ASSERT_NON_NULL(__n == 0 || __s != nullptr, "string::append received nullptr"); size_type __cap = capacity(); size_type __sz = size(); - if (__cap - __sz >= __n) { - if (__n) { - __annotate_increase(__n); - value_type* __p = std::__to_address(__get_pointer()); - traits_type::copy(__p + __sz, __s, __n); - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); - } - } else + if (__cap - __sz < __n) { __grow_by_and_replace(__cap, __sz + __n - __cap, __sz, __sz, 0, __n, __s); + return *this; + } + + if (__n == 0) + return *this; + + __annotate_increase(__n); + value_type* __p = std::__to_address(__get_pointer()); + traits_type::copy(__p + __sz, __s, __n); + __sz += __n; + __set_size(__sz); + traits_type::assign(__p[__sz], value_type()); return *this; } template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<_CharT, _Traits, _Allocator>& basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c) { - if (__n) { - size_type __cap = capacity(); - size_type __sz = size(); - if (__cap - __sz < __n) - __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); - __annotate_increase(__n); - pointer __p = __get_pointer(); - traits_type::assign(std::__to_address(__p) + __sz, __n, __c); - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); - } - return *this; -} + if (__n == 0) + return *this; -template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n) { - if (__n) { - size_type __cap = capacity(); - size_type __sz = size(); - if (__cap - __sz < __n) - __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); - __annotate_increase(__n); - pointer __p = __get_pointer(); - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); - } + size_type __cap = capacity(); + size_type __sz = size(); + if (__cap - __sz < __n) + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __sz, 0); + __annotate_increase(__n); + pointer __p = __get_pointer(); + traits_type::assign(std::__to_address(__p) + __sz, __n, __c); + __sz += __n; + __set_size(__sz); + traits_type::assign(__p[__sz], value_type()); + return *this; } template <class _CharT, class _Traits, class _Allocator> @@ -3120,23 +3124,27 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, const value_t if (__pos > __sz) this->__throw_out_of_range(); size_type __cap = capacity(); - if (__cap - __sz >= __n) { - if (__n) { - __annotate_increase(__n); - value_type* __p = std::__to_address(__get_pointer()); - size_type __n_move = __sz - __pos; - if (__n_move != 0) { - if (std::__is_pointer_in_range(__p + __pos, __p + __sz, __s)) - __s += __n; - traits_type::move(__p + __pos + __n, __p + __pos, __n_move); - } - traits_type::move(__p + __pos, __s, __n); - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); - } - } else + + if (__cap - __sz < __n) { __grow_by_and_replace(__cap, __sz + __n - __cap, __sz, __pos, 0, __n, __s); + return *this; + } + + if (__n == 0) + return *this; + + __annotate_increase(__n); + value_type* __p = std::__to_address(__get_pointer()); + size_type __n_move = __sz - __pos; + if (__n_move != 0) { + if (std::__is_pointer_in_range(__p + __pos, __p + __sz, __s)) + __s += __n; + traits_type::move(__p + __pos + __n, __p + __pos, __n_move); + } + traits_type::move(__p + __pos, __s, __n); + __sz += __n; + __set_size(__sz); + traits_type::assign(__p[__sz], value_type()); return *this; } @@ -3146,24 +3154,26 @@ basic_string<_CharT, _Traits, _Allocator>::insert(size_type __pos, size_type __n size_type __sz = size(); if (__pos > __sz) this->__throw_out_of_range(); - if (__n) { - size_type __cap = capacity(); - value_type* __p; - if (__cap - __sz >= __n) { - __annotate_increase(__n); - __p = std::__to_address(__get_pointer()); - size_type __n_move = __sz - __pos; - if (__n_move != 0) - traits_type::move(__p + __pos + __n, __p + __pos, __n_move); - } else { - __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); - __p = std::__to_address(__get_long_pointer()); - } - traits_type::assign(__p + __pos, __n, __c); - __sz += __n; - __set_size(__sz); - traits_type::assign(__p[__sz], value_type()); + + if (__n == 0) + return *this; + + size_type __cap = capacity(); + value_type* __p; + if (__cap - __sz >= __n) { + __annotate_increase(__n); + __p = std::__to_address(__get_pointer()); + size_type __n_move = __sz - __pos; + if (__n_move != 0) + traits_type::move(__p + __pos + __n, __p + __pos, __n_move); + } else { + __grow_by_without_replace(__cap, __sz + __n - __cap, __sz, __pos, 0, __n); + __p = std::__to_address(__get_long_pointer()); } + traits_type::assign(__p + __pos, __n, __c); + __sz += __n; + __set_size(__sz); + traits_type::assign(__p[__sz], value_type()); return *this; } @@ -3176,7 +3186,7 @@ basic_string<_CharT, _Traits, _Allocator>::__insert_with_size( if (__n == 0) return begin() + __ip; - if (__string_is_trivial_iterator<_Iterator>::value && !__addr_in_range(*__first)) { + if (__string_is_trivial_iterator_v<_Iterator> && !__addr_in_range(*__first)) { return __insert_from_safe_copy(__n, __ip, std::move(__first), std::move(__last)); } else { const basic_string __temp(__init_with_sentinel_tag(), std::move(__first), std::move(__last), __alloc_); @@ -3237,38 +3247,38 @@ basic_string<_CharT, _Traits, _Allocator>::replace( this->__throw_out_of_range(); __n1 = std::min(__n1, __sz - __pos); size_type __cap = capacity(); - if (__cap - __sz + __n1 >= __n2) { - value_type* __p = std::__to_address(__get_pointer()); - if (__n1 != __n2) { - if (__n2 > __n1) - __annotate_increase(__n2 - __n1); - size_type __n_move = __sz - __pos - __n1; - if (__n_move != 0) { - if (__n1 > __n2) { - traits_type::move(__p + __pos, __s, __n2); - traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); - return __null_terminate_at(__p, __sz + (__n2 - __n1)); - } - if (std::__is_pointer_in_range(__p + __pos + 1, __p + __sz, __s)) { - if (__p + __pos + __n1 <= __s) - __s += __n2 - __n1; - else // __p + __pos < __s < __p + __pos + __n1 - { - traits_type::move(__p + __pos, __s, __n1); - __pos += __n1; - __s += __n2; - __n2 -= __n1; - __n1 = 0; - } - } + if (__cap - __sz + __n1 < __n2) { + __grow_by_and_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2, __s); + return *this; + } + + value_type* __p = std::__to_address(__get_pointer()); + if (__n1 != __n2) { + if (__n2 > __n1) + __annotate_increase(__n2 - __n1); + size_type __n_move = __sz - __pos - __n1; + if (__n_move != 0) { + if (__n1 > __n2) { + traits_type::move(__p + __pos, __s, __n2); traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); + return __null_terminate_at(__p, __sz + (__n2 - __n1)); + } + if (std::__is_pointer_in_range(__p + __pos + 1, __p + __sz, __s)) { + if (__p + __pos + __n1 <= __s) { + __s += __n2 - __n1; + } else { // __p + __pos < __s < __p + __pos + __n1 + traits_type::move(__p + __pos, __s, __n1); + __pos += __n1; + __s += __n2; + __n2 -= __n1; + __n1 = 0; + } } + traits_type::move(__p + __pos + __n2, __p + __pos + __n1, __n_move); } - traits_type::move(__p + __pos, __s, __n2); - return __null_terminate_at(__p, __sz + (__n2 - __n1)); - } else - __grow_by_and_replace(__cap, __sz - __n1 + __n2 - __cap, __sz, __pos, __n1, __n2, __s); - return *this; + } + traits_type::move(__p + __pos, __s, __n2); + return __null_terminate_at(__p, __sz + (__n2 - __n1)); } template <class _CharT, class _Traits, class _Allocator> @@ -3320,16 +3330,17 @@ basic_string<_CharT, _Traits, _Allocator>::replace(size_type __pos, size_type __ // Does not check __pos against size() template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NOINLINE void -basic_string<_CharT, _Traits, _Allocator>::__erase_external_with_move(size_type __pos, size_type __n) { - if (__n) { - size_type __sz = size(); - value_type* __p = std::__to_address(__get_pointer()); - __n = std::min(__n, __sz - __pos); - size_type __n_move = __sz - __pos - __n; - if (__n_move != 0) - traits_type::move(__p + __pos, __p + __pos + __n, __n_move); - __null_terminate_at(__p, __sz - __n); - } +basic_string<_CharT, _Traits, _Allocator>::__erase_external_with_move(size_type __pos, size_type __n) _NOEXCEPT { + if (__n == 0) + return; + + size_type __sz = size(); + value_type* __p = std::__to_address(__get_pointer()); + __n = std::min(__n, __sz - __pos); + size_type __n_move = __sz - __pos - __n; + if (__n_move != 0) + traits_type::move(__p + __pos, __p + __pos + __n, __n_move); + __null_terminate_at(__p, __sz - __n); } template <class _CharT, class _Traits, class _Allocator> @@ -3397,16 +3408,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re } template <class _CharT, class _Traits, class _Allocator> -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline void -basic_string<_CharT, _Traits, _Allocator>::__resize_default_init(size_type __n) { - size_type __sz = size(); - if (__n > __sz) { - __append_default_init(__n - __sz); - } else - __erase_to_end(__n); -} - -template <class _CharT, class _Traits, class _Allocator> _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::reserve(size_type __requested_capacity) { if (__requested_capacity > max_size()) this->__throw_length_error(); @@ -3418,31 +3419,23 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::re return; __annotation_guard __g(*this); - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__requested_capacity) + 1); - auto __size = size(); - __begin_lifetime(__allocation.ptr, __allocation.count); - traits_type::copy(std::__to_address(__allocation.ptr), data(), __size + 1); - if (__is_long()) - __alloc_traits::deallocate(__alloc_, __get_long_pointer(), __get_long_cap()); - __set_long_cap(__allocation.count); - __set_long_size(__size); - __set_long_pointer(__allocation.ptr); + __long __buffer = __allocate_long_buffer(__alloc_, __requested_capacity); + __buffer.__size_ = size(); + traits_type::copy(std::__to_address(__buffer.__data_), data(), __buffer.__size_ + 1); + __reset_internal_buffer(__buffer); } template <class _CharT, class _Traits, class _Allocator> inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::shrink_to_fit() _NOEXCEPT { - size_type __target_capacity = __recommend(size()); - if (__target_capacity == capacity()) + if (!__is_long()) return; - _LIBCPP_ASSERT_INTERNAL(__is_long(), "Trying to shrink small string"); - - // We're a long string and we're shrinking into the small buffer. const auto __ptr = __get_long_pointer(); const auto __size = __get_long_size(); const auto __cap = __get_long_cap(); - if (__fits_in_sso(__target_capacity)) { + // We're a long string and we're shrinking into the small buffer. + if (__fits_in_sso(__size)) { __annotation_guard __g(*this); __set_short_size(__size); traits_type::copy(std::__to_address(__get_short_pointer()), std::__to_address(__ptr), __size + 1); @@ -3450,25 +3443,25 @@ inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocat return; } + if (__align_allocation_size(__size) == __cap) + return; + # if _LIBCPP_HAS_EXCEPTIONS try { # endif // _LIBCPP_HAS_EXCEPTIONS __annotation_guard __g(*this); - auto __allocation = std::__allocate_at_least(__alloc_, __target_capacity + 1); + __long __buffer = __allocate_long_buffer(__alloc_, __size); // The Standard mandates shrink_to_fit() does not increase the capacity. // With equal capacity keep the existing buffer. This avoids extra work // due to swapping the elements. - if (__allocation.count - 1 >= capacity()) { - __alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count); + if (__buffer.__cap_ * __endian_factor - 1 >= capacity()) { + __alloc_traits::deallocate(__alloc_, __buffer.__data_, __buffer.__cap_ * __endian_factor); return; } - __begin_lifetime(__allocation.ptr, __allocation.count); - traits_type::copy(std::__to_address(__allocation.ptr), std::__to_address(__ptr), __size + 1); - __alloc_traits::deallocate(__alloc_, __ptr, __cap); - __set_long_cap(__allocation.count); - __set_long_pointer(__allocation.ptr); + traits_type::copy(std::__to_address(__buffer.__data_), std::__to_address(__get_long_pointer()), __size + 1); + __reset_internal_buffer(__buffer); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { return; @@ -3574,7 +3567,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>; @@ -3858,46 +3852,52 @@ swap(basic_string<_CharT, _Traits, _Allocator>& __lhs, basic_string<_CharT, _Tra __lhs.swap(__rhs); } -_LIBCPP_EXPORTED_FROM_ABI int stoi(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long stol(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long stoul(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long long stoll(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long long stoull(const string& __str, size_t* __idx = nullptr, int __base = 10); - -_LIBCPP_EXPORTED_FROM_ABI float stof(const string& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr); - -_LIBCPP_EXPORTED_FROM_ABI string to_string(int __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(float __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(double __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int stoi(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long +stoul(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long stol(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long long +stoll(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long long +stoull(const string& __str, size_t* __idx = nullptr, int __base = 10); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI float stof(const string& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val); # if _LIBCPP_HAS_WIDE_CHARACTERS -_LIBCPP_EXPORTED_FROM_ABI int stoi(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long stol(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long stoul(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long long stoll(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long long stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10); - -_LIBCPP_EXPORTED_FROM_ABI float stof(const wstring& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr); - -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int stoi(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long stol(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long +stoul(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long long +stoll(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long long +stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI float stof(const wstring& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val); # endif // _LIBCPP_HAS_WIDE_CHARACTERS template <class _CharT, class _Traits, class _Allocator> @@ -3906,7 +3906,7 @@ _LIBCPP_TEMPLATE_DATA_VIS const typename basic_string<_CharT, _Traits, _Allocato template <class _CharT, class _Allocator> struct __string_hash : public __unary_function<basic_string<_CharT, char_traits<_CharT>, _Allocator>, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const basic_string<_CharT, char_traits<_CharT>, _Allocator>& __val) const _NOEXCEPT { return std::__do_string_hash(__val.data(), __val.data() + __val.size()); } @@ -3977,30 +3977,31 @@ erase_if(basic_string<_CharT, _Traits, _Allocator>& __str, _Predicate __pred) { // Literal suffixes for basic_string [basic.string.literals] inline namespace literals { inline namespace string_literals { -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char> operator""s(const char* __str, size_t __len) { return basic_string<char>(__str, __len); } # if _LIBCPP_HAS_WIDE_CHARACTERS -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<wchar_t> -operator""s(const wchar_t* __str, size_t __len) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<wchar_t> operator""s(const wchar_t* __str, size_t __len) { return basic_string<wchar_t>(__str, __len); } # endif # if _LIBCPP_HAS_CHAR8_T -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string<char8_t> operator""s(const char8_t* __str, size_t __len) { +[[__nodiscard__]] inline + _LIBCPP_HIDE_FROM_ABI constexpr basic_string<char8_t> operator""s(const char8_t* __str, size_t __len) { return basic_string<char8_t>(__str, __len); } # endif -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char16_t> -operator""s(const char16_t* __str, size_t __len) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char16_t> operator""s(const char16_t* __str, size_t __len) { return basic_string<char16_t>(__str, __len); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char32_t> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string<char32_t> operator""s(const char32_t* __str, size_t __len) { return basic_string<char32_t>(__str, __len); } diff --git a/lib/libcxx/include/string_view b/lib/libcxx/include/string_view @@ -130,6 +130,8 @@ namespace std { size_type copy(charT* s, size_type n, size_type pos = 0) const; // constexpr in C++20 constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const; + constexpr basic_string_view subview(size_type pos = 0, + size_type n = npos) const; // freestanding-deleted, since C++26 constexpr int compare(basic_string_view s) const noexcept; constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const; constexpr int compare(size_type pos1, size_type n1, @@ -318,9 +320,9 @@ 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) { -# if _LIBCPP_STD_VER >= 14 + _LIBCPP_DIAGNOSE_NULLPTR_IF(__len != 0 && __s == nullptr, " if len is not zero") + : __data_(__s), __size_(__len) { +# if !defined(_LIBCPP_CXX03_LANG) && (!defined(_LIBCPP_COMPILER_GCC) || _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 // passed in a negative length. @@ -352,7 +354,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 @@ -360,11 +362,11 @@ public: # endif // [string.view.iterators], iterators - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return cbegin(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return cbegin(); } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return cend(); } + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return cend(); } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data(), data(), data() + size()); # else @@ -372,7 +374,7 @@ public: # endif } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { # ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data() + size(), data(), data() + size()); # else @@ -380,51 +382,54 @@ public: # endif } - _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + rbegin() const _NOEXCEPT { return const_reverse_iterator(cend()); } - _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const _NOEXCEPT { return const_reverse_iterator(cbegin()); } - _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator + crbegin() const _NOEXCEPT { return const_reverse_iterator(cend()); } - _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX17 _LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const _NOEXCEPT { return const_reverse_iterator(cbegin()); } // [string.view.capacity], capacity - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __size_; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type length() const _NOEXCEPT { return __size_; } + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type length() const _NOEXCEPT { return __size_; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return numeric_limits<size_type>::max() / sizeof(value_type); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return __size_ == 0; } // [string.view.access], element access - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __pos) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference + operator[](size_type __pos) const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos < size(), "string_view[] index out of bounds"), __data_[__pos]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __pos) const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference at(size_type __pos) const { return __pos >= size() ? (__throw_out_of_range("string_view::at"), __data_[0]) : __data_[__pos]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::front(): string is empty"), __data_[0]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::back(): string is empty"), __data_[__size_ - 1]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_pointer data() const _NOEXCEPT { return __data_; } + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_pointer data() const _NOEXCEPT { return __data_; } // [string.view.modifiers], modifiers: _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI void remove_prefix(size_type __n) _NOEXCEPT { @@ -457,15 +462,23 @@ public: return __rlen; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view substr(size_type __pos = 0, size_type __n = npos) const { + [[__nodiscard__]] _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI basic_string_view + substr(size_type __pos = 0, size_type __n = npos) const { // Use the `__assume_valid` form of the constructor to avoid an unnecessary check. Any substring of a view is a // valid view. In particular, `size()` is known to be smaller than `numeric_limits<difference_type>::max()`, so the - // new size is also smaller. See also https://github.com/llvm/llvm-project/issues/91634. + // new size is also smaller. See also https://llvm.org/PR91634. return __pos > size() ? (__throw_out_of_range("string_view::substr"), basic_string_view()) : basic_string_view(__assume_valid(), data() + __pos, std::min(__n, size() - __pos)); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT { +# if _LIBCPP_STD_VER >= 26 + [[nodiscard]] + _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view subview(size_type __pos = 0, size_type __n = npos) const { + return substr(__pos, __n); + } +# endif + + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT { size_type __rlen = std::min(size(), __sv.size()); int __retval = _Traits::compare(data(), __sv.data(), __rlen); if (__retval == 0) // first __rlen chars matched @@ -473,217 +486,226 @@ public: return __retval; } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int compare(size_type __pos1, size_type __n1, basic_string_view __sv) const { return substr(__pos1, __n1).compare(__sv); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int compare(size_type __pos1, size_type __n1, basic_string_view __sv, size_type __pos2, size_type __n2) const { return substr(__pos1, __n1).compare(__sv.substr(__pos2, __n2)); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int compare(const _CharT* __s) const _NOEXCEPT { + [[__nodiscard__]] _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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int + 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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI int + 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)); } // find - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find(basic_string_view __s, size_type __pos = 0) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL(__s.size() == 0 || __s.data() != nullptr, "string_view::find(): received nullptr"); return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __s.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find(_CharT __c, size_type __pos = 0) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + find(_CharT __c, size_type __pos = 0) const _NOEXCEPT { return std::__str_find<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type - find(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } // rfind - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type rfind(basic_string_view __s, size_type __pos = npos) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL(__s.size() == 0 || __s.data() != nullptr, "string_view::find(): received nullptr"); return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __s.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type rfind(_CharT __c, size_type __pos = npos) const _NOEXCEPT { return std::__str_rfind<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type - rfind(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } // find_first_of - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_first_of(basic_string_view __s, size_type __pos = 0) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL(__s.size() == 0 || __s.data() != nullptr, "string_view::find_first_of(): received nullptr"); return std::__str_find_first_of<value_type, size_type, traits_type, npos>( data(), size(), __s.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_first_of(_CharT __c, size_type __pos = 0) const _NOEXCEPT { return find(__c, __pos); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type - find_first_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } // find_last_of - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_last_of(basic_string_view __s, size_type __pos = npos) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL(__s.size() == 0 || __s.data() != nullptr, "string_view::find_last_of(): received nullptr"); return std::__str_find_last_of<value_type, size_type, traits_type, npos>( data(), size(), __s.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_last_of(_CharT __c, size_type __pos = npos) const _NOEXCEPT { return rfind(__c, __pos); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type - find_last_of(const _CharT* __s, size_type __pos, size_type __n) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } // find_first_not_of - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_first_not_of(basic_string_view __s, size_type __pos = 0) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL( - __s.size() == 0 || __s.data() != 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.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_first_not_of(_CharT __c, size_type __pos = 0) const _NOEXCEPT { return std::__str_find_first_not_of<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } - _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 { + [[__nodiscard__]] _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 + _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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } // find_last_not_of - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_last_not_of(basic_string_view __s, size_type __pos = npos) const _NOEXCEPT { - _LIBCPP_ASSERT_NON_NULL( - __s.size() == 0 || __s.data() != 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.data(), __pos, __s.size()); } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type find_last_not_of(_CharT __c, size_type __pos = npos) const _NOEXCEPT { return std::__str_find_last_not_of<value_type, size_type, traits_type, npos>(data(), size(), __c, __pos); } - _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 { + [[__nodiscard__]] _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 + _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 { + [[__nodiscard__]] _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI size_type + 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)); } # if _LIBCPP_STD_VER >= 20 - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(basic_string_view __s) const noexcept { + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(basic_string_view __s) const noexcept { return size() >= __s.size() && compare(0, __s.size(), __s) == 0; } - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(value_type __c) const noexcept { + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(value_type __c) const noexcept { return !empty() && _Traits::eq(front(), __c); } - constexpr _LIBCPP_HIDE_FROM_ABI bool starts_with(const value_type* __s) const noexcept { + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool + starts_with(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const noexcept { return starts_with(basic_string_view(__s)); } - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(basic_string_view __s) const noexcept { + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(basic_string_view __s) const noexcept { return size() >= __s.size() && compare(size() - __s.size(), npos, __s) == 0; } - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(value_type __c) const noexcept { + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(value_type __c) const noexcept { return !empty() && _Traits::eq(back(), __c); } - constexpr _LIBCPP_HIDE_FROM_ABI bool ends_with(const value_type* __s) const noexcept { + [[nodiscard]] 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 # if _LIBCPP_STD_VER >= 23 - constexpr _LIBCPP_HIDE_FROM_ABI bool contains(basic_string_view __sv) const noexcept { return find(__sv) != npos; } + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool contains(basic_string_view __sv) const noexcept { + return find(__sv) != npos; + } - constexpr _LIBCPP_HIDE_FROM_ABI bool contains(value_type __c) const noexcept { return find(__c) != npos; } + [[nodiscard]] 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; } + [[nodiscard]] constexpr _LIBCPP_HIDE_FROM_ABI bool contains(const value_type* _LIBCPP_DIAGNOSE_NULLPTR __s) const { + return find(__s) != npos; + } # endif private: @@ -886,7 +908,8 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, basic_string_view<_CharT, _Trai // [string.view.hash] template <class _CharT> struct __string_view_hash : public __unary_function<basic_string_view<_CharT, char_traits<_CharT> >, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(const basic_string_view<_CharT, char_traits<_CharT> > __val) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t + operator()(const basic_string_view<_CharT, char_traits<_CharT> > __val) const _NOEXCEPT { return std::__do_string_hash(__val.data(), __val.data() + __val.size()); } }; @@ -913,30 +936,31 @@ struct hash<basic_string_view<wchar_t, char_traits<wchar_t> > > : __string_view_ # if _LIBCPP_STD_VER >= 14 inline namespace literals { inline namespace string_view_literals { -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char> operator""sv(const char* __str, size_t __len) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char> +operator""sv(const char* __str, size_t __len) noexcept { return basic_string_view<char>(__str, __len); } # if _LIBCPP_HAS_WIDE_CHARACTERS -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<wchar_t> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<wchar_t> operator""sv(const wchar_t* __str, size_t __len) noexcept { return basic_string_view<wchar_t>(__str, __len); } # endif # if _LIBCPP_HAS_CHAR8_T -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char8_t> +[[nodiscard]] inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char8_t> operator""sv(const char8_t* __str, size_t __len) noexcept { return basic_string_view<char8_t>(__str, __len); } # endif -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char16_t> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char16_t> operator""sv(const char16_t* __str, size_t __len) noexcept { return basic_string_view<char16_t>(__str, __len); } -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char32_t> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<char32_t> operator""sv(const char32_t* __str, size_t __len) noexcept { return basic_string_view<char32_t>(__str, __len); } diff --git a/lib/libcxx/include/strstream b/lib/libcxx/include/strstream @@ -179,8 +179,8 @@ public: void swap(strstreambuf& __rhs); void freeze(bool __freezefl = true); - char* str(); - int pcount() const; + [[__nodiscard__]] char* str(); + [[__nodiscard__]] int pcount() const; protected: int_type overflow(int_type __c = EOF) override; @@ -264,8 +264,8 @@ public: __sb_.swap(__rhs.__sb_); } - _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } - _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } private: strstreambuf __sb_; @@ -297,10 +297,10 @@ public: __sb_.swap(__rhs.__sb_); } - _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } _LIBCPP_HIDE_FROM_ABI void freeze(bool __freezefl = true) { __sb_.freeze(__freezefl); } - _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } - _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); } private: strstreambuf __sb_; // exposition only @@ -340,10 +340,10 @@ public: } // Members: - _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI strstreambuf* rdbuf() const { return const_cast<strstreambuf*>(&__sb_); } _LIBCPP_HIDE_FROM_ABI void freeze(bool __freezefl = true) { __sb_.freeze(__freezefl); } - _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); } - _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI int pcount() const { return __sb_.pcount(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI char* str() { return __sb_.str(); } private: strstreambuf __sb_; // exposition only diff --git a/lib/libcxx/include/syncstream b/lib/libcxx/include/syncstream @@ -317,9 +317,9 @@ public: _LIBCPP_HIDE_FROM_ABI bool emit() { return emit(false); } - _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __wrapped_; } - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const noexcept { return __str_.get_allocator(); } _LIBCPP_HIDE_FROM_ABI void set_emit_on_sync(bool __b) noexcept { __emit_on_sync_ = __b; } @@ -496,9 +496,9 @@ public: } } - _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI streambuf_type* get_wrapped() const noexcept { return __sb_.get_wrapped(); } - _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(std::addressof(__sb_)); } diff --git a/lib/libcxx/include/tgmath.h b/lib/libcxx/include/tgmath.h @@ -18,22 +18,22 @@ */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/tgmath.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif -# ifdef __cplusplus -# include <cmath> -# include <complex> -# else -# if __has_include_next(<tgmath.h>) -# include_next <tgmath.h> -# endif +#ifdef __cplusplus +# include <cmath> +# include <complex> +#else +# if __has_include_next(<tgmath.h>) +# include_next <tgmath.h> # endif -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif #endif // _LIBCPP_TGMATH_H diff --git a/lib/libcxx/include/tuple b/lib/libcxx/include/tuple @@ -106,6 +106,11 @@ public: void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...)); // constexpr in C++20 constexpr void swap(const tuple&) const noexcept(see-below); // C++23 + + template<tuple-like UTuple> + friend constexpr bool operator==(const tuple& t, const UTuple& u); // C++23 + template<tuple-like UTuple> + friend constexpr auto operator<=>(const tuple& t, const UTuple& u); // C++23 }; @@ -220,19 +225,16 @@ template <class... Types> # include <__config> # include <__cstddef/size_t.h> # include <__fwd/array.h> +# include <__fwd/get.h> # include <__fwd/pair.h> # include <__fwd/tuple.h> # include <__memory/allocator_arg_t.h> # include <__memory/uses_allocator.h> # include <__tuple/find_index.h> # include <__tuple/ignore.h> -# 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_like.h> # include <__tuple/tuple_size.h> -# include <__tuple/tuple_types.h> # include <__type_traits/common_reference.h> # include <__type_traits/common_type.h> # include <__type_traits/conditional.h> @@ -241,7 +243,6 @@ template <class... Types> # include <__type_traits/disjunction.h> # include <__type_traits/enable_if.h> # include <__type_traits/invoke.h> -# include <__type_traits/is_arithmetic.h> # include <__type_traits/is_assignable.h> # include <__type_traits/is_constructible.h> # include <__type_traits/is_convertible.h> @@ -251,7 +252,6 @@ template <class... Types> # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_reference.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> # include <__type_traits/is_trivially_relocatable.h> @@ -263,12 +263,12 @@ template <class... Types> # include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> # include <__type_traits/remove_reference.h> +# include <__type_traits/type_list.h> # 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> # include <__utility/swap.h> # include <version> @@ -288,9 +288,65 @@ _LIBCPP_BEGIN_NAMESPACE_STD # ifndef _LIBCPP_CXX03_LANG +template <size_t _Ip, class _Tp, class _Up> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool __tuple_compare_equal(const _Tp& __x, const _Up& __y) { + if constexpr (_Ip == 0) + return true; + else + return std::__tuple_compare_equal<_Ip - 1>(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); +} + +# if _LIBCPP_STD_VER >= 26 +template <class _Tp, class _Up, class _IndexSeq = make_index_sequence<tuple_size_v<_Tp>>> +inline constexpr bool __can_tuple_compare_equal = false; + +// TODO(LLVM 23): Remove `tuple_size_v<_Tp> == tuple_size_v<_Up>` here once once LLVM-20 support ends +// because the resolution of CWG2369 landed in LLVM-21. +template <class _Tp, class _Up, size_t... _Is> + requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) +inline constexpr bool __can_tuple_compare_equal<_Tp, _Up, index_sequence<_Is...>> = + __all<requires(const tuple_element_t<_Is, _Tp>& __t, const tuple_element_t<_Is, _Up>& __u) { + { __t == __u } -> __boolean_testable; + }...>::value; +# endif // _LIBCPP_STD_VER >= 26 + +# if _LIBCPP_STD_VER >= 20 +template <class _Ret, class _Tp, class _Up, size_t... _Is> +_LIBCPP_HIDE_FROM_ABI constexpr _Ret __tuple_compare_three_way(const _Tp& __x, const _Up& __y, index_sequence<_Is...>) { + _Ret __result = strong_ordering::equal; + static_cast<void>( + ((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); + return __result; +} +# endif // _LIBCPP_STD_VER >= 20 + +# if _LIBCPP_STD_VER >= 23 +template <class _Tp> +concept __tuple_like_no_tuple = __tuple_like<_Tp> && !__is_tuple_v<_Tp>; + +template <class _Tp, class _Up, class _IndexSeq> +struct __tuple_common_comparison_category_impl {}; + +// TODO(LLVM 23): Remove `tuple_size_v<_Tp> == tuple_size_v<_Up>` here once once LLVM-20 support ends +// because the resolution of CWG2369 landed in LLVM-21. +template <class _Tp, class _Up, size_t... _Is> + requires(tuple_size_v<_Tp> == tuple_size_v<_Up>) && requires { + typename common_comparison_category_t< + __synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; + } +struct __tuple_common_comparison_category_impl<_Tp, _Up, index_sequence<_Is...>> { + using type _LIBCPP_NODEBUG = + common_comparison_category_t<__synth_three_way_result<tuple_element_t<_Is, _Tp>, tuple_element_t<_Is, _Up>>...>; +}; + +template <__tuple_like _Tp, __tuple_like _Up> +using __tuple_common_comparison_category _LIBCPP_NODEBUG = + __tuple_common_comparison_category_impl<_Tp, _Up, make_index_sequence<tuple_size_v<_Tp>>>::type; +# endif // _LIBCPP_STD_VER >= 23 + // __tuple_leaf -template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__libcpp_is_final<_Hp>::value > +template <size_t _Ip, class _Hp, bool = is_empty<_Hp>::value && !__is_final_v<_Hp> > class __tuple_leaf; template <size_t _Ip, class _Hp, bool _Ep> @@ -444,62 +500,52 @@ 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> struct __tuple_impl; +struct __forward_args {}; +struct __value_init {}; +struct __from_tuple {}; + 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...>, - __tuple_types<_Tf...>, - __tuple_indices<_Ul...>, - __tuple_types<_Tl...>, - _Up&&... __u) noexcept(__all<is_nothrow_constructible<_Tf, _Up>::value...>::value && - __all<is_nothrow_default_constructible<_Tl>::value...>::value) - : __tuple_leaf<_Uf, _Tf>(std::forward<_Up>(__u))..., __tuple_leaf<_Ul, _Tl>()... {} - - template <class _Alloc, size_t... _Uf, class... _Tf, size_t... _Ul, class... _Tl, class... _Up> + template <class... _Args> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(__forward_args, _Args&&... __args) + : __tuple_leaf<_Indx, _Tp>(std::forward<_Args>(__args))... {} + + template <class _Alloc> + _LIBCPP_HIDE_FROM_ABI + _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl(allocator_arg_t, const _Alloc& __alloc, __value_init) + : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc>(), __alloc)... {} + + template <class _Alloc, class... _Args> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __tuple_impl( - allocator_arg_t, - const _Alloc& __a, - __tuple_indices<_Uf...>, - __tuple_types<_Tf...>, - __tuple_indices<_Ul...>, - __tuple_types<_Tl...>, - _Up&&... __u) - : __tuple_leaf<_Uf, _Tf>(__uses_alloc_ctor<_Tf, _Alloc, _Up>(), __a, std::forward<_Up>(__u))..., - __tuple_leaf<_Ul, _Tl>(__uses_alloc_ctor<_Tl, _Alloc>(), __a)... {} - - template <class _Tuple, __enable_if_t<__tuple_constructible<_Tuple, tuple<_Tp...> >::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(_Tuple&& __t) noexcept( - (__all<is_nothrow_constructible< - _Tp, - typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>::value...>::value)) + allocator_arg_t, const _Alloc& __alloc, __forward_args, _Args&&... __args) + : __tuple_leaf<_Indx, _Tp>(__uses_alloc_ctor<_Tp, _Alloc, _Args>(), __alloc, std::forward<_Args>(__args))... {} + + template <class _Tuple> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(__from_tuple, _Tuple&& __t) noexcept( + (__all<is_nothrow_constructible<_Tp, __copy_cvref_t<_Tuple, __tuple_element_t<_Indx, __remove_cvref_t<_Tuple>>>>:: + value...>::value)) : __tuple_leaf<_Indx, _Tp>( - std::forward<typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>( + std::forward<__copy_cvref_t<_Tuple, __tuple_element_t<_Indx, __remove_cvref_t<_Tuple>>>>( std::get<_Indx>(__t)))... {} - template <class _Alloc, class _Tuple, __enable_if_t<__tuple_constructible<_Tuple, tuple<_Tp...> >::value, int> = 0> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_impl(allocator_arg_t, const _Alloc& __a, _Tuple&& __t) + template <class _Alloc, class _Tuple> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 + __tuple_impl(allocator_arg_t, const _Alloc& __a, __from_tuple, _Tuple&& __t) : __tuple_leaf<_Indx, _Tp>( __uses_alloc_ctor<_Tp, _Alloc, - typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>(), + __copy_cvref_t<_Tuple, __tuple_element_t<_Indx, __remove_cvref_t<_Tuple>>>>(), __a, - std::forward<typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>( + std::forward<__copy_cvref_t<_Tuple, __tuple_element_t<_Indx, __remove_cvref_t<_Tuple>>>>( std::get<_Indx>(__t)))... {} __tuple_impl(const __tuple_impl&) = default; @@ -518,19 +564,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, __type_list<_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<__index_sequence_for<_Tp...>, _Tp...> _BaseT; _BaseT __base_; @@ -549,7 +595,6 @@ class _LIBCPP_NO_SPECIALIZATIONS tuple { public: using __trivially_relocatable _LIBCPP_NODEBUG = __conditional_t<_And<__libcpp_is_trivially_relocatable<_Tp>...>::value, tuple, void>; - using __replaceable _LIBCPP_NODEBUG = __conditional_t<_And<__is_replaceable<_Tp>...>::value, tuple, void>; // [tuple.cnstr] @@ -566,12 +611,7 @@ public: __enable_if_t< _And< _IsDefault<_Tp>... >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, _IsImpDefault<_Tp>...> >::value) tuple(allocator_arg_t, _Alloc const& __a) - : __base_(allocator_arg_t(), - __a, - __tuple_indices<>(), - __tuple_types<>(), - typename __make_tuple_indices<sizeof...(_Tp), 0>::type(), - __tuple_types<_Tp...>()) {} + : __base_(allocator_arg_t(), __a, __value_init{}) {} // tuple(const T&...) constructors (including allocator_arg_t variants) template <template <class...> class _And = _And, @@ -579,11 +619,7 @@ 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(), - __t...) {} + : __base_(__forward_args{}, __t...) {} template <class _Alloc, template <class...> class _And = _And, @@ -591,13 +627,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> >::value) 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(), - __t...) {} + : __base_(allocator_arg_t(), __a, __forward_args{}, __t...) {} // tuple(U&& ...) constructors (including allocator_arg_t variants) template <class... _Up> @@ -616,11 +646,7 @@ 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(), - std::forward<_Up>(__u)...) {} + : __base_(__forward_args{}, std::forward<_Up>(__u)...) {} template <class _Alloc, class... _Up, @@ -628,13 +654,7 @@ public: int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) 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(), - std::forward<_Up>(__u)...) {} + : __base_(allocator_arg_t(), __a, __forward_args{}, std::forward<_Up>(__u)...) {} // Copy and move constructors (including the allocator_arg_t variants) tuple(const tuple&) = default; @@ -644,13 +664,13 @@ public: template <class...> class _And = _And, __enable_if_t< _And<is_copy_constructible<_Tp>...>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t) - : __base_(allocator_arg_t(), __alloc, __t) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {} template <class _Alloc, template <class...> class _And = _And, __enable_if_t< _And<is_move_constructible<_Tp>...>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t) - : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {} // tuple(const tuple<U...>&) constructors (including allocator_arg_t variants) @@ -683,7 +703,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> >::value) tuple(const tuple<_Up...>& __t) noexcept(_And<is_nothrow_constructible<_Tp, const _Up&>...>::value) - : __base_(__t) {} + : __base_(__from_tuple(), __t) {} template <class... _Up, class _Alloc, @@ -691,33 +711,33 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> >::value) tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t) - : __base_(allocator_arg_t(), __a, __t) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), __t) {} # if _LIBCPP_STD_VER >= 23 // tuple(tuple<U...>&) constructors (including allocator_arg_t variants) template <class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<_Up&, _Tp>...>::value) tuple(tuple<_Up...>& __t) - : __base_(__t) {} + : __base_(__from_tuple(), __t) {} template <class _Alloc, class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<_Up&, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t) - : __base_(allocator_arg_t(), __alloc, __t) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __t) {} # endif // _LIBCPP_STD_VER >= 23 // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants) template <class... _Up, __enable_if_t< _And< _EnableCtorFromUTypesTuple<tuple<_Up...>&&> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(tuple<_Up...>&& __t) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value) - : __base_(std::move(__t)) {} + : __base_(__from_tuple(), std::move(__t)) {} template <class _Alloc, class... _Up, __enable_if_t< _And< _EnableCtorFromUTypesTuple<tuple<_Up...>&&> >::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_Lazy<_And, is_convertible<_Up, _Tp>...> >::value) tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t) - : __base_(allocator_arg_t(), __a, std::move(__t)) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__t)) {} # if _LIBCPP_STD_VER >= 23 // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants) @@ -725,14 +745,14 @@ public: template <class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<const _Up&&, _Tp>...>::value) tuple(const tuple<_Up...>&& __t) - : __base_(std::move(__t)) {} + : __base_(__from_tuple(), std::move(__t)) {} template <class _Alloc, class... _Up, enable_if_t< _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_Lazy<_And, is_convertible<const _Up&&, _Tp>...>::value) tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t) - : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__t)) {} # endif // _LIBCPP_STD_VER >= 23 // tuple(const pair<U1, U2>&) constructors (including allocator_arg_t variants) @@ -767,7 +787,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value) tuple(const pair<_Up1, _Up2>& __p) noexcept(_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value) - : __base_(__p) {} + : __base_(__from_tuple(), __p) {} template <class _Alloc, class _Up1, @@ -777,7 +797,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> >::value) tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p) - : __base_(allocator_arg_t(), __a, __p) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), __p) {} # if _LIBCPP_STD_VER >= 23 // tuple(pair<U1, U2>&) constructors (including allocator_arg_t variants) @@ -785,7 +805,7 @@ public: template <class _U1, class _U2, enable_if_t< _EnableCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value) tuple(pair<_U1, _U2>& __p) - : __base_(__p) {} + : __base_(__from_tuple(), __p) {} template <class _Alloc, class _U1, @@ -793,7 +813,7 @@ public: enable_if_t< _EnableCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value) tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p) - : __base_(allocator_arg_t(), __alloc, __p) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), __p) {} # endif // tuple(pair<U1, U2>&&) constructors (including allocator_arg_t variants) @@ -805,7 +825,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value) tuple(pair<_Up1, _Up2>&& __p) noexcept(_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value) - : __base_(std::move(__p)) {} + : __base_(__from_tuple(), std::move(__p)) {} template <class _Alloc, class _Up1, @@ -815,7 +835,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(_Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> >::value) tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p) - : __base_(allocator_arg_t(), __a, std::move(__p)) {} + : __base_(allocator_arg_t(), __a, __from_tuple(), std::move(__p)) {} # if _LIBCPP_STD_VER >= 23 // tuple(const pair<U1, U2>&&) constructors (including allocator_arg_t variants) @@ -823,7 +843,7 @@ public: template <class _U1, class _U2, enable_if_t< _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value) tuple(const pair<_U1, _U2>&& __p) - : __base_(std::move(__p)) {} + : __base_(__from_tuple(), std::move(__p)) {} template <class _Alloc, class _U1, @@ -831,14 +851,14 @@ public: enable_if_t< _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value) tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p) - : __base_(allocator_arg_t(), __alloc, std::move(__p)) {} + : __base_(allocator_arg_t(), __alloc, __from_tuple(), std::move(__p)) {} # endif // _LIBCPP_STD_VER >= 23 // [tuple.assign] _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, __index_sequence_for<_Tp...>()); return *this; } @@ -846,15 +866,14 @@ 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, __index_sequence_for<_Tp...>()); return *this; } _LIBCPP_HIDE_FROM_ABI constexpr const tuple& operator=(tuple&& __tuple) const 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()); + std::__memberwise_forward_assign(*this, std::move(__tuple), __type_list<_Tp...>(), __index_sequence_for<_Tp...>()); return *this; } # endif // _LIBCPP_STD_VER >= 23 @@ -862,8 +881,7 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 tuple& 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()); + std::__memberwise_forward_assign(*this, std::move(__tuple), __type_list<_Tp...>(), __index_sequence_for<_Tp...>()); return *this; } @@ -873,7 +891,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, __index_sequence_for<_Tp...>()); return *this; } @@ -882,8 +900,7 @@ public: int> = 0> _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()); + std::__memberwise_forward_assign(*this, std::move(__tuple), __type_list<_Up...>(), __index_sequence_for<_Tp...>()); return *this; } @@ -892,7 +909,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, index_sequence_for<_Tp...>()); return *this; } @@ -900,8 +917,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, __type_list<_UTypes...>(), index_sequence_for<_Tp...>()); return *this; } # endif // _LIBCPP_STD_VER >= 23 @@ -967,7 +983,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, __index_sequence_for<_Tp...>()); return *this; } @@ -979,10 +995,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), __type_list<_If<true, _Up, _Tp>...>(), __index_sequence_for<_Tp...>()); return *this; } @@ -997,7 +1010,24 @@ public: noexcept(__all<is_nothrow_swappable_v<const _Tp&>...>::value) { __base_.swap(__t.__base_); } -# endif // _LIBCPP_STD_VER >= 23 + + template <__tuple_like_no_tuple _UTuple> +# if _LIBCPP_STD_VER >= 26 + requires __can_tuple_compare_equal<tuple, _UTuple> && (sizeof...(_Tp) == tuple_size_v<_UTuple>) +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple& __x, const _UTuple& __y) { + static_assert(sizeof...(_Tp) == tuple_size_v<_UTuple>, "Can't compare tuple-like values of different sizes"); + return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); + } + + template <__tuple_like_no_tuple _UTuple> + requires(sizeof...(_Tp) == tuple_size_v<_UTuple>) + _LIBCPP_HIDE_FROM_ABI friend constexpr __tuple_common_comparison_category<tuple, _UTuple> + operator<=>(const tuple& __x, const _UTuple& __y) { + return std::__tuple_compare_three_way<__tuple_common_comparison_category<tuple, _UTuple>>( + __x, __y, index_sequence_for<_Tp...>{}); + } +# endif // _LIBCPP_STD_VER >= 23 }; _LIBCPP_DIAGNOSTIC_PUSH @@ -1019,6 +1049,21 @@ public: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(tuple&) _NOEXCEPT {} # if _LIBCPP_STD_VER >= 23 _LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} + + template <__tuple_like_no_tuple _UTuple> +# if _LIBCPP_STD_VER >= 26 + requires(tuple_size_v<_UTuple> == 0) +# endif // _LIBCPP_STD_VER >= 26 + _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const tuple&, const _UTuple&) { + static_assert(tuple_size_v<_UTuple> == 0, "Can't compare tuple-like values of different sizes"); + return true; + } + + template <__tuple_like_no_tuple _UTuple> + requires(tuple_size_v<_UTuple> == 0) + _LIBCPP_HIDE_FROM_ABI friend constexpr strong_ordering operator<=>(const tuple&, const _UTuple&) { + return strong_ordering::equal; + } # endif }; _LIBCPP_DIAGNOSTIC_POP @@ -1068,28 +1113,32 @@ swap(const tuple<_Tp...>& __lhs, // get template <size_t _Ip, class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, tuple<_Tp...> >::type& get(tuple<_Tp...>& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast<__tuple_leaf<_Ip, type>&>(__t.__base_).get(); } template <size_t _Ip, class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type& get(const tuple<_Tp...>& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast<const __tuple_leaf<_Ip, type>&>(__t.__base_).get(); } template <size_t _Ip, class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename tuple_element<_Ip, tuple<_Tp...> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(tuple<_Tp...>&& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast<type&&>(static_cast<__tuple_leaf<_Ip, type>&&>(__t.__base_).get()); } template <size_t _Ip, class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type&& +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX14 const typename tuple_element<_Ip, tuple<_Tp...> >::type&& get(const tuple<_Tp...>&& __t) _NOEXCEPT { using type _LIBCPP_NODEBUG = typename tuple_element<_Ip, tuple<_Tp...> >::type; return static_cast<const type&&>(static_cast<const __tuple_leaf<_Ip, type>&&>(__t.__base_).get()); @@ -1098,22 +1147,22 @@ get(const tuple<_Tp...>&& __t) _NOEXCEPT { # if _LIBCPP_STD_VER >= 14 template <class _T1, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(tuple<_Args...>& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1& get(tuple<_Args...>& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup); } template <class _T1, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(tuple<_Args...> const& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const& get(tuple<_Args...> const& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup); } template <class _T1, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1&& get(tuple<_Args...>&& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(std::move(__tup)); } template <class _T1, class... _Args> -inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& __tup) noexcept { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& __tup) noexcept { return std::get<__find_exactly_one_t<_T1, _Args...>::value>(std::move(__tup)); } @@ -1122,37 +1171,22 @@ inline _LIBCPP_HIDE_FROM_ABI constexpr _T1 const&& get(tuple<_Args...> const&& _ // tie template <class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&...> tie(_Tp&... __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&...> tie(_Tp&... __t) _NOEXCEPT { return tuple<_Tp&...>(__t...); } template <class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<__unwrap_ref_decay_t<_Tp>...> +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<__unwrap_ref_decay_t<_Tp>...> make_tuple(_Tp&&... __t) { return tuple<__unwrap_ref_decay_t<_Tp>...>(std::forward<_Tp>(__t)...); } template <class... _Tp> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> forward_as_tuple(_Tp&&... __t) _NOEXCEPT { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<_Tp&&...> +forward_as_tuple(_Tp&&... __t) _NOEXCEPT { return tuple<_Tp&&...>(std::forward<_Tp>(__t)...); } -template <size_t _Ip> -struct __tuple_equal { - template <class _Tp, class _Up> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp& __x, const _Up& __y) { - return __tuple_equal<_Ip - 1>()(__x, __y) && std::get<_Ip - 1>(__x) == std::get<_Ip - 1>(__y); - } -}; - -template <> -struct __tuple_equal<0> { - template <class _Tp, class _Up> - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator()(const _Tp&, const _Up&) { - return true; - } -}; - template <class... _Tp, class... _Up> # if _LIBCPP_STD_VER >= 26 requires(__all<requires(const _Tp& __t, const _Up& __u) { @@ -1162,27 +1196,19 @@ template <class... _Tp, class... _Up> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 bool operator==(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { static_assert(sizeof...(_Tp) == sizeof...(_Up), "Can't compare tuples of different sizes"); - return __tuple_equal<sizeof...(_Tp)>()(__x, __y); + return std::__tuple_compare_equal<sizeof...(_Tp)>(__x, __y); } # if _LIBCPP_STD_VER >= 20 // operator<=> -template <class... _Tp, class... _Up, size_t... _Is> -_LIBCPP_HIDE_FROM_ABI constexpr auto -__tuple_compare_three_way(const tuple<_Tp...>& __x, const tuple<_Up...>& __y, index_sequence<_Is...>) { - common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> __result = strong_ordering::equal; - static_cast<void>( - ((__result = std::__synth_three_way(std::get<_Is>(__x), std::get<_Is>(__y)), __result != 0) || ...)); - return __result; -} - template <class... _Tp, class... _Up> requires(sizeof...(_Tp) == sizeof...(_Up)) _LIBCPP_HIDE_FROM_ABI constexpr common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...> operator<=>(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { - return std::__tuple_compare_three_way(__x, __y, index_sequence_for<_Tp...>{}); + return std::__tuple_compare_three_way<common_comparison_category_t<__synth_three_way_result<_Tp, _Up>...>>( + __x, __y, index_sequence_for<_Tp...>{}); } # else // _LIBCPP_STD_VER >= 20 @@ -1243,65 +1269,59 @@ operator<=(const tuple<_Tp...>& __x, const tuple<_Up...>& __y) { // tuple_cat -template <class _Tp, class _Up> -struct __tuple_cat_type; +template <class... _Tuples> +struct __tuple_cat_return_impl; -template <class... _Ttypes, class... _Utypes> -struct __tuple_cat_type<tuple<_Ttypes...>, __tuple_types<_Utypes...> > { - using type _LIBCPP_NODEBUG = tuple<_Ttypes..., _Utypes...>; +template <class... _Types> +struct __tuple_cat_return_impl<tuple<_Types...>> { + using type _LIBCPP_NODEBUG = tuple<_Types...>; }; -template <class _ResultTuple, bool _Is_Tuple0TupleLike, class... _Tuples> -struct __tuple_cat_return_1 {}; +template <class... _Types0, class... _Types1, class... _Tuples> +struct __tuple_cat_return_impl<tuple<_Types0...>, tuple<_Types1...>, _Tuples...> + : __tuple_cat_return_impl<tuple<_Types0..., _Types1...>, _Tuples...> {}; -template <class... _Types, class _Tuple0> -struct __tuple_cat_return_1<tuple<_Types...>, true, _Tuple0> { - using type _LIBCPP_NODEBUG = - typename __tuple_cat_type< tuple<_Types...>, - typename __make_tuple_types<__remove_cvref_t<_Tuple0> >::type >::type; -}; - -template <class... _Types, class _Tuple0, class _Tuple1, class... _Tuples> -struct __tuple_cat_return_1<tuple<_Types...>, true, _Tuple0, _Tuple1, _Tuples...> - : public __tuple_cat_return_1< - typename __tuple_cat_type< tuple<_Types...>, - typename __make_tuple_types<__remove_cvref_t<_Tuple0> >::type >::type, - __tuple_like_ext<__libcpp_remove_reference_t<_Tuple1> >::value, - _Tuple1, - _Tuples...> {}; +template <class... _Types0, class _Tp, class _Up, class... _Tuples> +struct __tuple_cat_return_impl<tuple<_Types0...>, pair<_Tp, _Up>, _Tuples...> + : __tuple_cat_return_impl<tuple<_Types0..., _Tp, _Up>, _Tuples...> {}; -template <class... _Tuples> -struct __tuple_cat_return; +template <class, class, class> +struct __tuple_cat_array; -template <class _Tuple0, class... _Tuples> -struct __tuple_cat_return<_Tuple0, _Tuples...> - : public __tuple_cat_return_1<tuple<>, - __tuple_like_ext<__libcpp_remove_reference_t<_Tuple0> >::value, - _Tuple0, - _Tuples...> {}; +template <class... _Types, class _ValueT, size_t... _Indices> +struct __tuple_cat_array<tuple<_Types...>, _ValueT, __index_sequence<_Indices...>> { + template <size_t> + using __value_type _LIBCPP_NODEBUG = _ValueT; -template <> -struct __tuple_cat_return<> { - using type _LIBCPP_NODEBUG = tuple<>; + using type _LIBCPP_NODEBUG = tuple<_Types..., __value_type<_Indices>...>; }; -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<> tuple_cat() { return tuple<>(); } +template <class... _Types, class _ValueT, size_t _Np, class... _Tuples> +struct __tuple_cat_return_impl<tuple<_Types...>, array<_ValueT, _Np>, _Tuples...> + : __tuple_cat_return_impl<typename __tuple_cat_array<tuple<_Types...>, _ValueT, __make_index_sequence<_Np>>::type, + _Tuples...> {}; + +template <class... _Tuples> +using __tuple_cat_return_t _LIBCPP_NODEBUG = + typename __tuple_cat_return_impl<tuple<>, __remove_cvref_t<_Tuples>...>::type; + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 tuple<> tuple_cat() { return tuple<>(); } 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 +1329,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 +1337,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 +1355,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,21 +1366,21 @@ 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))...); } template <class _Tuple0, class... _Tuples> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 typename __tuple_cat_return<_Tuple0, _Tuples...>::type +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_cat_return_t<_Tuple0, _Tuples...> 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 _TRet _LIBCPP_NODEBUG = __tuple_cat_return_t<_Tuple0, _Tuples...>; + 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 +1396,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 +1404,29 @@ 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 +#undef _LIBCPP_NOEXCEPT_RETURN 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, @@ -1418,10 +1439,19 @@ template <class _Tp, class _Tuple> #else template <class _Tp, class _Tuple, class = enable_if_t<__can_make_from_tuple<_Tp, _Tuple>>> // strengthen #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{})) -# undef _LIBCPP_NOEXCEPT_RETURN + +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI constexpr _Tp make_from_tuple(_Tuple&& __t) + noexcept(noexcept(std::__make_from_tuple_impl<_Tp>(std::forward<_Tuple>(__t), + make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()))) { +#if _LIBCPP_STD_VER >= 23 + if constexpr (tuple_size_v<remove_reference_t<_Tuple>> == 1) { + static_assert(!std::reference_constructs_from_temporary_v<_Tp, decltype(std::get<0>(std::declval<_Tuple>()))>, + "Attempted construction of reference element binds to a temporary whose lifetime has ended"); + } +#endif // _LIBCPP_STD_VER >= 23 + return std::__make_from_tuple_impl<_Tp>( + std::forward<_Tuple>(__t), make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>()); +} # endif // _LIBCPP_STD_VER >= 17 diff --git a/lib/libcxx/include/type_traits b/lib/libcxx/include/type_traits @@ -454,6 +454,10 @@ namespace std template<class B> inline constexpr bool negation_v = negation<B>::value; // since C++17 + // [meta.const.eval], constant evaluation context + constexpr bool is_constant_evaluated() noexcept; // C++20 + template<class T> + consteval bool is_within_lifetime(const T*) noexcept; // C++26 } */ @@ -546,9 +550,7 @@ namespace std # if _LIBCPP_STD_VER >= 20 # include <__type_traits/common_reference.h> -# include <__type_traits/is_bounded_array.h> # include <__type_traits/is_constant_evaluated.h> -# include <__type_traits/is_unbounded_array.h> # include <__type_traits/type_identity.h> # include <__type_traits/unwrap_ref.h> # endif @@ -559,6 +561,10 @@ namespace std # include <__type_traits/reference_converts_from_temporary.h> # endif +# if _LIBCPP_STD_VER >= 26 +# include <__type_traits/is_within_lifetime.h> +# endif + # include <version> # if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/lib/libcxx/include/typeindex b/lib/libcxx/include/typeindex @@ -86,8 +86,8 @@ public: } # endif - _LIBCPP_HIDE_FROM_ABI size_t hash_code() const _NOEXCEPT { return __t_->hash_code(); } - _LIBCPP_HIDE_FROM_ABI const char* name() const _NOEXCEPT { return __t_->name(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t hash_code() const _NOEXCEPT { return __t_->hash_code(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char* name() const _NOEXCEPT { return __t_->name(); } }; template <class _Tp> @@ -95,7 +95,9 @@ struct hash; template <> struct hash<type_index> : public __unary_function<type_index, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t operator()(type_index __index) const _NOEXCEPT { return __index.hash_code(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(type_index __index) const _NOEXCEPT { + return __index.hash_code(); + } }; _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/include/typeinfo b/lib/libcxx/include/typeinfo @@ -95,11 +95,13 @@ class _LIBCPP_EXPORTED_FROM_ABI type_info { public: virtual ~type_info(); - const char* name() const _NOEXCEPT; + [[__nodiscard__]] const char* name() const _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI bool before(const type_info& __arg) const _NOEXCEPT { return __compare(__arg) < 0; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool before(const type_info& __arg) const _NOEXCEPT { + return __compare(__arg) < 0; + } - size_t hash_code() const _NOEXCEPT; + [[__nodiscard__]] size_t hash_code() const _NOEXCEPT; _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const type_info& __arg) const _NOEXCEPT { // When evaluated in a constant expression, both type infos simply can't come @@ -186,99 +188,99 @@ public: # endif # endif -struct __type_info_implementations { - struct __string_impl_base { - typedef const char* __type_name_t; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static const char* - __type_name_to_string(__type_name_t __v) _NOEXCEPT { - return __v; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static __type_name_t - __string_to_type_name(const char* __v) _NOEXCEPT { - return __v; - } - }; +namespace __type_info_implementations { +struct __string_impl_base { + typedef const char* __type_name_t; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static const char* + __type_name_to_string(__type_name_t __v) _NOEXCEPT { + return __v; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE _LIBCPP_CONSTEXPR static __type_name_t + __string_to_type_name(const char* __v) _NOEXCEPT { + return __v; + } +}; - struct __unique_impl : __string_impl_base { - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { - return reinterpret_cast<size_t>(__v); - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs == __rhs; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs < __rhs; - } - }; - - struct __non_unique_impl : __string_impl_base { - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __ptr) _NOEXCEPT { - size_t __hash = 5381; - while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) - __hash = (__hash * 33) ^ __c; - return __hash; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - return __builtin_strcmp(__lhs, __rhs) < 0; - } - }; +struct __unique_impl : __string_impl_base { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { + return reinterpret_cast<size_t>(__v); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs == __rhs; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs < __rhs; + } +}; - struct __non_unique_arm_rtti_bit_impl { - typedef uintptr_t __type_name_t; +struct __non_unique_impl : __string_impl_base { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __ptr) _NOEXCEPT { + size_t __hash = 5381; + while (unsigned char __c = static_cast<unsigned char>(*__ptr++)) + __hash = (__hash * 33) ^ __c; + return __hash; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __lhs == __rhs || __builtin_strcmp(__lhs, __rhs) == 0; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + return __builtin_strcmp(__lhs, __rhs) < 0; + } +}; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { - return reinterpret_cast<const char*>(__v & ~__non_unique_rtti_bit::value); - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { - return reinterpret_cast<__type_name_t>(__v); - } +struct __non_unique_arm_rtti_bit_impl { + typedef uintptr_t __type_name_t; - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { - if (__is_type_name_unique(__v)) - return __v; - return __non_unique_impl::__hash(__type_name_to_string(__v)); - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - if (__lhs == __rhs) - return true; - if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) - // Either both are unique and have a different address, or one of them - // is unique and the other one isn't. In both cases they are unequal. - return false; - return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; - } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { - if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) - return __lhs < __rhs; - return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; - } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static const char* __type_name_to_string(__type_name_t __v) _NOEXCEPT { + return reinterpret_cast<const char*>(__v & ~__non_unique_rtti_bit::value); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static __type_name_t __string_to_type_name(const char* __v) _NOEXCEPT { + return reinterpret_cast<__type_name_t>(__v); + } - private: - // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when - // this implementation is actually used. - typedef integral_constant<__type_name_t, (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> - __non_unique_rtti_bit; + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static size_t __hash(__type_name_t __v) _NOEXCEPT { + if (__is_type_name_unique(__v)) + return __v; + return __non_unique_impl::__hash(__type_name_to_string(__v)); + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __eq(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + if (__lhs == __rhs) + return true; + if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) + // Either both are unique and have a different address, or one of them + // is unique and the other one isn't. In both cases they are unequal. + return false; + return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) == 0; + } + _LIBCPP_HIDE_FROM_ABI _LIBCPP_ALWAYS_INLINE static bool __lt(__type_name_t __lhs, __type_name_t __rhs) _NOEXCEPT { + if (__is_type_name_unique(__lhs) || __is_type_name_unique(__rhs)) + return __lhs < __rhs; + return __builtin_strcmp(__type_name_to_string(__lhs), __type_name_to_string(__rhs)) < 0; + } - _LIBCPP_HIDE_FROM_ABI static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { - return !(__lhs & __non_unique_rtti_bit::value); - } - }; +private: + // The unique bit is the top bit. It is expected that __type_name_t is 64 bits when + // this implementation is actually used. + typedef integral_constant<__type_name_t, (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1))> + __non_unique_rtti_bit; + + _LIBCPP_HIDE_FROM_ABI static bool __is_type_name_unique(__type_name_t __lhs) _NOEXCEPT { + return !(__lhs & __non_unique_rtti_bit::value); + } +}; - typedef +typedef # if _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 1 - __unique_impl + __unique_impl # elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 2 - __non_unique_impl + __non_unique_impl # elif _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION == 3 - __non_unique_arm_rtti_bit_impl + __non_unique_arm_rtti_bit_impl # else # error invalid configuration for _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION # endif - __impl; -}; + __impl; +} // namespace __type_info_implementations # if __has_cpp_attribute(_Clang::__ptrauth_vtable_pointer__) # if __has_feature(ptrauth_type_info_vtable_pointer_discrimination) @@ -306,14 +308,15 @@ protected: public: virtual ~type_info(); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const char* name() const _NOEXCEPT { + return __impl::__type_name_to_string(__type_name); + } - _LIBCPP_HIDE_FROM_ABI const char* name() const _NOEXCEPT { return __impl::__type_name_to_string(__type_name); } - - _LIBCPP_HIDE_FROM_ABI bool before(const type_info& __arg) const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool before(const type_info& __arg) const _NOEXCEPT { return __impl::__lt(__type_name, __arg.__type_name); } - _LIBCPP_HIDE_FROM_ABI size_t hash_code() const _NOEXCEPT { return __impl::__hash(__type_name); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t hash_code() const _NOEXCEPT { return __impl::__hash(__type_name); } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 bool operator==(const type_info& __arg) const _NOEXCEPT { // When evaluated in a constant expression, both type infos simply can't come @@ -336,7 +339,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_cast(const bad_cast&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_cast& operator=(const bad_cast&) _NOEXCEPT = default; ~bad_cast() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; class _LIBCPP_EXPORTED_FROM_ABI bad_typeid : public exception { @@ -345,7 +348,7 @@ public: _LIBCPP_HIDE_FROM_ABI bad_typeid(const bad_typeid&) _NOEXCEPT = default; _LIBCPP_HIDE_FROM_ABI bad_typeid& operator=(const bad_typeid&) _NOEXCEPT = default; ~bad_typeid() _NOEXCEPT override; - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; } // namespace std diff --git a/lib/libcxx/include/unordered_map b/lib/libcxx/include/unordered_map @@ -600,6 +600,7 @@ template <class Key, class T, class Hash, class Pred, class Alloc> # include <__memory/addressof.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> +# include <__memory/compressed_pair.h> # include <__memory/pointer_traits.h> # include <__memory/unique_ptr.h> # include <__memory_resource/polymorphic_allocator.h> @@ -643,34 +644,9 @@ _LIBCPP_PUSH_MACROS _LIBCPP_BEGIN_NAMESPACE_STD -template <class _Key, - class _Cp, - class _Hash, - class _Pred, - bool = is_empty<_Hash>::value && !__libcpp_is_final<_Hash>::value> -class __unordered_map_hasher : private _Hash { -public: - _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) : _Hash() {} - _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher(const _Hash& __h) _NOEXCEPT_(is_nothrow_copy_constructible<_Hash>::value) - : _Hash(__h) {} - _LIBCPP_HIDE_FROM_ABI const _Hash& hash_function() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Cp& __x) const { return static_cast<const _Hash&>(*this)(__x.first); } - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _Key& __x) const { return static_cast<const _Hash&>(*this)(__x); } -# if _LIBCPP_STD_VER >= 20 - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI size_t operator()(const _K2& __x) const { - return static_cast<const _Hash&>(*this)(__x); - } -# endif - _LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_hasher& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Hash>) { - using std::swap; - swap(static_cast<_Hash&>(*this), static_cast<_Hash&>(__y)); - } -}; - template <class _Key, class _Cp, class _Hash, class _Pred> -class __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, false> { - _Hash __hash_; +class __unordered_map_hasher { + _LIBCPP_COMPRESSED_ELEMENT(_Hash, __hash_); public: _LIBCPP_HIDE_FROM_ABI __unordered_map_hasher() _NOEXCEPT_(is_nothrow_default_constructible<_Hash>::value) @@ -692,60 +668,16 @@ public: } }; -template <class _Key, class _Cp, class _Hash, class _Pred, bool __b> +template <class _Key, class _Cp, class _Hash, class _Pred> inline _LIBCPP_HIDE_FROM_ABI void -swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __x, - __unordered_map_hasher<_Key, _Cp, _Hash, _Pred, __b>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { +swap(__unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __x, __unordered_map_hasher<_Key, _Cp, _Hash, _Pred>& __y) + _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } -template <class _Key, - class _Cp, - class _Pred, - class _Hash, - bool = is_empty<_Pred>::value && !__libcpp_is_final<_Pred>::value> -class __unordered_map_equal : private _Pred { -public: - _LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) : _Pred() {} - _LIBCPP_HIDE_FROM_ABI __unordered_map_equal(const _Pred& __p) _NOEXCEPT_(is_nothrow_copy_constructible<_Pred>::value) - : _Pred(__p) {} - _LIBCPP_HIDE_FROM_ABI const _Pred& key_eq() const _NOEXCEPT { return *this; } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Cp& __y) const { - return static_cast<const _Pred&>(*this)(__x.first, __y.first); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _Key& __y) const { - return static_cast<const _Pred&>(*this)(__x.first, __y); - } - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _Cp& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first); - } -# if _LIBCPP_STD_VER >= 20 - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Cp& __x, const _K2& __y) const { - return static_cast<const _Pred&>(*this)(__x.first, __y); - } - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Cp& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y.__get_value().first); - } - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _Key& __x, const _K2& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y); - } - template <typename _K2> - _LIBCPP_HIDE_FROM_ABI bool operator()(const _K2& __x, const _Key& __y) const { - return static_cast<const _Pred&>(*this)(__x, __y); - } -# endif - _LIBCPP_HIDE_FROM_ABI void swap(__unordered_map_equal& __y) _NOEXCEPT_(__is_nothrow_swappable_v<_Pred>) { - using std::swap; - swap(static_cast<_Pred&>(*this), static_cast<_Pred&>(__y)); - } -}; - template <class _Key, class _Cp, class _Pred, class _Hash> -class __unordered_map_equal<_Key, _Cp, _Pred, _Hash, false> { - _Pred __pred_; +class __unordered_map_equal { + _LIBCPP_COMPRESSED_ELEMENT(_Pred, __pred_); public: _LIBCPP_HIDE_FROM_ABI __unordered_map_equal() _NOEXCEPT_(is_nothrow_default_constructible<_Pred>::value) @@ -780,9 +712,9 @@ public: } }; -template <class _Key, class _Cp, class _Pred, class _Hash, bool __b> +template <class _Key, class _Cp, class _Pred, class _Hash> inline _LIBCPP_HIDE_FROM_ABI void -swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash, __b>& __y) +swap(__unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __x, __unordered_map_equal<_Key, _Cp, _Pred, _Hash>& __y) _NOEXCEPT_(_NOEXCEPT_(__x.swap(__y))) { __x.swap(__y); } @@ -844,10 +776,10 @@ class __hash_map_iterator { public: typedef forward_iterator_tag iterator_category; - typedef typename _NodeTypes::__map_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using value_type = typename _HashIterator::value_type; + using difference_type = ptrdiff_t; typedef value_type& reference; - typedef typename _NodeTypes::__map_value_type_pointer pointer; + using pointer = typename _HashIterator::pointer; _LIBCPP_HIDE_FROM_ABI __hash_map_iterator() _NOEXCEPT {} @@ -895,10 +827,10 @@ class __hash_map_const_iterator { public: typedef forward_iterator_tag iterator_category; - typedef typename _NodeTypes::__map_value_type value_type; - typedef typename _NodeTypes::difference_type difference_type; + using value_type = typename _HashIterator::value_type; + using difference_type = ptrdiff_t; typedef const value_type& reference; - typedef typename _NodeTypes::__const_map_value_type_pointer pointer; + using pointer = typename _HashIterator::pointer; _LIBCPP_HIDE_FROM_ABI __hash_map_const_iterator() _NOEXCEPT {} @@ -972,9 +904,6 @@ private: __table __table_; - typedef typename __table::_NodeTypes _NodeTypes; - typedef typename __table::__node_pointer __node_pointer; - typedef typename __table::__node_const_pointer __node_const_pointer; typedef typename __table::__node_traits __node_traits; typedef typename __table::__node_allocator __node_allocator; typedef typename __table::__node __node; @@ -1046,10 +975,10 @@ public: # endif _LIBCPP_HIDE_FROM_ABI explicit unordered_map(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u); + _LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_map(const unordered_map& __u, const allocator_type& __a); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u) _NOEXCEPT_(is_nothrow_move_constructible<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_map(unordered_map&& __u, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI unordered_map(initializer_list<value_type> __il); _LIBCPP_HIDE_FROM_ABI @@ -1099,41 +1028,26 @@ public: static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); } - _LIBCPP_HIDE_FROM_ABI unordered_map& operator=(const unordered_map& __u) { -# ifndef _LIBCPP_CXX03_LANG - __table_ = __u.__table_; -# else - if (this != std::addressof(__u)) { - __table_.clear(); - __table_.hash_function() = __u.__table_.hash_function(); - __table_.key_eq() = __u.__table_.key_eq(); - __table_.max_load_factor() = __u.__table_.max_load_factor(); - __table_.__copy_assign_alloc(__u.__table_); - insert(__u.begin(), __u.end()); - } -# endif - return *this; - } + _LIBCPP_HIDE_FROM_ABI unordered_map& operator=(const unordered_map& __u) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_map& operator=(unordered_map&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_map& operator=(unordered_map&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_map& operator=(initializer_list<value_type> __il); # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__table_.__node_alloc()); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(const value_type& __x) { return __table_.__emplace_unique(__x); } @@ -1187,14 +1101,13 @@ public: # if _LIBCPP_STD_VER >= 17 template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> try_emplace(const key_type& __k, _Args&&... __args) { - return __table_.__emplace_unique_key_args( - __k, piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple(std::forward<_Args>(__args)...)); + return __table_.__emplace_unique( + piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple(std::forward<_Args>(__args)...)); } template <class... _Args> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> try_emplace(key_type&& __k, _Args&&... __args) { - return __table_.__emplace_unique_key_args( - __k, + return __table_.__emplace_unique( piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple(std::forward<_Args>(__args)...)); @@ -1212,7 +1125,7 @@ public: template <class _Vp> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert_or_assign(const key_type& __k, _Vp&& __v) { - pair<iterator, bool> __res = __table_.__emplace_unique_key_args(__k, __k, std::forward<_Vp>(__v)); + pair<iterator, bool> __res = __table_.__emplace_unique(__k, std::forward<_Vp>(__v)); if (!__res.second) { __res.first->second = std::forward<_Vp>(__v); } @@ -1221,7 +1134,7 @@ public: template <class _Vp> _LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert_or_assign(key_type&& __k, _Vp&& __v) { - pair<iterator, bool> __res = __table_.__emplace_unique_key_args(__k, std::move(__k), std::forward<_Vp>(__v)); + pair<iterator, bool> __res = __table_.__emplace_unique(std::move(__k), std::forward<_Vp>(__v)); if (!__res.second) { __res.first->second = std::forward<_Vp>(__v); } @@ -1258,10 +1171,10 @@ public: "node_type with incompatible allocator passed to unordered_map::insert()"); return __table_.template __node_handle_insert_unique<node_type>(__hint.__i_, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __table_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __table_.template __node_handle_extract<node_type>(__it.__i_); } @@ -1295,52 +1208,56 @@ public: __table_.swap(__u.__table_); } - _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function().hash_function(); } - _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq().key_eq(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { + return __table_.hash_function().hash_function(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq().key_eq(); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __table_.find(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __table_.find(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __table_.__count_unique(__k); + } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __table_.__count_unique(__k); } # endif // _LIBCPP_STD_VER >= 20 # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __table_.__equal_range_unique(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __table_.__equal_range_unique(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __table_.__equal_range_unique(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __table_.__equal_range_unique(__k); } # endif // _LIBCPP_STD_VER >= 20 @@ -1350,24 +1267,32 @@ public: _LIBCPP_HIDE_FROM_ABI mapped_type& operator[](key_type&& __k); # endif - _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); - _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mapped_type& at(const key_type& __k); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const mapped_type& at(const key_type& __k) const; - _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } - _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { + return __table_.max_bucket_count(); + } - _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); } - _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { + return __table_.bucket_size(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } - _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } - _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } - _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); } _LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_unique(__n); } _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_unique(__n); } @@ -1384,10 +1309,10 @@ template <class _InputIterator, class _Pred = equal_to<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0, @@ -1401,10 +1326,10 @@ template <ranges::input_range _Range, class _Hash = hash<__range_key_type<_Range>>, class _Pred = equal_to<__range_key_type<_Range>>, class _Allocator = allocator<__range_to_alloc_type<_Range>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type = 0, @@ -1419,10 +1344,10 @@ template <class _Key, class _Hash = hash<remove_const_t<_Key>>, class _Pred = equal_to<remove_const_t<_Key>>, class _Allocator = allocator<pair<const _Key, _Tp>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type = 0, _Hash = _Hash(), @@ -1432,7 +1357,7 @@ unordered_map(initializer_list<pair<_Key, _Tp>>, template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -1443,7 +1368,7 @@ unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocat template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(_InputIterator, _InputIterator, _Allocator) -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -1455,9 +1380,9 @@ template <class _InputIterator, class _Hash, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_map<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -1467,7 +1392,7 @@ unordered_map(_InputIterator, _InputIterator, typename allocator_traits<_Allocat # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_map<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -1475,7 +1400,7 @@ unordered_map(from_range_t, _Range&&, typename allocator_traits<_Allocator>::siz equal_to<__range_key_type<_Range>>, _Allocator>; -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(from_range_t, _Range&&, _Allocator) -> unordered_map<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -1486,9 +1411,9 @@ unordered_map(from_range_t, _Range&&, _Allocator) template <ranges::input_range _Range, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_map<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -1498,11 +1423,11 @@ unordered_map(from_range_t, _Range&&, typename allocator_traits<_Allocator>::siz # endif -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_map<remove_const_t<_Key>, _Tp, hash<remove_const_t<_Key>>, equal_to<remove_const_t<_Key>>, _Allocator>; -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(initializer_list<pair<_Key, _Tp>>, _Allocator) -> unordered_map<remove_const_t<_Key>, _Tp, hash<remove_const_t<_Key>>, equal_to<remove_const_t<_Key>>, _Allocator>; @@ -1510,9 +1435,9 @@ template <class _Key, class _Tp, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_map(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_map<remove_const_t<_Key>, _Tp, _Hash, equal_to<remove_const_t<_Key>>, _Allocator>; # endif @@ -1564,12 +1489,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( } template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_map& __u) : __table_(__u.__table_) { - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_map& __u, const allocator_type& __a) : __table_(__u.__table_, typename __table::allocator_type(__a)) { __table_.__rehash_unique(__u.bucket_count()); @@ -1579,11 +1498,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(const unordered_ma # ifndef _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value) - : __table_(std::move(__u.__table_)) {} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map(unordered_map&& __u, const allocator_type& __a) : __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) { if (__a != __u.get_allocator()) { @@ -1620,14 +1534,6 @@ unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map( template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& -unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_map&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value) { - __table_ = std::move(__u.__table_); - return *this; -} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -inline unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) { __table_.__assign_unique(__il.begin(), __il.end()); return *this; @@ -1646,16 +1552,13 @@ inline void unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::insert(_InputIterato template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](const key_type& __k) { - return __table_ - .__emplace_unique_key_args(__k, piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple()) + return __table_.__emplace_unique(piecewise_construct, std::forward_as_tuple(__k), std::forward_as_tuple()) .first->second; } template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> _Tp& unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::operator[](key_type&& __k) { - return __table_ - .__emplace_unique_key_args( - __k, piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple()) + return __table_.__emplace_unique(piecewise_construct, std::forward_as_tuple(std::move(__k)), std::forward_as_tuple()) .first->second; } # else // _LIBCPP_CXX03_LANG @@ -1781,12 +1684,8 @@ private: __table __table_; - typedef typename __table::_NodeTypes _NodeTypes; typedef typename __table::__node_traits __node_traits; - typedef typename __table::__node_allocator __node_allocator; typedef typename __table::__node __node; - typedef __hash_map_node_destructor<__node_allocator> _Dp; - typedef unique_ptr<__node, _Dp> __node_holder; typedef allocator_traits<allocator_type> __alloc_traits; static_assert(is_same<typename __node_traits::size_type, typename __alloc_traits::size_type>::value, "Allocator uses different size_type for different types"); @@ -1852,11 +1751,10 @@ public: # endif _LIBCPP_HIDE_FROM_ABI explicit unordered_multimap(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u); + _LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multimap(const unordered_multimap& __u, const allocator_type& __a); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_multimap(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_multimap(unordered_multimap&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multimap(unordered_multimap&& __u, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI unordered_multimap(initializer_list<value_type> __il); _LIBCPP_HIDE_FROM_ABI unordered_multimap( @@ -1906,41 +1804,26 @@ public: static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Key, _Hash, _Pred>(0)), ""); } - _LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(const unordered_multimap& __u) { -# ifndef _LIBCPP_CXX03_LANG - __table_ = __u.__table_; -# else - if (this != std::addressof(__u)) { - __table_.clear(); - __table_.hash_function() = __u.__table_.hash_function(); - __table_.key_eq() = __u.__table_.key_eq(); - __table_.max_load_factor() = __u.__table_.max_load_factor(); - __table_.__copy_assign_alloc(__u.__table_); - insert(__u.begin(), __u.end()); - } -# endif - return *this; - } + _LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(const unordered_multimap& __u) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(unordered_multimap&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multimap& operator=(initializer_list<value_type> __il); # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__table_.__node_alloc()); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } _LIBCPP_HIDE_FROM_ABI iterator insert(const value_type& __x) { return __table_.__emplace_multi(__x); } @@ -2008,10 +1891,10 @@ public: "node_type with incompatible allocator passed to unordered_multimap::insert()"); return __table_.template __node_handle_insert_multi<node_type>(__hint.__i_, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __table_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __table_.template __node_handle_extract<node_type>(__it.__i_); } @@ -2045,71 +1928,83 @@ public: __table_.swap(__u.__table_); } - _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function().hash_function(); } - _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq().key_eq(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { + return __table_.hash_function().hash_function(); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq().key_eq(); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __table_.find(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __table_.find(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_multi(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __table_.__count_multi(__k); + } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __table_.__count_multi(__k); } # endif // _LIBCPP_STD_VER >= 20 # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __table_.__equal_range_multi(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __table_.__equal_range_multi(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __table_.__equal_range_multi(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __table_.__equal_range_multi(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } - _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { + return __table_.max_bucket_count(); + } - _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); } - _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { + return __table_.bucket_size(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } - _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } - _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } - _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); } _LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_multi(__n); } _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_multi(__n); } @@ -2121,10 +2016,10 @@ template <class _InputIterator, class _Pred = equal_to<__iter_key_type<_InputIterator>>, class _Allocator = allocator<__iter_to_alloc_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0, @@ -2142,10 +2037,10 @@ template <ranges::input_range _Range, class _Hash = hash<__range_key_type<_Range>>, class _Pred = equal_to<__range_key_type<_Range>>, class _Allocator = allocator<__range_to_alloc_type<_Range>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type = 0, @@ -2160,21 +2055,21 @@ template <class _Key, class _Hash = hash<remove_const_t<_Key>>, class _Pred = equal_to<remove_const_t<_Key>>, class _Allocator = allocator<pair<const _Key, _Tp>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_multimap( - initializer_list<pair<_Key, _Tp>>, - typename allocator_traits<_Allocator>::size_type = 0, - _Hash = _Hash(), - _Pred = _Pred(), - _Allocator = _Allocator()) -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>; + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> +unordered_multimap(initializer_list<pair<_Key, _Tp>>, + typename allocator_traits<_Allocator>::size_type = 0, + _Hash = _Hash(), + _Pred = _Pred(), + _Allocator = _Allocator()) + -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, _Pred, _Allocator>; template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -2185,7 +2080,7 @@ unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Al template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(_InputIterator, _InputIterator, _Allocator) -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -2197,9 +2092,9 @@ template <class _InputIterator, class _Hash, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_multimap<__iter_key_type<_InputIterator>, __iter_mapped_type<_InputIterator>, @@ -2209,7 +2104,7 @@ unordered_multimap(_InputIterator, _InputIterator, typename allocator_traits<_Al # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multimap<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -2217,7 +2112,7 @@ unordered_multimap(from_range_t, _Range&&, typename allocator_traits<_Allocator> equal_to<__range_key_type<_Range>>, _Allocator>; -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(from_range_t, _Range&&, _Allocator) -> unordered_multimap<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -2228,9 +2123,9 @@ unordered_multimap(from_range_t, _Range&&, _Allocator) template <ranges::input_range _Range, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_multimap<__range_key_type<_Range>, __range_mapped_type<_Range>, @@ -2240,7 +2135,7 @@ unordered_multimap(from_range_t, _Range&&, typename allocator_traits<_Allocator> # endif -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multimap<remove_const_t<_Key>, _Tp, @@ -2248,7 +2143,7 @@ unordered_multimap(initializer_list<pair<_Key, _Tp>>, typename allocator_traits< equal_to<remove_const_t<_Key>>, _Allocator>; -template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Key, class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap(initializer_list<pair<_Key, _Tp>>, _Allocator) -> unordered_multimap<remove_const_t<_Key>, _Tp, @@ -2260,9 +2155,9 @@ template <class _Key, class _Tp, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multimap( initializer_list<pair<_Key, _Tp>>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_multimap<remove_const_t<_Key>, _Tp, _Hash, equal_to<remove_const_t<_Key>>, _Allocator>; @@ -2316,13 +2211,6 @@ inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(c : __table_(typename __table::allocator_type(__a)) {} template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(const unordered_multimap& __u) - : __table_(__u.__table_) { - __table_.__rehash_multi(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap( const unordered_multimap& __u, const allocator_type& __a) : __table_(__u.__table_, typename __table::allocator_type(__a)) { @@ -2333,11 +2221,6 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap( # ifndef _LIBCPP_CXX03_LANG template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value) - : __table_(std::move(__u.__table_)) {} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap( unordered_multimap&& __u, const allocator_type& __a) : __table_(std::move(__u.__table_), typename __table::allocator_type(__a)) { @@ -2375,14 +2258,6 @@ unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_multimap( template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& -unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(unordered_multimap&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value) { - __table_ = std::move(__u.__table_); - return *this; -} - -template <class _Key, class _Tp, class _Hash, class _Pred, class _Alloc> -inline unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>& unordered_multimap<_Key, _Tp, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) { __table_.__assign_multi(__il.begin(), __il.end()); return *this; diff --git a/lib/libcxx/include/unordered_set b/lib/libcxx/include/unordered_set @@ -544,8 +544,6 @@ template <class Value, class Hash, class Pred, class Alloc> # include <__iterator/distance.h> # include <__iterator/erase_if_container.h> # include <__iterator/iterator_traits.h> -# include <__iterator/ranges_iterator_traits.h> -# include <__memory/addressof.h> # include <__memory/allocator.h> # include <__memory/allocator_traits.h> # include <__memory_resource/polymorphic_allocator.h> @@ -558,7 +556,6 @@ template <class Value, class Hash, class Pred, class Alloc> # include <__type_traits/invoke.h> # include <__type_traits/is_allocator.h> # include <__type_traits/is_integral.h> -# include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> @@ -703,10 +700,10 @@ public: # endif _LIBCPP_HIDE_FROM_ABI explicit unordered_set(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u); + _LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_set(const unordered_set& __u, const allocator_type& __a); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_set(unordered_set&& __u) _NOEXCEPT_(is_nothrow_move_constructible<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_set(unordered_set&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_set(unordered_set&& __u, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI unordered_set(initializer_list<value_type> __il); _LIBCPP_HIDE_FROM_ABI @@ -733,30 +730,26 @@ public: static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); } - _LIBCPP_HIDE_FROM_ABI unordered_set& operator=(const unordered_set& __u) { - __table_ = __u.__table_; - return *this; - } + _LIBCPP_HIDE_FROM_ABI unordered_set& operator=(const unordered_set& __u) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_set& operator=(unordered_set&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_set& operator=(unordered_set&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_set& operator=(initializer_list<value_type> __il); # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__table_.__node_alloc()); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } # ifndef _LIBCPP_CXX03_LANG template <class... _Args> @@ -808,10 +801,10 @@ public: "node_type with incompatible allocator passed to unordered_set::insert()"); return __table_.template __node_handle_insert_unique<node_type>(__h, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __table_.template __node_handle_extract<node_type>(__key); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __it) { return __table_.template __node_handle_extract<node_type>(__it); } @@ -845,71 +838,81 @@ public: __table_.swap(__u.__table_); } - _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); } - _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __table_.find(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __table_.find(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_unique(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __table_.__count_unique(__k); + } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __table_.__count_unique(__k); } # endif // _LIBCPP_STD_VER >= 20 # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __table_.__equal_range_unique(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __table_.__equal_range_unique(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __table_.__equal_range_unique(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __table_.__equal_range_unique(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } - _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { + return __table_.max_bucket_count(); + } - _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); } - _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { + return __table_.bucket_size(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } - _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } - _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } - _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); } _LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_unique(__n); } _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_unique(__n); } @@ -917,47 +920,48 @@ public: # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Hash = hash<__iter_value_type<_InputIterator>>, - class _Pred = equal_to<__iter_value_type<_InputIterator>>, - class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class _Hash = hash<__iterator_value_type<_InputIterator>>, + class _Pred = equal_to<__iterator_value_type<_InputIterator>>, + class _Allocator = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0, _Hash = _Hash(), _Pred = _Pred(), - _Allocator = _Allocator()) -> unordered_set<__iter_value_type<_InputIterator>, _Hash, _Pred, _Allocator>; + _Allocator = _Allocator()) + -> unordered_set<__iterator_value_type<_InputIterator>, _Hash, _Pred, _Allocator>; # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Hash = hash<ranges::range_value_t<_Range>>, class _Pred = equal_to<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> -unordered_set( - from_range_t, - _Range&&, - typename allocator_traits<_Allocator>::size_type = 0, - _Hash = _Hash(), - _Pred = _Pred(), - _Allocator = _Allocator()) -> unordered_set<ranges::range_value_t<_Range>, _Hash, _Pred, _Allocator>; // C++23 + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> +unordered_set(from_range_t, + _Range&&, + typename allocator_traits<_Allocator>::size_type = 0, + _Hash = _Hash(), + _Pred = _Pred(), + _Allocator = _Allocator()) + -> unordered_set<ranges::range_value_t<_Range>, _Hash, _Pred, _Allocator>; // C++23 # endif template <class _Tp, class _Hash = hash<_Tp>, class _Pred = equal_to<_Tp>, class _Allocator = allocator<_Tp>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type = 0, _Hash = _Hash(), @@ -967,33 +971,36 @@ unordered_set(initializer_list<_Tp>, template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) - -> unordered_set<__iter_value_type<_InputIterator>, - hash<__iter_value_type<_InputIterator>>, - equal_to<__iter_value_type<_InputIterator>>, + -> unordered_set<__iterator_value_type<_InputIterator>, + hash<__iterator_value_type<_InputIterator>>, + equal_to<__iterator_value_type<_InputIterator>>, _Allocator>; template <class _InputIterator, class _Hash, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) - -> unordered_set<__iter_value_type<_InputIterator>, _Hash, equal_to<__iter_value_type<_InputIterator>>, _Allocator>; + -> unordered_set<__iterator_value_type<_InputIterator>, + _Hash, + equal_to<__iterator_value_type<_InputIterator>>, + _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_set<ranges::range_value_t<_Range>, hash<ranges::range_value_t<_Range>>, equal_to<ranges::range_value_t<_Range>>, _Allocator>; -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(from_range_t, _Range&&, _Allocator) -> unordered_set<ranges::range_value_t<_Range>, hash<ranges::range_value_t<_Range>>, @@ -1003,24 +1010,24 @@ unordered_set(from_range_t, _Range&&, _Allocator) template <ranges::input_range _Range, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_set<ranges::range_value_t<_Range>, _Hash, equal_to<ranges::range_value_t<_Range>>, _Allocator>; # endif -template <class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_set<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; template <class _Tp, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_set(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_set<_Tp, _Hash, equal_to<_Tp>, _Allocator>; # endif @@ -1071,12 +1078,6 @@ template <class _Value, class _Hash, class _Pred, class _Alloc> inline unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const allocator_type& __a) : __table_(__a) {} template <class _Value, class _Hash, class _Pred, class _Alloc> -unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const unordered_set& __u) : __table_(__u.__table_) { - __table_.__rehash_unique(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -template <class _Value, class _Hash, class _Pred, class _Alloc> unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const unordered_set& __u, const allocator_type& __a) : __table_(__u.__table_, __a) { __table_.__rehash_unique(__u.bucket_count()); @@ -1086,11 +1087,6 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(const unordered_set& # ifndef _LIBCPP_CXX03_LANG template <class _Value, class _Hash, class _Pred, class _Alloc> -inline unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(unordered_set&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value) - : __table_(std::move(__u.__table_)) {} - -template <class _Value, class _Hash, class _Pred, class _Alloc> unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set(unordered_set&& __u, const allocator_type& __a) : __table_(std::move(__u.__table_), __a) { if (__a != __u.get_allocator()) { @@ -1127,14 +1123,6 @@ unordered_set<_Value, _Hash, _Pred, _Alloc>::unordered_set( template <class _Value, class _Hash, class _Pred, class _Alloc> inline unordered_set<_Value, _Hash, _Pred, _Alloc>& -unordered_set<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_set&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value) { - __table_ = std::move(__u.__table_); - return *this; -} - -template <class _Value, class _Hash, class _Pred, class _Alloc> -inline unordered_set<_Value, _Hash, _Pred, _Alloc>& unordered_set<_Value, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) { __table_.__assign_unique(__il.begin(), __il.end()); return *this; @@ -1308,11 +1296,10 @@ public: # endif _LIBCPP_HIDE_FROM_ABI explicit unordered_multiset(const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u); + _LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multiset(const unordered_multiset& __u, const allocator_type& __a); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_multiset(unordered_multiset&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_multiset(unordered_multiset&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multiset(unordered_multiset&& __u, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI unordered_multiset(initializer_list<value_type> __il); _LIBCPP_HIDE_FROM_ABI unordered_multiset( @@ -1339,30 +1326,26 @@ public: static_assert(sizeof(std::__diagnose_unordered_container_requirements<_Value, _Hash, _Pred>(0)), ""); } - _LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(const unordered_multiset& __u) { - __table_ = __u.__table_; - return *this; - } + _LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(const unordered_multiset& __u) = default; # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(unordered_multiset&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value); + _LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(unordered_multiset&& __u) = default; _LIBCPP_HIDE_FROM_ABI unordered_multiset& operator=(initializer_list<value_type> __il); # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI allocator_type get_allocator() const _NOEXCEPT { return allocator_type(__table_.__node_alloc()); } [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool empty() const _NOEXCEPT { return __table_.size() == 0; } - _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } - _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type size() const _NOEXCEPT { return __table_.size(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_size() const _NOEXCEPT { return __table_.max_size(); } - _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } - _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator end() _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator begin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator end() const _NOEXCEPT { return __table_.end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const _NOEXCEPT { return __table_.begin(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator cend() const _NOEXCEPT { return __table_.end(); } # ifndef _LIBCPP_CXX03_LANG template <class... _Args> @@ -1410,10 +1393,10 @@ public: "node_type with incompatible allocator passed to unordered_multiset::insert()"); return __table_.template __node_handle_insert_multi<node_type>(__hint, std::move(__nh)); } - _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __position) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(const_iterator __position) { return __table_.template __node_handle_extract<node_type>(__position); } - _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { return __table_.template __node_handle_extract<node_type>(__key); } @@ -1454,71 +1437,81 @@ public: __table_.swap(__u.__table_); } - _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); } - _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI hasher hash_function() const { return __table_.hash_function(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI key_equal key_eq() const { return __table_.key_eq(); } - _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } - _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __k) { return __table_.find(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __k) const { return __table_.find(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI iterator find(const _K2& __k) { return __table_.find(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_iterator find(const _K2& __k) const { return __table_.find(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { return __table_.__count_multi(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const key_type& __k) const { + return __table_.__count_multi(__k); + } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type count(const _K2& __k) const { return __table_.__count_multi(__k); } # endif // _LIBCPP_STD_VER >= 20 # if _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __k) const { return find(__k) != end(); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI bool contains(const _K2& __k) const { return find(__k) != end(); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const key_type& __k) { return __table_.__equal_range_multi(__k); } - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const key_type& __k) const { return __table_.__equal_range_multi(__k); } # if _LIBCPP_STD_VER >= 20 template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<iterator, iterator> equal_range(const _K2& __k) { return __table_.__equal_range_multi(__k); } template <class _K2, enable_if_t<__is_transparent_v<hasher, _K2> && __is_transparent_v<key_equal, _K2>>* = nullptr> - _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI pair<const_iterator, const_iterator> equal_range(const _K2& __k) const { return __table_.__equal_range_multi(__k); } # endif // _LIBCPP_STD_VER >= 20 - _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } - _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { return __table_.max_bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_count() const _NOEXCEPT { return __table_.bucket_count(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type max_bucket_count() const _NOEXCEPT { + return __table_.max_bucket_count(); + } - _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { return __table_.bucket_size(__n); } - _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket_size(size_type __n) const { + return __table_.bucket_size(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_type bucket(const key_type& __k) const { return __table_.bucket(__k); } - _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } - _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { return __table_.cbegin(__n); } - _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator begin(size_type __n) { return __table_.begin(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI local_iterator end(size_type __n) { return __table_.end(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator begin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator end(size_type __n) const { return __table_.cend(__n); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cbegin(size_type __n) const { + return __table_.cbegin(__n); + } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const_local_iterator cend(size_type __n) const { return __table_.cend(__n); } - _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } - _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float load_factor() const _NOEXCEPT { return __table_.load_factor(); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI float max_load_factor() const _NOEXCEPT { return __table_.max_load_factor(); } _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) { __table_.max_load_factor(__mlf); } _LIBCPP_HIDE_FROM_ABI void rehash(size_type __n) { __table_.__rehash_multi(__n); } _LIBCPP_HIDE_FROM_ABI void reserve(size_type __n) { __table_.__reserve_multi(__n); } @@ -1526,31 +1519,31 @@ public: # if _LIBCPP_STD_VER >= 17 template <class _InputIterator, - class _Hash = hash<__iter_value_type<_InputIterator>>, - class _Pred = equal_to<__iter_value_type<_InputIterator>>, - class _Allocator = allocator<__iter_value_type<_InputIterator>>, + class _Hash = hash<__iterator_value_type<_InputIterator>>, + class _Pred = equal_to<__iterator_value_type<_InputIterator>>, + class _Allocator = allocator<__iterator_value_type<_InputIterator>>, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset( _InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type = 0, _Hash = _Hash(), _Pred = _Pred(), - _Allocator = _Allocator()) -> unordered_multiset<__iter_value_type<_InputIterator>, _Hash, _Pred, _Allocator>; + _Allocator = _Allocator()) -> unordered_multiset<__iterator_value_type<_InputIterator>, _Hash, _Pred, _Allocator>; # if _LIBCPP_STD_VER >= 23 template <ranges::input_range _Range, class _Hash = hash<ranges::range_value_t<_Range>>, class _Pred = equal_to<ranges::range_value_t<_Range>>, class _Allocator = allocator<ranges::range_value_t<_Range>>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset( from_range_t, _Range&&, @@ -1564,10 +1557,10 @@ template <class _Tp, class _Hash = hash<_Tp>, class _Pred = equal_to<_Tp>, class _Allocator = allocator<_Tp>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<!__is_allocator<_Pred>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<!__is_allocator_v<_Pred>>, + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type = 0, _Hash = _Hash(), @@ -1577,36 +1570,36 @@ unordered_multiset(initializer_list<_Tp>, template <class _InputIterator, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Allocator) - -> unordered_multiset<__iter_value_type<_InputIterator>, - hash<__iter_value_type<_InputIterator>>, - equal_to<__iter_value_type<_InputIterator>>, + -> unordered_multiset<__iterator_value_type<_InputIterator>, + hash<__iterator_value_type<_InputIterator>>, + equal_to<__iterator_value_type<_InputIterator>>, _Allocator>; template <class _InputIterator, class _Hash, class _Allocator, class = enable_if_t<__has_input_iterator_category<_InputIterator>::value>, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(_InputIterator, _InputIterator, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) - -> unordered_multiset<__iter_value_type<_InputIterator>, + -> unordered_multiset<__iterator_value_type<_InputIterator>, _Hash, - equal_to<__iter_value_type<_InputIterator>>, + equal_to<__iterator_value_type<_InputIterator>>, _Allocator>; # if _LIBCPP_STD_VER >= 23 -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multiset<ranges::range_value_t<_Range>, hash<ranges::range_value_t<_Range>>, equal_to<ranges::range_value_t<_Range>>, _Allocator>; -template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <ranges::input_range _Range, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(from_range_t, _Range&&, _Allocator) -> unordered_multiset<ranges::range_value_t<_Range>, hash<ranges::range_value_t<_Range>>, @@ -1616,24 +1609,24 @@ unordered_multiset(from_range_t, _Range&&, _Allocator) template <ranges::input_range _Range, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(from_range_t, _Range&&, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_multiset<ranges::range_value_t<_Range>, _Hash, equal_to<ranges::range_value_t<_Range>>, _Allocator>; # endif -template <class _Tp, class _Allocator, class = enable_if_t<__is_allocator<_Allocator>::value>> +template <class _Tp, class _Allocator, class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type, _Allocator) -> unordered_multiset<_Tp, hash<_Tp>, equal_to<_Tp>, _Allocator>; template <class _Tp, class _Hash, class _Allocator, - class = enable_if_t<!__is_allocator<_Hash>::value>, + class = enable_if_t<!__is_allocator_v<_Hash>>, class = enable_if_t<!is_integral<_Hash>::value>, - class = enable_if_t<__is_allocator<_Allocator>::value>> + class = enable_if_t<__is_allocator_v<_Allocator>>> unordered_multiset(initializer_list<_Tp>, typename allocator_traits<_Allocator>::size_type, _Hash, _Allocator) -> unordered_multiset<_Tp, _Hash, equal_to<_Tp>, _Allocator>; # endif @@ -1686,13 +1679,6 @@ inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(cons : __table_(__a) {} template <class _Value, class _Hash, class _Pred, class _Alloc> -unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(const unordered_multiset& __u) - : __table_(__u.__table_) { - __table_.__rehash_multi(__u.bucket_count()); - insert(__u.begin(), __u.end()); -} - -template <class _Value, class _Hash, class _Pred, class _Alloc> unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset( const unordered_multiset& __u, const allocator_type& __a) : __table_(__u.__table_, __a) { @@ -1703,11 +1689,6 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset( # ifndef _LIBCPP_CXX03_LANG template <class _Value, class _Hash, class _Pred, class _Alloc> -inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset(unordered_multiset&& __u) - _NOEXCEPT_(is_nothrow_move_constructible<__table>::value) - : __table_(std::move(__u.__table_)) {} - -template <class _Value, class _Hash, class _Pred, class _Alloc> unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset( unordered_multiset&& __u, const allocator_type& __a) : __table_(std::move(__u.__table_), __a) { @@ -1745,14 +1726,6 @@ unordered_multiset<_Value, _Hash, _Pred, _Alloc>::unordered_multiset( template <class _Value, class _Hash, class _Pred, class _Alloc> inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>& -unordered_multiset<_Value, _Hash, _Pred, _Alloc>::operator=(unordered_multiset&& __u) - _NOEXCEPT_(is_nothrow_move_assignable<__table>::value) { - __table_ = std::move(__u.__table_); - return *this; -} - -template <class _Value, class _Hash, class _Pred, class _Alloc> -inline unordered_multiset<_Value, _Hash, _Pred, _Alloc>& unordered_multiset<_Value, _Hash, _Pred, _Alloc>::operator=(initializer_list<value_type> __il) { __table_.__assign_multi(__il.begin(), __il.end()); return *this; diff --git a/lib/libcxx/include/utility b/lib/libcxx/include/utility @@ -216,6 +216,18 @@ template<size_t N> template<class... T> using index_sequence_for = make_index_sequence<sizeof...(T)>; +template<class T, T... Values> // C++26 + struct tuple_size<integer_sequence<T, Values...>>; + +template<size_t I, class T, T... Values> // C++26 + struct tuple_element<I, integer_sequence<T, Values...>>; + +template<size_t I, class T, T... Values> // C++26 + struct tuple_element<I, const integer_sequence<T, Values...>>; + +template<size_t I, class T, T... Values> // C++26 + constexpr T get(integer_sequence<T, Values...>) noexcept; + template<class T, class U=T> constexpr T exchange(T& obj, U&& new_value) // constexpr in C++17, noexcept in C++23 noexcept(is_nothrow_move_constructible<T>::value && is_nothrow_assignable<T&, U>::value); diff --git a/lib/libcxx/include/valarray b/lib/libcxx/include/valarray @@ -362,6 +362,7 @@ template <class T> unspecified2 end(const valarray<T>& v); # include <__memory/uninitialized_algorithms.h> # include <__type_traits/decay.h> # include <__type_traits/remove_reference.h> +# include <__utility/exception_guard.h> # include <__utility/move.h> # include <__utility/swap.h> # include <cmath> @@ -395,9 +396,9 @@ public: _LIBCPP_HIDE_FROM_ABI slice(size_t __start, size_t __size, size_t __stride) : __start_(__start), __size_(__size), __stride_(__stride) {} - _LIBCPP_HIDE_FROM_ABI size_t start() const { return __start_; } - _LIBCPP_HIDE_FROM_ABI size_t size() const { return __size_; } - _LIBCPP_HIDE_FROM_ABI size_t stride() const { return __stride_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t start() const { return __start_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t size() const { return __size_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t stride() const { return __stride_; } # if _LIBCPP_STD_VER >= 20 @@ -792,7 +793,7 @@ private: public: // construct/destroy: _LIBCPP_HIDE_FROM_ABI valarray() : __begin_(nullptr), __end_(nullptr) {} - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 explicit valarray(size_t __n); + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 explicit valarray(size_t __n); _LIBCPP_HIDE_FROM_ABI valarray(const value_type& __x, size_t __n); valarray(const value_type* __p, size_t __n); valarray(const valarray& __v); @@ -804,7 +805,7 @@ public: valarray(const gslice_array<value_type>& __ga); valarray(const mask_array<value_type>& __ma); valarray(const indirect_array<value_type>& __ia); - inline _LIBCPP_HIDE_FROM_ABI_AFTER_V1 ~valarray(); + inline _LIBCPP_HIDE_FROM_ABI_SINCE_LLVM8 ~valarray(); // assignment: valarray& operator=(const valarray& __v); @@ -821,36 +822,41 @@ public: _LIBCPP_HIDE_FROM_ABI valarray& operator=(const __val_expr<_ValExpr>& __v); // element access: - _LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI const value_type& operator[](size_t __i) const { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds"); return __begin_[__i]; } - _LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) { + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_type& operator[](size_t __i) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__i < size(), "valarray::operator[] index out of bounds"); return __begin_[__i]; } // subset operations: - _LIBCPP_HIDE_FROM_ABI __val_expr<__slice_expr<const valarray&> > operator[](slice __s) const; - _LIBCPP_HIDE_FROM_ABI slice_array<value_type> operator[](slice __s); - _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > operator[](const gslice& __gs) const; - _LIBCPP_HIDE_FROM_ABI gslice_array<value_type> operator[](const gslice& __gs); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__slice_expr<const valarray&> > operator[](slice __s) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI slice_array<value_type> operator[](slice __s); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > + operator[](const gslice& __gs) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI gslice_array<value_type> operator[](const gslice& __gs); # ifndef _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > operator[](gslice&& __gs) const; - _LIBCPP_HIDE_FROM_ABI gslice_array<value_type> operator[](gslice&& __gs); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > operator[](gslice&& __gs) const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI gslice_array<value_type> operator[](gslice&& __gs); # endif // _LIBCPP_CXX03_LANG + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__mask_expr<const valarray&> > operator[](const valarray<bool>& __vb) const; - _LIBCPP_HIDE_FROM_ABI mask_array<value_type> operator[](const valarray<bool>& __vb); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mask_array<value_type> operator[](const valarray<bool>& __vb); # ifndef _LIBCPP_CXX03_LANG + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__mask_expr<const valarray&> > operator[](valarray<bool>&& __vb) const; - _LIBCPP_HIDE_FROM_ABI mask_array<value_type> operator[](valarray<bool>&& __vb); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI mask_array<value_type> operator[](valarray<bool>&& __vb); # endif // _LIBCPP_CXX03_LANG + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > operator[](const valarray<size_t>& __vs) const; - _LIBCPP_HIDE_FROM_ABI indirect_array<value_type> operator[](const valarray<size_t>& __vs); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI indirect_array<value_type> operator[](const valarray<size_t>& __vs); # ifndef _LIBCPP_CXX03_LANG + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI __val_expr<__indirect_expr<const valarray&> > operator[](valarray<size_t>&& __vs) const; - _LIBCPP_HIDE_FROM_ABI indirect_array<value_type> operator[](valarray<size_t>&& __vs); + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI indirect_array<value_type> operator[](valarray<size_t>&& __vs); # endif // _LIBCPP_CXX03_LANG // unary operators: @@ -904,16 +910,16 @@ public: // member functions: _LIBCPP_HIDE_FROM_ABI void swap(valarray& __v) _NOEXCEPT; - _LIBCPP_HIDE_FROM_ABI size_t size() const { return static_cast<size_t>(__end_ - __begin_); } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t size() const { return static_cast<size_t>(__end_ - __begin_); } - _LIBCPP_HIDE_FROM_ABI value_type sum() const; - _LIBCPP_HIDE_FROM_ABI value_type min() const; - _LIBCPP_HIDE_FROM_ABI value_type max() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_type sum() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_type min() const; + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI value_type max() const; - valarray shift(int __i) const; - valarray cshift(int __i) const; - valarray apply(value_type __f(value_type)) const; - valarray apply(value_type __f(const value_type&)) const; + [[__nodiscard__]] valarray shift(int __i) const; + [[__nodiscard__]] valarray cshift(int __i) const; + [[__nodiscard__]] valarray apply(value_type __f(value_type)) const; + [[__nodiscard__]] valarray apply(value_type __f(const value_type&)) const; void resize(size_t __n, value_type __x = value_type()); private: @@ -1248,11 +1254,11 @@ public: # endif // _LIBCPP_CXX03_LANG - _LIBCPP_HIDE_FROM_ABI size_t start() const { return __1d_.size() ? __1d_[0] : 0; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t start() const { return __1d_.size() ? __1d_[0] : 0; } - _LIBCPP_HIDE_FROM_ABI valarray<size_t> size() const { return __size_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI valarray<size_t> size() const { return __size_; } - _LIBCPP_HIDE_FROM_ABI valarray<size_t> stride() const { return __stride_; } + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI valarray<size_t> stride() const { return __stride_; } private: void __init(size_t __start); @@ -1992,17 +1998,10 @@ template <class _Tp> inline valarray<_Tp>::valarray(size_t __n) : __begin_(nullptr), __end_(nullptr) { if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) - ::new ((void*)__end_) value_type(); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) + ::new ((void*)__end_) value_type(); + __guard.__complete(); } } @@ -2015,17 +2014,10 @@ template <class _Tp> valarray<_Tp>::valarray(const value_type* __p, size_t __n) : __begin_(nullptr), __end_(nullptr) { if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (size_t __n_left = __n; __n_left; ++__end_, ++__p, --__n_left) - ::new ((void*)__end_) value_type(*__p); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + for (size_t __n_left = __n; __n_left; ++__end_, ++__p, --__n_left) + ::new ((void*)__end_) value_type(*__p); + __guard.__complete(); } } @@ -2033,17 +2025,10 @@ template <class _Tp> valarray<_Tp>::valarray(const valarray& __v) : __begin_(nullptr), __end_(nullptr) { if (__v.size()) { __begin_ = __end_ = allocator<value_type>().allocate(__v.size()); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (value_type* __p = __v.__begin_; __p != __v.__end_; ++__end_, ++__p) - ::new ((void*)__end_) value_type(*__p); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__v.size()); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__v.size()); }); + for (value_type* __p = __v.__begin_; __p != __v.__end_; ++__end_, ++__p) + ::new ((void*)__end_) value_type(*__p); + __guard.__complete(); } } @@ -2059,18 +2044,11 @@ valarray<_Tp>::valarray(initializer_list<value_type> __il) : __begin_(nullptr), const size_t __n = __il.size(); if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - size_t __n_left = __n; - for (const value_type* __p = __il.begin(); __n_left; ++__end_, ++__p, --__n_left) - ::new ((void*)__end_) value_type(*__p); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + size_t __n_left = __n; + for (const value_type* __p = __il.begin(); __n_left; ++__end_, ++__p, --__n_left) + ::new ((void*)__end_) value_type(*__p); + __guard.__complete(); } } @@ -2081,18 +2059,11 @@ valarray<_Tp>::valarray(const slice_array<value_type>& __sa) : __begin_(nullptr) const size_t __n = __sa.__size_; if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - size_t __n_left = __n; - for (const value_type* __p = __sa.__vp_; __n_left; ++__end_, __p += __sa.__stride_, --__n_left) - ::new ((void*)__end_) value_type(*__p); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + size_t __n_left = __n; + for (const value_type* __p = __sa.__vp_; __n_left; ++__end_, __p += __sa.__stride_, --__n_left) + ::new ((void*)__end_) value_type(*__p); + __guard.__complete(); } } @@ -2101,19 +2072,12 @@ valarray<_Tp>::valarray(const gslice_array<value_type>& __ga) : __begin_(nullptr const size_t __n = __ga.__1d_.size(); if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - typedef const size_t* _Ip; - const value_type* __s = __ga.__vp_; - for (_Ip __i = __ga.__1d_.__begin_, __e = __ga.__1d_.__end_; __i != __e; ++__i, ++__end_) - ::new ((void*)__end_) value_type(__s[*__i]); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + typedef const size_t* _Ip; + const value_type* __s = __ga.__vp_; + for (_Ip __i = __ga.__1d_.__begin_, __e = __ga.__1d_.__end_; __i != __e; ++__i, ++__end_) + ::new ((void*)__end_) value_type(__s[*__i]); + __guard.__complete(); } } @@ -2122,19 +2086,12 @@ valarray<_Tp>::valarray(const mask_array<value_type>& __ma) : __begin_(nullptr), const size_t __n = __ma.__1d_.size(); if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - typedef const size_t* _Ip; - const value_type* __s = __ma.__vp_; - for (_Ip __i = __ma.__1d_.__begin_, __e = __ma.__1d_.__end_; __i != __e; ++__i, ++__end_) - ::new ((void*)__end_) value_type(__s[*__i]); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + typedef const size_t* _Ip; + const value_type* __s = __ma.__vp_; + for (_Ip __i = __ma.__1d_.__begin_, __e = __ma.__1d_.__end_; __i != __e; ++__i, ++__end_) + ::new ((void*)__end_) value_type(__s[*__i]); + __guard.__complete(); } } @@ -2143,19 +2100,12 @@ valarray<_Tp>::valarray(const indirect_array<value_type>& __ia) : __begin_(nullp const size_t __n = __ia.__1d_.size(); if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - typedef const size_t* _Ip; - const value_type* __s = __ia.__vp_; - for (_Ip __i = __ia.__1d_.__begin_, __e = __ia.__1d_.__end_; __i != __e; ++__i, ++__end_) - ::new ((void*)__end_) value_type(__s[*__i]); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + typedef const size_t* _Ip; + const value_type* __s = __ia.__vp_; + for (_Ip __i = __ia.__1d_.__begin_, __e = __ia.__1d_.__end_; __i != __e; ++__i, ++__end_) + ::new ((void*)__end_) value_type(__s[*__i]); + __guard.__complete(); } } @@ -2644,17 +2594,10 @@ void valarray<_Tp>::resize(size_t __n, value_type __x) { __clear(size()); if (__n) { __begin_ = __end_ = allocator<value_type>().allocate(__n); -# if _LIBCPP_HAS_EXCEPTIONS - try { -# endif // _LIBCPP_HAS_EXCEPTIONS - for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) - ::new ((void*)__end_) value_type(__x); -# if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - __clear(__n); - throw; - } -# endif // _LIBCPP_HAS_EXCEPTIONS + auto __guard = std::__make_exception_guard([&] { __clear(__n); }); + for (size_t __n_left = __n; __n_left; --__n_left, ++__end_) + ::new ((void*)__end_) value_type(__x); + __guard.__complete(); } } @@ -3168,7 +3111,7 @@ operator>=(const typename _Expr::value_type& __x, const _Expr& __y) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__abs_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__abs_expr<typename _Expr::value_type>, _Expr> > abs(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__abs_expr<value_type>, _Expr> _Op; @@ -3176,7 +3119,7 @@ abs(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__acos_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__acos_expr<typename _Expr::value_type>, _Expr> > acos(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__acos_expr<value_type>, _Expr> _Op; @@ -3184,7 +3127,7 @@ acos(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__asin_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__asin_expr<typename _Expr::value_type>, _Expr> > asin(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__asin_expr<value_type>, _Expr> _Op; @@ -3192,7 +3135,7 @@ asin(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__atan_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__atan_expr<typename _Expr::value_type>, _Expr> > atan(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__atan_expr<value_type>, _Expr> _Op; @@ -3202,15 +3145,16 @@ atan(const _Expr& __x) { template <class _Expr1, class _Expr2, __enable_if_t<__is_val_expr<_Expr1>::value && __is_val_expr<_Expr2>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__atan2_expr<typename _Expr1::value_type>, _Expr1, _Expr2> > -atan2(const _Expr1& __x, const _Expr2& __y) { +[[__nodiscard__]] inline + _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__atan2_expr<typename _Expr1::value_type>, _Expr1, _Expr2> > + atan2(const _Expr1& __x, const _Expr2& __y) { typedef typename _Expr1::value_type value_type; typedef _BinaryOp<__atan2_expr<value_type>, _Expr1, _Expr2> _Op; return __val_expr<_Op>(_Op(__atan2_expr<value_type>(), __x, __y)); } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__atan2_expr<typename _Expr::value_type>, _Expr, __scalar_expr<typename _Expr::value_type> > > atan2(const _Expr& __x, const typename _Expr::value_type& __y) { typedef typename _Expr::value_type value_type; @@ -3219,7 +3163,7 @@ atan2(const _Expr& __x, const typename _Expr::value_type& __y) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__atan2_expr<typename _Expr::value_type>, __scalar_expr<typename _Expr::value_type>, _Expr> > atan2(const typename _Expr::value_type& __x, const _Expr& __y) { typedef typename _Expr::value_type value_type; @@ -3228,7 +3172,7 @@ atan2(const typename _Expr::value_type& __x, const _Expr& __y) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__cos_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__cos_expr<typename _Expr::value_type>, _Expr> > cos(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__cos_expr<value_type>, _Expr> _Op; @@ -3236,7 +3180,7 @@ cos(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__cosh_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__cosh_expr<typename _Expr::value_type>, _Expr> > cosh(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__cosh_expr<value_type>, _Expr> _Op; @@ -3244,7 +3188,7 @@ cosh(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__exp_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__exp_expr<typename _Expr::value_type>, _Expr> > exp(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__exp_expr<value_type>, _Expr> _Op; @@ -3252,7 +3196,7 @@ exp(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__log_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__log_expr<typename _Expr::value_type>, _Expr> > log(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__log_expr<value_type>, _Expr> _Op; @@ -3260,7 +3204,7 @@ log(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__log10_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__log10_expr<typename _Expr::value_type>, _Expr> > log10(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__log10_expr<value_type>, _Expr> _Op; @@ -3270,15 +3214,16 @@ log10(const _Expr& __x) { template <class _Expr1, class _Expr2, __enable_if_t<__is_val_expr<_Expr1>::value && __is_val_expr<_Expr2>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__pow_expr<typename _Expr1::value_type>, _Expr1, _Expr2> > -pow(const _Expr1& __x, const _Expr2& __y) { +[[__nodiscard__]] inline + _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__pow_expr<typename _Expr1::value_type>, _Expr1, _Expr2> > + pow(const _Expr1& __x, const _Expr2& __y) { typedef typename _Expr1::value_type value_type; typedef _BinaryOp<__pow_expr<value_type>, _Expr1, _Expr2> _Op; return __val_expr<_Op>(_Op(__pow_expr<value_type>(), __x, __y)); } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__pow_expr<typename _Expr::value_type>, _Expr, __scalar_expr<typename _Expr::value_type> > > pow(const _Expr& __x, const typename _Expr::value_type& __y) { typedef typename _Expr::value_type value_type; @@ -3287,7 +3232,7 @@ pow(const _Expr& __x, const typename _Expr::value_type& __y) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_BinaryOp<__pow_expr<typename _Expr::value_type>, __scalar_expr<typename _Expr::value_type>, _Expr> > pow(const typename _Expr::value_type& __x, const _Expr& __y) { typedef typename _Expr::value_type value_type; @@ -3296,7 +3241,7 @@ pow(const typename _Expr::value_type& __x, const _Expr& __y) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sin_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sin_expr<typename _Expr::value_type>, _Expr> > sin(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__sin_expr<value_type>, _Expr> _Op; @@ -3304,7 +3249,7 @@ sin(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sinh_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sinh_expr<typename _Expr::value_type>, _Expr> > sinh(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__sinh_expr<value_type>, _Expr> _Op; @@ -3312,7 +3257,7 @@ sinh(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sqrt_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__sqrt_expr<typename _Expr::value_type>, _Expr> > sqrt(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__sqrt_expr<value_type>, _Expr> _Op; @@ -3320,7 +3265,7 @@ sqrt(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__tan_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__tan_expr<typename _Expr::value_type>, _Expr> > tan(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__tan_expr<value_type>, _Expr> _Op; @@ -3328,7 +3273,7 @@ tan(const _Expr& __x) { } template <class _Expr, __enable_if_t<__is_val_expr<_Expr>::value, int> = 0> -inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__tanh_expr<typename _Expr::value_type>, _Expr> > +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI __val_expr<_UnaryOp<__tanh_expr<typename _Expr::value_type>, _Expr> > tanh(const _Expr& __x) { typedef typename _Expr::value_type value_type; typedef _UnaryOp<__tanh_expr<value_type>, _Expr> _Op; @@ -3336,22 +3281,22 @@ tanh(const _Expr& __x) { } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _Tp* begin(valarray<_Tp>& __v) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _Tp* begin(valarray<_Tp>& __v) { return __v.__begin_; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI const _Tp* begin(const valarray<_Tp>& __v) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI const _Tp* begin(const valarray<_Tp>& __v) { return __v.__begin_; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI _Tp* end(valarray<_Tp>& __v) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _Tp* end(valarray<_Tp>& __v) { return __v.__end_; } template <class _Tp> -inline _LIBCPP_HIDE_FROM_ABI const _Tp* end(const valarray<_Tp>& __v) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI const _Tp* end(const valarray<_Tp>& __v) { return __v.__end_; } diff --git a/lib/libcxx/include/variant b/lib/libcxx/include/variant @@ -247,7 +247,6 @@ namespace std { # include <__type_traits/is_nothrow_assignable.h> # include <__type_traits/is_nothrow_constructible.h> # include <__type_traits/is_reference.h> -# include <__type_traits/is_replaceable.h> # include <__type_traits/is_same.h> # include <__type_traits/is_swappable.h> # include <__type_traits/is_trivially_assignable.h> @@ -289,7 +288,7 @@ _LIBCPP_BEGIN_UNVERSIONED_NAMESPACE_STD class _LIBCPP_EXPORTED_FROM_ABI bad_variant_access : public exception { public: - const char* what() const _NOEXCEPT override; + [[__nodiscard__]] const char* what() const _NOEXCEPT override; }; _LIBCPP_END_UNVERSIONED_NAMESPACE_STD @@ -918,18 +917,10 @@ protected: _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_alt(__alt<_Ip, _Tp>& __a, _Arg&& __arg) { if (this->index() == _Ip) { __a.__value = std::forward<_Arg>(__arg); + } else if constexpr (is_nothrow_constructible_v<_Tp, _Arg> || !is_nothrow_move_constructible_v<_Tp>) { + this->__emplace<_Ip>(std::forward<_Arg>(__arg)); } else { - struct { - _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()(true_type) const { - __this->__emplace<_Ip>(std::forward<_Arg>(__arg)); - } - _LIBCPP_HIDDEN _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()(false_type) const { - __this->__emplace<_Ip>(_Tp(std::forward<_Arg>(__arg))); - } - __assignment* __this; - _Arg&& __arg; - } __impl{this, std::forward<_Arg>(__arg)}; - __impl(bool_constant < is_nothrow_constructible_v<_Tp, _Arg> || !is_nothrow_move_constructible_v < _Tp >> {}); + this->__emplace<_Ip>(_Tp(std::forward<_Arg>(__arg))); } } @@ -1127,14 +1118,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; @@ -1172,7 +1163,6 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES _LIBCPP_NO_SPECIALIZATIONS variant public: using __trivially_relocatable _LIBCPP_NODEBUG = conditional_t<_And<__libcpp_is_trivially_relocatable<_Types>...>::value, variant, void>; - using __replaceable _LIBCPP_NODEBUG = conditional_t<_And<__is_replaceable<_Types>...>::value, variant, void>; template <bool _Dummy = true, enable_if_t<__dependent_type<is_default_constructible<__first_type>, _Dummy>::value, int> = 0> @@ -1284,11 +1274,11 @@ public: return __impl_.template __emplace<_Ip>(__il, std::forward<_Args>(__args)...); } - _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool valueless_by_exception() const noexcept { return __impl_.valueless_by_exception(); } - _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __impl_.index(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t index() const noexcept { return __impl_.index(); } template < bool _Dummy = true, enable_if_t< __all<(__dependent_type<is_move_constructible<_Types>, _Dummy>::value && @@ -1299,7 +1289,7 @@ public: __impl_.__swap(__that.__impl_); } -# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER +# if _LIBCPP_STD_VER >= 26 // Helper class to implement [variant.visit]/10 // Constraints: The call to visit does not use an explicit template-argument-list // that begins with a type template-argument. @@ -1331,7 +1321,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __holds_alternative(const variant<_Types... } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool holds_alternative(const variant<_Types...>& __v) noexcept { return std::__holds_alternative<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } @@ -1345,21 +1335,23 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto&& __generic_get(_Vp&& __v) { } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>& get(variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>& +get(variant<_Types...>& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); return std::__generic_get<_Ip>(__v); } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>&& get(variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr variant_alternative_t<_Ip, variant<_Types...>>&& +get(variant<_Types...>&& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); return std::__generic_get<_Ip>(std::move(__v)); } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>& +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>& get(const variant<_Types...>& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); @@ -1367,7 +1359,7 @@ get(const variant<_Types...>& __v) { } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const variant_alternative_t<_Ip, variant<_Types...>>&& get(const variant<_Types...>&& __v) { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); @@ -1375,25 +1367,25 @@ get(const variant<_Types...>&& __v) { } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& get(variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& get(variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(std::move(__v)); } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const variant<_Types...>& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& get(const variant<_Types...>& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const variant<_Types...>&& __v) { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& get(const variant<_Types...>&& __v) { static_assert(!is_void_v<_Tp>); return std::get<__find_exactly_one_t<_Tp, _Types...>::value>(std::move(__v)); } @@ -1405,7 +1397,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto* __generic_get_if(_Vp* __v) noexcept { } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<variant_alternative_t<_Ip, variant<_Types...>>> get_if(variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); @@ -1413,7 +1405,7 @@ get_if(variant<_Types...>* __v) noexcept { } template <size_t _Ip, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<const variant_alternative_t<_Ip, variant<_Types...>>> +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<const variant_alternative_t<_Ip, variant<_Types...>>> get_if(const variant<_Types...>* __v) noexcept { static_assert(_Ip < sizeof...(_Types)); static_assert(!is_void_v<variant_alternative_t<_Ip, variant<_Types...>>>); @@ -1421,13 +1413,13 @@ get_if(const variant<_Types...>* __v) noexcept { } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> get_if(variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); return std::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } template <class _Tp, class... _Types> -_LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<const _Tp> get_if(const variant<_Types...>* __v) noexcept { +[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<const _Tp> get_if(const variant<_Types...>* __v) noexcept { static_assert(!is_void_v<_Tp>); return std::get_if<__find_exactly_one_t<_Tp, _Types...>::value>(__v); } @@ -1608,7 +1600,7 @@ struct hash< __enable_hash_helper<variant<_Types...>, remove_const_t<_Types>...> using result_type _LIBCPP_DEPRECATED_IN_CXX17 = size_t; # endif - _LIBCPP_HIDE_FROM_ABI size_t operator()(const variant<_Types...>& __v) const { + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const variant<_Types...>& __v) const { using __variant_detail::__visitation::__variant; size_t __res = __v.valueless_by_exception() diff --git a/lib/libcxx/include/version b/lib/libcxx/include/version @@ -37,7 +37,8 @@ __cpp_lib_atomic_float 201711L <atomic> __cpp_lib_atomic_is_always_lock_free 201603L <atomic> __cpp_lib_atomic_lock_free_type_aliases 201907L <atomic> __cpp_lib_atomic_min_max 202403L <atomic> -__cpp_lib_atomic_ref 201806L <atomic> +__cpp_lib_atomic_ref 202411L <atomic> + 201806L // C++20 __cpp_lib_atomic_shared_ptr 201711L <atomic> __cpp_lib_atomic_value_initialization 201911L <atomic> <memory> __cpp_lib_atomic_wait 201907L <atomic> @@ -62,7 +63,7 @@ __cpp_lib_clamp 201603L <algorithm> __cpp_lib_common_reference 202302L <type_traits> __cpp_lib_common_reference_wrapper 202302L <functional> __cpp_lib_complex_udls 201309L <complex> -__cpp_lib_concepts 202002L <concepts> +__cpp_lib_concepts 202207L <concepts> __cpp_lib_constexpr_algorithms 202306L <algorithm> <utility> 201806L // C++20 __cpp_lib_constexpr_bitset 202207L <bitset> @@ -70,6 +71,8 @@ __cpp_lib_constexpr_charconv 202207L <charconv> __cpp_lib_constexpr_cmath 202202L <cmath> <cstdlib> __cpp_lib_constexpr_complex 201711L <complex> __cpp_lib_constexpr_dynamic_alloc 201907L <memory> +__cpp_lib_constexpr_flat_map 202502L <flat_map> +__cpp_lib_constexpr_flat_set 202502L <flat_set> __cpp_lib_constexpr_forward_list 202502L <forward_list> __cpp_lib_constexpr_functional 201907L <functional> __cpp_lib_constexpr_iterator 201811L <iterator> @@ -108,8 +111,8 @@ __cpp_lib_execution 201902L <execution> 201603L // C++17 __cpp_lib_expected 202211L <expected> __cpp_lib_filesystem 201703L <filesystem> -__cpp_lib_flat_map 202207L <flat_map> -__cpp_lib_flat_set 202207L <flat_set> +__cpp_lib_flat_map 202511L <flat_map> +__cpp_lib_flat_set 202511L <flat_set> __cpp_lib_format 202110L <format> __cpp_lib_format_path 202403L <filesystem> __cpp_lib_format_ranges 202207L <format> @@ -138,7 +141,8 @@ __cpp_lib_incomplete_container_elements 201505L <forward_list> < __cpp_lib_inplace_vector 202406L <inplace_vector> __cpp_lib_int_pow2 202002L <bit> __cpp_lib_integer_comparison_functions 202002L <utility> -__cpp_lib_integer_sequence 201304L <utility> +__cpp_lib_integer_sequence 202511L <utility> + 201304L // C++14 __cpp_lib_integral_constant_callable 201304L <type_traits> __cpp_lib_interpolate 201902L <cmath> <numeric> __cpp_lib_invoke 201411L <functional> @@ -184,7 +188,8 @@ __cpp_lib_nonmember_container_access 201411L <array> <deque> __cpp_lib_not_fn 202306L <functional> 201603L // C++17 __cpp_lib_null_iterators 201304L <iterator> -__cpp_lib_optional 202110L <optional> +__cpp_lib_optional 202506L <optional> + 202110L // C++23 202106L // C++20 201606L // C++17 __cpp_lib_optional_range_support 202406L <optional> @@ -205,6 +210,7 @@ __cpp_lib_ranges_chunk_by 202202L <ranges> __cpp_lib_ranges_concat 202403L <ranges> __cpp_lib_ranges_contains 202207L <algorithm> __cpp_lib_ranges_find_last 202207L <algorithm> +__cpp_lib_ranges_indices 202506L <ranges> __cpp_lib_ranges_iota 202202L <numeric> __cpp_lib_ranges_join_with 202202L <ranges> __cpp_lib_ranges_repeat 202207L <ranges> @@ -245,6 +251,7 @@ __cpp_lib_starts_ends_with 201711L <string> <string __cpp_lib_stdatomic_h 202011L <stdatomic.h> __cpp_lib_string_contains 202011L <string> <string_view> __cpp_lib_string_resize_and_overwrite 202110L <string> +__cpp_lib_string_subview 202506L <string> <string_view> __cpp_lib_string_udls 201304L <string> __cpp_lib_string_view 202403L <string> <string_view> 201803L // C++20 @@ -333,13 +340,11 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_clamp 201603L # define __cpp_lib_enable_shared_from_this 201603L // # define __cpp_lib_execution 201603L -# if _LIBCPP_HAS_FILESYSTEM && _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_LIBRARY +# if _LIBCPP_HAS_FILESYSTEM # define __cpp_lib_filesystem 201703L # endif # define __cpp_lib_gcd_lcm 201606L -# if defined(__GCC_DESTRUCTIVE_SIZE) && defined(__GCC_CONSTRUCTIVE_SIZE) -# define __cpp_lib_hardware_interference_size 201703L -# endif +# define __cpp_lib_hardware_interference_size 201703L # define __cpp_lib_has_unique_object_representations 201606L # define __cpp_lib_hypot 201603L # define __cpp_lib_incomplete_container_elements 201505L @@ -391,10 +396,8 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_atomic_ref 201806L // # define __cpp_lib_atomic_shared_ptr 201711L # define __cpp_lib_atomic_value_initialization 201911L -# if _LIBCPP_AVAILABILITY_HAS_SYNC -# define __cpp_lib_atomic_wait 201907L -# endif -# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC +# define __cpp_lib_atomic_wait 201907L +# if _LIBCPP_HAS_THREADS # define __cpp_lib_barrier 201907L # endif # define __cpp_lib_bind_front 201907L @@ -406,7 +409,7 @@ __cpp_lib_void_t 201411L <type_traits> # endif # define __cpp_lib_common_reference 202302L # define __cpp_lib_common_reference_wrapper 202302L -# define __cpp_lib_concepts 202002L +# define __cpp_lib_concepts 202207L # define __cpp_lib_constexpr_algorithms 201806L # define __cpp_lib_constexpr_complex 201711L # define __cpp_lib_constexpr_dynamic_alloc 201907L @@ -439,10 +442,10 @@ __cpp_lib_void_t 201411L <type_traits> // # define __cpp_lib_is_layout_compatible 201907L # define __cpp_lib_is_nothrow_convertible 201806L // # define __cpp_lib_is_pointer_interconvertible 201907L -# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC +# if _LIBCPP_HAS_THREADS # define __cpp_lib_jthread 201911L # endif -# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC +# if _LIBCPP_HAS_THREADS # define __cpp_lib_latch 201907L # endif # define __cpp_lib_list_remove_return_type 201806L @@ -455,7 +458,7 @@ __cpp_lib_void_t 201411L <type_traits> # endif # define __cpp_lib_ranges 202110L # define __cpp_lib_remove_cvref 201711L -# if _LIBCPP_HAS_THREADS && _LIBCPP_AVAILABILITY_HAS_SYNC +# if _LIBCPP_HAS_THREADS # define __cpp_lib_semaphore 201907L # endif # undef __cpp_lib_shared_ptr_arrays @@ -494,8 +497,8 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_constexpr_typeinfo 202106L # define __cpp_lib_containers_ranges 202202L # define __cpp_lib_expected 202211L -# define __cpp_lib_flat_map 202207L -# define __cpp_lib_flat_set 202207L +# define __cpp_lib_flat_map 202511L +# define __cpp_lib_flat_set 202511L # define __cpp_lib_format_ranges 202207L // # define __cpp_lib_formatters 202302L # define __cpp_lib_forward_like 202207L @@ -528,7 +531,7 @@ __cpp_lib_void_t 201411L <type_traits> // # define __cpp_lib_ranges_slide 202202L # define __cpp_lib_ranges_starts_ends_with 202106L # define __cpp_lib_ranges_to_container 202202L -// # define __cpp_lib_ranges_zip 202110L +# define __cpp_lib_ranges_zip 202110L // # define __cpp_lib_reference_from_temporary 202202L // # define __cpp_lib_spanstream 202106L // # define __cpp_lib_stacktrace 202011L @@ -544,18 +547,22 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_aligned_accessor 202411L // # define __cpp_lib_associative_heterogeneous_insertion 202306L // # define __cpp_lib_atomic_min_max 202403L +# undef __cpp_lib_atomic_ref +# define __cpp_lib_atomic_ref 202411L # undef __cpp_lib_bind_front # define __cpp_lib_bind_front 202306L # define __cpp_lib_bitset 202306L # undef __cpp_lib_constexpr_algorithms # define __cpp_lib_constexpr_algorithms 202306L +# define __cpp_lib_constexpr_flat_map 202502L +# define __cpp_lib_constexpr_flat_set 202502L # define __cpp_lib_constexpr_forward_list 202502L # define __cpp_lib_constexpr_list 202502L # if !defined(_LIBCPP_ABI_VCRUNTIME) # define __cpp_lib_constexpr_new 202406L # endif # define __cpp_lib_constexpr_queue 202502L -// # define __cpp_lib_constrained_equality 202411L +# define __cpp_lib_constrained_equality 202411L // # define __cpp_lib_copyable_function 202306L // # define __cpp_lib_debugging 202311L // # define __cpp_lib_default_template_type_for_algorithm_values 202403L @@ -575,21 +582,30 @@ __cpp_lib_void_t 201411L <type_traits> // # define __cpp_lib_generate_random 202403L // # define __cpp_lib_hazard_pointer 202306L // # define __cpp_lib_inplace_vector 202406L +# undef __cpp_lib_integer_sequence +# define __cpp_lib_integer_sequence 202511L # define __cpp_lib_is_sufficiently_aligned 202411L # if __has_builtin(__builtin_is_virtual_base_of) # define __cpp_lib_is_virtual_base_of 202406L # endif -// # define __cpp_lib_is_within_lifetime 202306L +# if __has_builtin(__builtin_is_within_lifetime) +# define __cpp_lib_is_within_lifetime 202306L +# endif // # define __cpp_lib_linalg 202311L # undef __cpp_lib_mdspan # define __cpp_lib_mdspan 202406L # undef __cpp_lib_not_fn # define __cpp_lib_not_fn 202306L -// # define __cpp_lib_optional_range_support 202406L +# undef __cpp_lib_optional +# define __cpp_lib_optional 202506L +# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR +# define __cpp_lib_optional_range_support 202406L +# endif # undef __cpp_lib_out_ptr # define __cpp_lib_out_ptr 202311L // # define __cpp_lib_philox_engine 202406L // # define __cpp_lib_ranges_concat 202403L +# define __cpp_lib_ranges_indices 202506L # define __cpp_lib_ratio 202306L // # define __cpp_lib_rcu 202306L # define __cpp_lib_reference_wrapper 202403L @@ -599,6 +615,7 @@ __cpp_lib_void_t 201411L <type_traits> # define __cpp_lib_span_at 202311L # define __cpp_lib_span_initializer_list 202311L # define __cpp_lib_sstream_from_string_view 202306L +# define __cpp_lib_string_subview 202506L # undef __cpp_lib_string_view # define __cpp_lib_string_view 202403L // # define __cpp_lib_submdspan 202306L diff --git a/lib/libcxx/include/wctype.h b/lib/libcxx/include/wctype.h @@ -45,13 +45,14 @@ wctrans_t wctrans(const char* property); */ #if defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) -# include <__cxx03/wctype.h> +# include <__cxx03/__config> #else # include <__config> +#endif -# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# pragma GCC system_header -# endif +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif // TODO: // In the future, we should unconditionally include_next <wctype.h> here and instead @@ -62,33 +63,32 @@ wctrans_t wctrans(const char* property); // nothing (with using_if_exists), and if we include another header that defines one // of these declarations (e.g. <wchar.h>), the second `using ::wint_t` with using_if_exists // will fail because it does not refer to the same declaration. -# if __has_include_next(<wctype.h>) -# include_next <wctype.h> -# define _LIBCPP_INCLUDED_C_LIBRARY_WCTYPE_H -# endif +#if __has_include_next(<wctype.h>) +# include_next <wctype.h> +# define _LIBCPP_INCLUDED_C_LIBRARY_WCTYPE_H +#endif -# ifdef __cplusplus +#ifdef __cplusplus -# undef iswalnum -# undef iswalpha -# undef iswblank -# undef iswcntrl -# undef iswdigit -# undef iswgraph -# undef iswlower -# undef iswprint -# undef iswpunct -# undef iswspace -# undef iswupper -# undef iswxdigit -# undef iswctype -# undef wctype -# undef towlower -# undef towupper -# undef towctrans -# undef wctrans +# undef iswalnum +# undef iswalpha +# undef iswblank +# undef iswcntrl +# undef iswdigit +# undef iswgraph +# undef iswlower +# undef iswprint +# undef iswpunct +# undef iswspace +# undef iswupper +# undef iswxdigit +# undef iswctype +# undef wctype +# undef towlower +# undef towupper +# undef towctrans +# undef wctrans -# endif // __cplusplus -#endif // defined(__cplusplus) && __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS) +#endif // __cplusplus #endif // _LIBCPP_WCTYPE_H diff --git a/lib/libcxx/src/any.cpp b/lib/libcxx/src/any.cpp @@ -14,6 +14,8 @@ const char* bad_any_cast::what() const noexcept { return "bad any cast"; } #include <__config> +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7 + // Preserve std::experimental::any_bad_cast for ABI compatibility // Even though it no longer exists in a header file _LIBCPP_BEGIN_NAMESPACE_LFTS @@ -25,4 +27,6 @@ public: const char* bad_any_cast::what() const noexcept { return "bad any cast"; } +#endif + _LIBCPP_END_NAMESPACE_LFTS diff --git a/lib/libcxx/src/atomic.cpp b/lib/libcxx/src/atomic.cpp @@ -9,8 +9,13 @@ #include <__thread/timed_backoff_policy.h> #include <atomic> #include <climits> +#include <cstddef> +#include <cstdint> +#include <cstring> #include <functional> +#include <new> #include <thread> +#include <type_traits> #include "include/apple_availability.h" @@ -41,6 +46,11 @@ // OpenBSD has no indirect syscalls # define _LIBCPP_FUTEX(...) futex(__VA_ARGS__) +#elif defined(_WIN32) + +# include <memory> +# include <windows.h> + #else // <- Add other operating systems here // Baseline needs no new headers @@ -49,17 +59,34 @@ #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD +struct NoTimeout {}; + #ifdef __linux__ -static void -__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) { - static constexpr timespec __timeout = {2, 0}; - _LIBCPP_FUTEX(__ptr, FUTEX_WAIT_PRIVATE, __val, &__timeout, 0, 0); +template <std::size_t _Size, class MaybeTimeout> +static void __platform_wait_on_address(void const* __ptr, void const* __val, MaybeTimeout maybe_timeout_ns) { + static_assert(_Size == 4, "Can only wait on 4 bytes value"); + alignas(__cxx_contention_t) char buffer[_Size]; + std::memcpy(&buffer, const_cast<const void*>(__val), _Size); + static constexpr timespec __default_timeout = {2, 0}; + timespec __timeout; + if constexpr (is_same_v<MaybeTimeout, NoTimeout>) { + __timeout = __default_timeout; + } else { + __timeout.tv_sec = maybe_timeout_ns / 1'000'000'000; + __timeout.tv_nsec = maybe_timeout_ns % 1'000'000'000; + } + _LIBCPP_FUTEX(__ptr, FUTEX_WAIT_PRIVATE, *reinterpret_cast<__cxx_contention_t const*>(&buffer), &__timeout, 0, 0); } -static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) { +template <std::size_t _Size> +static void __platform_wake_by_address(void const* __ptr, bool __notify_one) { + static_assert(_Size == 4, "Can only wake up on 4 bytes value"); _LIBCPP_FUTEX(__ptr, FUTEX_WAKE_PRIVATE, __notify_one ? 1 : INT_MAX, 0, 0, 0); } @@ -70,19 +97,41 @@ extern "C" int __ulock_wait( extern "C" int __ulock_wake(uint32_t operation, void* addr, uint64_t wake_value); // https://github.com/apple/darwin-xnu/blob/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/sys/ulock.h#L82 +# define UL_COMPARE_AND_WAIT 1 # define UL_COMPARE_AND_WAIT64 5 # define ULF_WAKE_ALL 0x00000100 -static void -__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) { - static_assert(sizeof(__cxx_atomic_contention_t) == 8, "Waiting on 8 bytes value"); - __ulock_wait(UL_COMPARE_AND_WAIT64, const_cast<__cxx_atomic_contention_t*>(__ptr), __val, 0); +template <std::size_t _Size, class MaybeTimeout> +static void __platform_wait_on_address(void const* __ptr, void const* __val, MaybeTimeout maybe_timeout_ns) { + static_assert(_Size == 8 || _Size == 4, "Can only wait on 8 bytes or 4 bytes value"); + auto __timeout_us = [&] { + if constexpr (is_same_v<MaybeTimeout, NoTimeout>) { + return uint32_t(0); + } else { + return std::max(static_cast<uint32_t>(maybe_timeout_ns / 1000), uint32_t(1)); + } + }(); + if constexpr (_Size == 4) { + alignas(uint32_t) char buffer[_Size]; + std::memcpy(&buffer, const_cast<const void*>(__val), _Size); + __ulock_wait( + UL_COMPARE_AND_WAIT, const_cast<void*>(__ptr), *reinterpret_cast<uint32_t const*>(&buffer), __timeout_us); + } else { + alignas(uint64_t) char buffer[_Size]; + std::memcpy(&buffer, const_cast<const void*>(__val), _Size); + __ulock_wait( + UL_COMPARE_AND_WAIT64, const_cast<void*>(__ptr), *reinterpret_cast<uint64_t const*>(&buffer), __timeout_us); + } } -static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) { - static_assert(sizeof(__cxx_atomic_contention_t) == 8, "Waking up on 8 bytes value"); - __ulock_wake( - UL_COMPARE_AND_WAIT64 | (__notify_one ? 0 : ULF_WAKE_ALL), const_cast<__cxx_atomic_contention_t*>(__ptr), 0); +template <std::size_t _Size> +static void __platform_wake_by_address(void const* __ptr, bool __notify_one) { + static_assert(_Size == 8 || _Size == 4, "Can only wake up on 8 bytes or 4 bytes value"); + + if constexpr (_Size == 4) + __ulock_wake(UL_COMPARE_AND_WAIT | (__notify_one ? 0 : ULF_WAKE_ALL), const_cast<void*>(__ptr), 0); + else + __ulock_wake(UL_COMPARE_AND_WAIT64 | (__notify_one ? 0 : ULF_WAKE_ALL), const_cast<void*>(__ptr), 0); } #elif defined(__FreeBSD__) && __SIZEOF_LONG__ == 8 @@ -92,119 +141,355 @@ static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const vo * limit its use to architectures where long and int64_t are synonyms. */ -static void -__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) { - _umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAIT, __val, nullptr, nullptr); +template <std::size_t _Size, class MaybeTimeout> +static void __platform_wait_on_address(void const* __ptr, void const* __val, MaybeTimeout maybe_timeout_ns) { + static_assert(_Size == 8, "Can only wait on 8 bytes value"); + // At the moment, FreeBSD is stuck on stable ABI, which only supports platform wait with __cxx_contention_t + // It is safe to reinterpret_cast the val as it is ever going to be passed a __cxx_contention_t under this ABI + // If in the future FreeBSD decides to experiment unstable ABI to support more types, this cast will no longer be + // safe. + __cxx_contention_t value = *reinterpret_cast<const __cxx_contention_t*>(__val); + if constexpr (is_same_v<MaybeTimeout, NoTimeout>) { + _umtx_op(const_cast<void*>(__ptr), UMTX_OP_WAIT, value, nullptr, nullptr); + } else { + timespec timeout{}; + timeout.tv_sec = maybe_timeout_ns / 1'000'000'000; + timeout.tv_nsec = maybe_timeout_ns % 1'000'000'000; + + _umtx_op(const_cast<void*>(__ptr), + UMTX_OP_WAIT, + value, + reinterpret_cast<void*>(static_cast<uintptr_t>(sizeof(timeout))), + &timeout); + } +} + +template <std::size_t _Size> +static void __platform_wake_by_address(void const* __ptr, bool __notify_one) { + static_assert(_Size == 8, "Can only wake up on 8 bytes value"); + _umtx_op(const_cast<void*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, nullptr, nullptr); +} + +#elif defined(_WIN32) + +static void* win32_get_synch_api_function(const char* function_name) { + // Attempt to load the API set. Note that as per the Microsoft STL implementation, we assume this API is already + // loaded and accessible. While this isn't explicitly guaranteed by publicly available Win32 API documentation, it is + // true in practice, and may be guaranteed by internal documentation not released publicly. In any case the fact that + // the Microsoft STL made this assumption is reasonable basis to say that we can too. The alternative to this would be + // to use LoadLibrary, but then leak the module handle. We can't call FreeLibrary, as this would have to be triggered + // by a global static destructor, which would hang off DllMain, and calling FreeLibrary from DllMain is explicitly + // mentioned as not being allowed: + // https://learn.microsoft.com/en-us/windows/win32/dlls/dllmain + // Given the range of bad options here, we have chosen to mirror what Microsoft did, as it seems fair to assume that + // Microsoft will guarantee compatibility for us, as we are exposed to the same conditions as all existing Windows + // apps using the Microsoft STL VS2015/2017/2019/2022 runtimes, where Windows 7 support has not been excluded at + // compile time. + static auto module_handle = GetModuleHandleW(L"api-ms-win-core-synch-l1-2-0.dll"); + if (module_handle == nullptr) { + return nullptr; + } + + // Attempt to locate the function in the API and return the result to the caller. Note that the NULL return from this + // method is documented as being interchangeable with nullptr. + // https://devblogs.microsoft.com/oldnewthing/20180307-00/?p=98175 + return reinterpret_cast<void*>(GetProcAddress(module_handle, function_name)); } -static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile* __ptr, bool __notify_one) { - _umtx_op(const_cast<__cxx_atomic_contention_t*>(__ptr), UMTX_OP_WAKE, __notify_one ? 1 : INT_MAX, nullptr, nullptr); +template <std::size_t _Size, class MaybeTimeout> +static void __platform_wait_on_address(void const* __ptr, void const* __val, MaybeTimeout maybe_timeout_ns) { + static_assert(_Size == 8, "Can only wait on 8 bytes value"); + // WaitOnAddress was added in Windows 8 (build 9200) + static auto wait_on_address = + reinterpret_cast<BOOL(WINAPI*)(void*, PVOID, SIZE_T, DWORD)>(win32_get_synch_api_function("WaitOnAddress")); + if (wait_on_address != nullptr) { + auto timeout_ms = [&]() -> DWORD { + if constexpr (is_same_v<MaybeTimeout, NoTimeout>) { + return INFINITE; + } else { + uint64_t ms = maybe_timeout_ns / 1'000'000; + if (ms == 0 && maybe_timeout_ns > 100'000) + // Round up to 1ms if requested between 100us - 1ms + return 1; + + return static_cast<DWORD>(std::min(static_cast<uint64_t>(INFINITE), ms)); + } + }(); + wait_on_address(const_cast<void*>(__ptr), const_cast<void*>(__val), _Size, timeout_ms); + } else { + std::chrono::nanoseconds timeout = std::chrono::nanoseconds(0); + if constexpr (!is_same_v<MaybeTimeout, NoTimeout>) { + timeout = std::chrono::nanoseconds(maybe_timeout_ns); + } + __libcpp_thread_poll_with_backoff( + [=]() -> bool { return std::memcmp(const_cast<const void*>(__ptr), __val, _Size) != 0; }, + __libcpp_timed_backoff_policy(), + timeout); + } +} + +template <std::size_t _Size> +static void __platform_wake_by_address(void const* __ptr, bool __notify_one) { + static_assert(_Size == 8, "Can only wake up on 8 bytes value"); + if (__notify_one) { + // WakeByAddressSingle was added in Windows 8 (build 9200) + static auto wake_by_address_single = + reinterpret_cast<void(WINAPI*)(PVOID)>(win32_get_synch_api_function("WakeByAddressSingle")); + if (wake_by_address_single != nullptr) { + wake_by_address_single(const_cast<void*>(__ptr)); + } else { + // The fallback implementation of waking does nothing, as the fallback wait implementation just does polling, so + // there's nothing to do here. + } + } else { + // WakeByAddressAll was added in Windows 8 (build 9200) + static auto wake_by_address_all = + reinterpret_cast<void(WINAPI*)(PVOID)>(win32_get_synch_api_function("WakeByAddressAll")); + if (wake_by_address_all != nullptr) { + wake_by_address_all(const_cast<void*>(__ptr)); + } else { + // The fallback implementation of waking does nothing, as the fallback wait implementation just does polling, so + // there's nothing to do here. + } + } } #else // <- Add other operating systems here // Baseline is just a timed backoff -static void -__libcpp_platform_wait_on_address(__cxx_atomic_contention_t const volatile* __ptr, __cxx_contention_t __val) { +template <std::size_t _Size, class MaybeTimeout> +static void __platform_wait_on_address(void const* __ptr, void const* __val, MaybeTimeout maybe_timeout_ns) { + std::chrono::nanoseconds timeout = std::chrono::nanoseconds(0); + if constexpr (!is_same_v<MaybeTimeout, NoTimeout>) { + timeout = std::chrono::nanoseconds(maybe_timeout_ns); + } __libcpp_thread_poll_with_backoff( - [=]() -> bool { return !__cxx_nonatomic_compare_equal(__cxx_atomic_load(__ptr, memory_order_relaxed), __val); }, - __libcpp_timed_backoff_policy()); + [=]() -> bool { return std::memcmp(const_cast<const void*>(__ptr), __val, _Size) != 0; }, + __libcpp_timed_backoff_policy(), + timeout); } -static void __libcpp_platform_wake_by_address(__cxx_atomic_contention_t const volatile*, bool) {} +template <std::size_t _Size> +static void __platform_wake_by_address(void const*, bool) {} #endif // __linux__ -static constexpr size_t __libcpp_contention_table_size = (1 << 8); /* < there's no magic in this number */ - -struct alignas(64) /* aim to avoid false sharing */ __libcpp_contention_table_entry { - __cxx_atomic_contention_t __contention_state; - __cxx_atomic_contention_t __platform_state; - inline constexpr __libcpp_contention_table_entry() : __contention_state(0), __platform_state(0) {} -}; - -static __libcpp_contention_table_entry __libcpp_contention_table[__libcpp_contention_table_size]; - -static hash<void const volatile*> __libcpp_contention_hasher; - -static __libcpp_contention_table_entry* __libcpp_contention_state(void const volatile* p) { - return &__libcpp_contention_table[__libcpp_contention_hasher(p) & (__libcpp_contention_table_size - 1)]; -} +// ============================= +// Local hidden helper functions +// ============================= /* Given an atomic to track contention and an atomic to actually wait on, which may be the same atomic, we try to detect contention to avoid spuriously calling the platform. */ -static void __libcpp_contention_notify(__cxx_atomic_contention_t volatile* __contention_state, - __cxx_atomic_contention_t const volatile* __platform_state, - bool __notify_one) { - if (0 != __cxx_atomic_load(__contention_state, memory_order_seq_cst)) +template <std::size_t _Size> +static void +__contention_notify(__cxx_atomic_contention_t* __waiter_count, void const* __address_to_notify, bool __notify_one) { + if (0 != __cxx_atomic_load(__waiter_count, memory_order_seq_cst)) // We only call 'wake' if we consumed a contention bit here. - __libcpp_platform_wake_by_address(__platform_state, __notify_one); -} -static __cxx_contention_t -__libcpp_contention_monitor_for_wait(__cxx_atomic_contention_t volatile* /*__contention_state*/, - __cxx_atomic_contention_t const volatile* __platform_state) { - // We will monitor this value. - return __cxx_atomic_load(__platform_state, memory_order_acquire); -} -static void __libcpp_contention_wait(__cxx_atomic_contention_t volatile* __contention_state, - __cxx_atomic_contention_t const volatile* __platform_state, - __cxx_contention_t __old_value) { - __cxx_atomic_fetch_add(__contention_state, __cxx_contention_t(1), memory_order_relaxed); - // https://github.com/llvm/llvm-project/issues/109290 + __platform_wake_by_address<_Size>(__address_to_notify, __notify_one); +} + +template <std::size_t _Size, class MaybeTimeout> +static void __contention_wait(__cxx_atomic_contention_t* __waiter_count, + void const* __address_to_wait, + void const* __old_value, + MaybeTimeout maybe_timeout_ns) { + __cxx_atomic_fetch_add(__waiter_count, __cxx_contention_t(1), memory_order_relaxed); + // https://llvm.org/PR109290 // There are no platform guarantees of a memory barrier in the platform wait implementation __cxx_atomic_thread_fence(memory_order_seq_cst); // We sleep as long as the monitored value hasn't changed. - __libcpp_platform_wait_on_address(__platform_state, __old_value); - __cxx_atomic_fetch_sub(__contention_state, __cxx_contention_t(1), memory_order_release); + __platform_wait_on_address<_Size>(__address_to_wait, __old_value, maybe_timeout_ns); + __cxx_atomic_fetch_sub(__waiter_count, __cxx_contention_t(1), memory_order_release); +} + +static constexpr size_t __contention_table_size = (1 << 8); /* < there's no magic in this number */ + +static constexpr hash<void const*> __contention_hasher; + +// Waiter count table for all atomics with the correct size that use itself as the wait/notify address. + +struct alignas( + std::hardware_constructive_interference_size) /* aim to avoid false sharing */ __contention_state_native { + __cxx_atomic_contention_t __waiter_count; + constexpr __contention_state_native() : __waiter_count(0) {} +}; + +static __contention_state_native __contention_table_native[__contention_table_size]; + +static __cxx_atomic_contention_t* __get_native_waiter_count(void const* p) { + return &__contention_table_native[__contention_hasher(p) & (__contention_table_size - 1)].__waiter_count; +} + +// Global contention table for all atomics with the wrong size that use the global table's atomic as wait/notify +// address. + +struct alignas( + std::hardware_constructive_interference_size) /* aim to avoid false sharing */ __contention_state_global { + __cxx_atomic_contention_t __waiter_count; + __cxx_atomic_contention_t __platform_state; + constexpr __contention_state_global() : __waiter_count(0), __platform_state(0) {} +}; + +static __contention_state_global __contention_table_global[__contention_table_size]; + +static __contention_state_global* __get_global_contention_state(void const* p) { + return &__contention_table_global[__contention_hasher(p) & (__contention_table_size - 1)]; } /* When the incoming atomic is the wrong size for the platform wait size, need to launder the value sequence through an atomic from our table. */ -static void __libcpp_atomic_notify(void const volatile* __location) { - auto const __entry = __libcpp_contention_state(__location); +static void __atomic_notify_global_table(void const* __location) { + auto const __entry = __get_global_contention_state(__location); // The value sequence laundering happens on the next line below. __cxx_atomic_fetch_add(&__entry->__platform_state, __cxx_contention_t(1), memory_order_seq_cst); - __libcpp_contention_notify( - &__entry->__contention_state, - &__entry->__platform_state, - false /* when laundering, we can't handle notify_one */); + __contention_notify<sizeof(__cxx_atomic_contention_t)>( + &__entry->__waiter_count, &__entry->__platform_state, false /* when laundering, we can't handle notify_one */); +} + +// ============================= +// New dylib exported symbols +// ============================= + +// global +_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __atomic_monitor_global(void const* __location) noexcept { + auto const __entry = __get_global_contention_state(__location); + return __cxx_atomic_load(&__entry->__platform_state, memory_order_acquire); +} + +_LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_global_table(void const* __location, __cxx_contention_t __old_value) noexcept { + auto const __entry = __get_global_contention_state(__location); + __contention_wait<sizeof(__cxx_atomic_contention_t)>( + &__entry->__waiter_count, &__entry->__platform_state, &__old_value, NoTimeout{}); +} + +_LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_global_table_with_timeout( + void const* __location, __cxx_contention_t __old_value, uint64_t __timeout_ns) _NOEXCEPT { + auto const __entry = __get_global_contention_state(__location); + __contention_wait<sizeof(__cxx_atomic_contention_t)>( + &__entry->__waiter_count, &__entry->__platform_state, &__old_value, __timeout_ns); +} + +_LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_global_table(void const* __location) noexcept { + __atomic_notify_global_table(__location); +} + +_LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_global_table(void const* __location) noexcept { + __atomic_notify_global_table(__location); +} + +// native + +template <std::size_t _Size> +_LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_native(void const* __address, void const* __old_value) noexcept { + __contention_wait<_Size>(__get_native_waiter_count(__address), __address, __old_value, NoTimeout{}); } + +template <std::size_t _Size> +_LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_native_with_timeout(void const* __address, void const* __old_value, uint64_t __timeout_ns) noexcept { + __contention_wait<_Size>(__get_native_waiter_count(__address), __address, __old_value, __timeout_ns); +} + +template <std::size_t _Size> +_LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native(void const* __location) noexcept { + __contention_notify<_Size>(__get_native_waiter_count(__location), __location, true); +} + +template <std::size_t _Size> +_LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native(void const* __location) noexcept { + __contention_notify<_Size>(__get_native_waiter_count(__location), __location, false); +} + +// ================================================== +// Instantiation of the templates with supported size +// ================================================== + +#if defined(_LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE) + +# define _INSTANTIATE(_SIZE) \ + template _LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_native<_SIZE>(void const*, void const*) noexcept; \ + template _LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_native_with_timeout<_SIZE>( \ + void const*, void const*, uint64_t) noexcept; \ + template _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_one_native<_SIZE>(void const*) noexcept; \ + template _LIBCPP_EXPORTED_FROM_ABI void __atomic_notify_all_native<_SIZE>(void const*) noexcept; + +_LIBCPP_NATIVE_PLATFORM_WAIT_SIZES(_INSTANTIATE) + +# undef _INSTANTIATE + +#else // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE + +template _LIBCPP_EXPORTED_FROM_ABI void +__atomic_wait_native<sizeof(__cxx_contention_t)>(void const* __address, void const* __old_value) noexcept; + +template _LIBCPP_EXPORTED_FROM_ABI void __atomic_wait_native_with_timeout<sizeof(__cxx_contention_t)>( + void const* __address, void const* __old_value, uint64_t) noexcept; + +template _LIBCPP_EXPORTED_FROM_ABI void +__atomic_notify_one_native<sizeof(__cxx_contention_t)>(void const* __location) noexcept; + +template _LIBCPP_EXPORTED_FROM_ABI void +__atomic_notify_all_native<sizeof(__cxx_contention_t)>(void const* __location) noexcept; + +#endif // _LIBCPP_ABI_ATOMIC_WAIT_NATIVE_BY_SIZE + +// ============================================================= +// Old dylib exported symbols, for backwards compatibility +// ============================================================= +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") + _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(void const volatile* __location) noexcept { - __libcpp_atomic_notify(__location); + __atomic_notify_global_table(const_cast<void const*>(__location)); } + _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(void const volatile* __location) noexcept { - __libcpp_atomic_notify(__location); + __atomic_notify_global_table(const_cast<void const*>(__location)); } + _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(void const volatile* __location) noexcept { - auto const __entry = __libcpp_contention_state(__location); - return __libcpp_contention_monitor_for_wait(&__entry->__contention_state, &__entry->__platform_state); + auto const __entry = __get_global_contention_state(const_cast<void const*>(__location)); + return __cxx_atomic_load(&__entry->__platform_state, memory_order_acquire); } + _LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(void const volatile* __location, __cxx_contention_t __old_value) noexcept { - auto const __entry = __libcpp_contention_state(__location); - __libcpp_contention_wait(&__entry->__contention_state, &__entry->__platform_state, __old_value); + auto const __entry = __get_global_contention_state(const_cast<void const*>(__location)); + __contention_wait<sizeof(__cxx_atomic_contention_t)>( + &__entry->__waiter_count, &__entry->__platform_state, &__old_value, NoTimeout{}); } -/* When the incoming atomic happens to be the platform wait size, we still need to use the - table for the contention detection, but we can use the atomic directly for the wait. */ - _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t const volatile* __location) noexcept { - __libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, true); + auto __location_cast = const_cast<const void*>(static_cast<const volatile void*>(__location)); + __contention_notify<sizeof(__cxx_atomic_contention_t)>( + __get_native_waiter_count(__location_cast), __location_cast, true); } + _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile* __location) noexcept { - __libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, false); -} -// This function is never used, but still exported for ABI compatibility. -_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t -__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile* __location) noexcept { - return __libcpp_contention_monitor_for_wait(&__libcpp_contention_state(__location)->__contention_state, __location); + auto __location_cast = const_cast<const void*>(static_cast<const volatile void*>(__location)); + __contention_notify<sizeof(__cxx_atomic_contention_t)>( + __get_native_waiter_count(__location_cast), __location_cast, false); } + _LIBCPP_EXPORTED_FROM_ABI void __libcpp_atomic_wait(__cxx_atomic_contention_t const volatile* __location, __cxx_contention_t __old_value) noexcept { - __libcpp_contention_wait(&__libcpp_contention_state(__location)->__contention_state, __location, __old_value); + auto __location_cast = const_cast<const void*>(static_cast<const volatile void*>(__location)); + __contention_wait<sizeof(__cxx_atomic_contention_t)>( + __get_native_waiter_count(__location_cast), __location_cast, &__old_value, NoTimeout{}); } +// this function is even unused in the old ABI +_LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t +__libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile* __location) noexcept { + return __cxx_atomic_load(__location, memory_order_acquire); +} + +_LIBCPP_DIAGNOSTIC_POP + _LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS diff --git a/lib/libcxx/src/barrier.cpp b/lib/libcxx/src/barrier.cpp @@ -60,11 +60,12 @@ public: _LIBCPP_EXPORTED_FROM_ABI __barrier_algorithm_base* __construct_barrier_algorithm_base(ptrdiff_t& __expected) { return new __barrier_algorithm_base(__expected); } -_LIBCPP_EXPORTED_FROM_ABI bool -__arrive_barrier_algorithm_base(__barrier_algorithm_base* __barrier, __barrier_phase_t __old_phase) noexcept { +_LIBCPP_EXPORTED_FROM_ABI bool __arrive_barrier_algorithm_base( + _LIBCPP_NOESCAPE __barrier_algorithm_base* __barrier, __barrier_phase_t __old_phase) noexcept { return __barrier->__arrive(__old_phase); } -_LIBCPP_EXPORTED_FROM_ABI void __destroy_barrier_algorithm_base(__barrier_algorithm_base* __barrier) noexcept { +_LIBCPP_EXPORTED_FROM_ABI void +__destroy_barrier_algorithm_base(_LIBCPP_NOESCAPE __barrier_algorithm_base* __barrier) noexcept { delete __barrier; } diff --git a/lib/libcxx/src/charconv.cpp b/lib/libcxx/src/charconv.cpp @@ -14,17 +14,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15 namespace __itoa { +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") +// These functions exist for ABI compatibility, so we don't ever want a declaration prior to the definition. _LIBCPP_EXPORTED_FROM_ABI char* __u32toa(uint32_t value, char* buffer) noexcept { return __base_10_u32(buffer, value); } - _LIBCPP_EXPORTED_FROM_ABI char* __u64toa(uint64_t value, char* buffer) noexcept { return __base_10_u64(buffer, value); } +_LIBCPP_DIAGNOSTIC_POP } // namespace __itoa -#endif // _LIBCPP_ABI_DO_NOT_EXPORT_TO_CHARS_BASE_10 +#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15 // The original version of floating-point to_chars was written by Microsoft and // contributed with the following license. diff --git a/lib/libcxx/src/condition_variable_destructor.cpp b/lib/libcxx/src/condition_variable_destructor.cpp @@ -14,7 +14,7 @@ #include <__config> #include <__thread/support.h> -#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION # define NEEDS_CONDVAR_DESTRUCTOR #endif diff --git a/lib/libcxx/src/error_category.cpp b/lib/libcxx/src/error_category.cpp @@ -8,7 +8,9 @@ #include <__config> -#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS +// This has technically been removed in LLVM 3.4 +#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) && \ + _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 4 # define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS #endif diff --git a/lib/libcxx/src/exception.cpp b/lib/libcxx/src/exception.cpp @@ -9,20 +9,12 @@ #define _LIBCPP_ENABLE_CXX20_REMOVED_UNCAUGHT_EXCEPTION #define _LIBCPP_DISABLE_DEPRECATION_WARNINGS -#include <exception> -#include <new> -#include <typeinfo> - -#if defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI) -# include <cxxabi.h> -using namespace __cxxabiv1; -# define HAVE_DEPENDENT_EH_ABI 1 -#endif +#include <__config> #if defined(_LIBCPP_ABI_MICROSOFT) # include "support/runtime/exception_msvc.ipp" # include "support/runtime/exception_pointer_msvc.ipp" -#elif defined(_LIBCPPABI_VERSION) +#elif defined(LIBCXX_BUILDING_LIBCXXABI) # include "support/runtime/exception_libcxxabi.ipp" # include "support/runtime/exception_pointer_cxxabi.ipp" #elif defined(LIBCXXRT) diff --git a/lib/libcxx/src/experimental/time_zone.cpp b/lib/libcxx/src/experimental/time_zone.cpp @@ -720,7 +720,7 @@ __get_sys_info(sys_seconds __time, // Iff the "offsets" are the same '__current.__end' is replaced with // '__next.__end', which effectively merges the two objects in one object. The // function returns true if a merge occurred. -[[nodiscard]] bool __merge_continuation(sys_info& __current, const sys_info& __next) { +[[nodiscard]] static bool __merge_continuation(sys_info& __current, const sys_info& __next) { if (__current.end != __next.begin) return false; diff --git a/lib/libcxx/src/experimental/tzdb.cpp b/lib/libcxx/src/experimental/tzdb.cpp @@ -49,6 +49,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // This function is weak so it can be overriden in the tests. The // declaration is in the test header test/support/test_tzdb.h _LIBCPP_WEAK string_view __libcpp_tzdb_directory() { @@ -59,6 +61,7 @@ _LIBCPP_WEAK string_view __libcpp_tzdb_directory() { abort(); #endif } +_LIBCPP_DIAGNOSTIC_POP //===----------------------------------------------------------------------===// // Details @@ -767,7 +770,7 @@ void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) { // On Linux systems it seems /etc/timezone is deprecated and being phased out. // This file is used when /etc/localtime does not exist, or when it exists but // is not a symlink. For more information and links see - // https://github.com/llvm/llvm-project/issues/105634 + // https://llvm.org/PR105634 string __name = chrono::__current_zone_environment(); diff --git a/lib/libcxx/src/filesystem/error.h b/lib/libcxx/src/filesystem/error.h @@ -128,17 +128,8 @@ struct ErrorHandler { T report(const error_code& ec, const char* msg, ...) const { va_list ap; va_start(ap, msg); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - report_impl(ec, msg, ap); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS - va_end(ap); + __scope_guard guard([&] { va_end(ap); }); + report_impl(ec, msg, ap); return error_value<T>(); } @@ -148,17 +139,8 @@ struct ErrorHandler { T report(errc const& err, const char* msg, ...) const { va_list ap; va_start(ap, msg); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - report_impl(make_error_code(err), msg, ap); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS - va_end(ap); + __scope_guard guard([&] { va_end(ap); }); + report_impl(make_error_code(err), msg, ap); return error_value<T>(); } diff --git a/lib/libcxx/src/filesystem/format_string.h b/lib/libcxx/src/filesystem/format_string.h @@ -11,6 +11,7 @@ #include <__assert> #include <__config> +#include <__utility/scope_guard.h> #include <array> #include <cstdarg> #include <cstddef> @@ -34,20 +35,19 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string vformat_string(const ch va_list apcopy; va_copy(apcopy, ap); - int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); + int size = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); va_end(apcopy); string result; - if (static_cast<size_t>(ret) < buf.size()) { - result.assign(buf.data(), static_cast<size_t>(ret)); + if (static_cast<size_t>(size) < buf.size()) { + result.assign(buf.data(), static_cast<size_t>(size)); } else { // we did not provide a long enough buffer on our first attempt. The // return value is the number of bytes (excluding the null byte) that are // needed for formatting. - size_t size_with_null = static_cast<size_t>(ret) + 1; - result.__resize_default_init(size_with_null - 1); - ret = ::vsnprintf(&result[0], size_with_null, msg, ap); - _LIBCPP_ASSERT_INTERNAL(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); + result.resize_and_overwrite(size, [&](char* res, size_t n) { return ::vsnprintf(res, n, msg, ap); }); + _LIBCPP_ASSERT_INTERNAL(static_cast<size_t>(size) == result.size(), + "vsnprintf did not result in the same number of characters as the first attempt?"); } return result; } @@ -56,17 +56,8 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) string format_string(const cha string ret; va_list ap; va_start(ap, msg); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - ret = detail::vformat_string(msg, ap); -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS - va_end(ap); + __scope_guard guard([&] { va_end(ap); }); + ret = detail::vformat_string(msg, ap); return ret; } diff --git a/lib/libcxx/src/filesystem/int128_builtins.cpp b/lib/libcxx/src/filesystem/int128_builtins.cpp @@ -16,6 +16,8 @@ #include <__config> #include <climits> +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") // See the FIXME above + #if _LIBCPP_HAS_INT128 extern "C" __attribute__((no_sanitize("undefined"))) _LIBCPP_EXPORTED_FROM_ABI __int128_t diff --git a/lib/libcxx/src/filesystem/operations.cpp b/lib/libcxx/src/filesystem/operations.cpp @@ -41,17 +41,10 @@ #include <time.h> // since Linux 4.5 and FreeBSD 13, but the Linux libc wrapper is only provided by glibc >= 2.27 and musl -#if defined(__linux__) -# if defined(_LIBCPP_GLIBC_PREREQ) -# if _LIBCPP_GLIBC_PREREQ(2, 27) -# define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE -# endif -# elif _LIBCPP_HAS_MUSL_LIBC -# define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE -# endif -#elif defined(__FreeBSD__) +#if _LIBCPP_GLIBC_PREREQ(2, 27) || _LIBCPP_HAS_MUSL_LIBC || defined(__FreeBSD__) # define _LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE #endif + #if __has_include(<sys/sendfile.h>) # include <sys/sendfile.h> # define _LIBCPP_FILESYSTEM_USE_SENDFILE diff --git a/lib/libcxx/src/filesystem/path.cpp b/lib/libcxx/src/filesystem/path.cpp @@ -292,7 +292,9 @@ path path::lexically_relative(const path& base) const { // return a path constructed with 'n' dot-dot elements, followed by the // elements of '*this' after the mismatch. path Result; - // FIXME: Reserve enough room in Result that it won't have to re-allocate. + constexpr size_t ElemSize = 2; // ".." + constexpr size_t SeparatorSize = 1; // separator is always a single char + Result.__reserve(ElemCount * (ElemSize + SeparatorSize) + SeparatorSize + PP.Path.size()); while (ElemCount--) Result /= PATHSTR(".."); for (; PP; ++PP) diff --git a/lib/libcxx/src/include/aligned_alloc.h b/lib/libcxx/src/include/aligned_alloc.h @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_SRC_ALIGNED_ALLOC_H +#define _LIBCPP_SRC_ALIGNED_ALLOC_H + +#include <__config> +#include <cstdlib> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION + +// Low-level helpers to call the aligned allocation and deallocation functions +// on the target platform. This is used to implement libc++'s own memory +// allocation routines -- if you need to allocate memory inside the library, +// chances are that you want to use `__libcpp_allocate` instead. +// +// Returns the allocated memory, or `nullptr` on failure. +inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) { +# if defined(_LIBCPP_MSVCRT_LIKE) + return ::_aligned_malloc(__size, __alignment); + +// Android only provides aligned_alloc when targeting API 28 or higher. +# elif !defined(__ANDROID__) || __ANDROID_API__ >= 28 + // aligned_alloc() requires that __size is a multiple of __alignment, + // but for C++ [new.delete.general], only states "if the value of an + // alignment argument passed to any of these functions is not a valid + // alignment value, the behavior is undefined". + // To handle calls such as ::operator new(1, std::align_val_t(128)), we + // round __size up to the next multiple of __alignment. + size_t __rounded_size = (__size + __alignment - 1) & ~(__alignment - 1); + // Rounding up could have wrapped around to zero, so we have to add another + // max() ternary to the actual call site to avoid succeeded in that case. + return ::aligned_alloc(__alignment, __size > __rounded_size ? __size : __rounded_size); +# else + void* __result = nullptr; + (void)::posix_memalign(&__result, __alignment, __size); + // If posix_memalign fails, __result is unmodified so we still return `nullptr`. + return __result; +# endif +} + +inline _LIBCPP_HIDE_FROM_ABI void __libcpp_aligned_free(void* __ptr) { +# if defined(_LIBCPP_MSVCRT_LIKE) + ::_aligned_free(__ptr); +# else + ::free(__ptr); +# endif +} + +#endif // _LIBCPP_HAS_LIBRARY_ALIGNED_ALLOCATION + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SRC_ALIGNED_ALLOC_H diff --git a/lib/libcxx/src/include/config_elast.h b/lib/libcxx/src/include/config_elast.h @@ -23,7 +23,7 @@ # define _LIBCPP_ELAST ELAST #elif defined(__LLVM_LIBC__) // No _LIBCPP_ELAST needed for LLVM libc -#elif defined(_NEWLIB_VERSION) +#elif _LIBCPP_LIBC_NEWLIB # define _LIBCPP_ELAST __ELASTERROR #elif defined(__NuttX__) // No _LIBCPP_ELAST needed on NuttX diff --git a/lib/libcxx/src/include/from_chars_floating_point.h b/lib/libcxx/src/include/from_chars_floating_point.h @@ -9,11 +9,6 @@ #ifndef _LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H #define _LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H -// These headers are in the shared LLVM-libc header library. -#include "shared/fp_bits.h" -#include "shared/str_to_float.h" -#include "shared/str_to_integer.h" - #include <__assert> #include <__config> #include <cctype> @@ -21,6 +16,15 @@ #include <concepts> #include <limits> +// Make sure we use libc++'s assertion machinery within the shared code we use +// from LLVM libc. +#define LIBC_ASSERT(cond) _LIBCPP_ASSERT((cond), _LIBCPP_TOSTRING(cond)) + +// These headers are in the shared LLVM-libc header library. +#include "shared/fp_bits.h" +#include "shared/str_to_float.h" +#include "shared/str_to_integer.h" + // Included for the _Floating_type_traits class #include "to_chars_floating_point.h" @@ -193,7 +197,7 @@ struct __exponent_result { // __offset, 0, false. This allows using the results unconditionally, the // __present is important for the scientific notation, where the value is // mandatory. -__exponent_result __parse_exponent(const char* __input, size_t __n, size_t __offset, char __marker) { +static __exponent_result __parse_exponent(const char* __input, size_t __n, size_t __offset, char __marker) { if (__offset + 1 < __n && // an exponent always needs at least one digit. std::tolower(__input[__offset]) == __marker && // !std::isspace(__input[__offset + 1]) // leading whitespace is not allowed. @@ -213,7 +217,7 @@ __exponent_result __parse_exponent(const char* __input, size_t __n, size_t __off } // Here we do this operation as int64 to avoid overflow. -int32_t __merge_exponents(int64_t __fractional, int64_t __exponent, int __max_biased_exponent) { +static int32_t __merge_exponents(int64_t __fractional, int64_t __exponent, int __max_biased_exponent) { int64_t __sum = __fractional + __exponent; if (__sum > __max_biased_exponent) diff --git a/lib/libcxx/src/include/overridable_function.h b/lib/libcxx/src/include/overridable_function.h @@ -29,12 +29,12 @@ // This is a low-level utility which does not work on all platforms, since it needs // to make assumptions about the object file format in use. Furthermore, it requires // the "base definition" of the function (the one we want to check whether it has been -// overridden) to be defined using the _LIBCPP_OVERRIDABLE_FUNCTION macro. +// overridden) to be defined using the OVERRIDABLE_FUNCTION macro. // // This currently works with Mach-O files (used on Darwin) and with ELF files (used on Linux // and others). On platforms where we know how to implement this detection, the macro // _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION is defined to 1, and it is defined to 0 on -// other platforms. The _LIBCPP_OVERRIDABLE_FUNCTION macro is defined to perform a normal +// other platforms. The OVERRIDABLE_FUNCTION macro is defined to perform a normal // function definition on unsupported platforms so that it can be used to define functions // regardless of whether detection is actually supported. // @@ -44,7 +44,7 @@ // Let's say we want to check whether a weak function `f` has been overridden by the user. // The general mechanism works by placing `f`'s definition (in the libc++ built library) // inside a special section, which we do using the `__section__` attribute via the -// _LIBCPP_OVERRIDABLE_FUNCTION macro. +// OVERRIDABLE_FUNCTION macro. // // Then, when comes the time to check whether the function has been overridden, we take // the address of the function and we check whether it falls inside the special function @@ -66,11 +66,10 @@ #if defined(_LIBCPP_OBJECT_FORMAT_MACHO) # define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 -# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \ - __attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) _LIBCPP_WEAK type name arglist +# define OVERRIDABLE_FUNCTION \ + __attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) _LIBCPP_WEAK -_LIBCPP_BEGIN_NAMESPACE_STD -template <typename T, T* _Func> +_LIBCPP_BEGIN_NAMESPACE_STD template <typename T, T* _Func> _LIBCPP_HIDE_FROM_ABI inline bool __is_function_overridden() noexcept { // Declare two dummy bytes and give them these special `__asm` values. These values are // defined by the linker, which means that referring to `&__lcxx_override_start` will @@ -100,8 +99,7 @@ _LIBCPP_END_NAMESPACE_STD #elif defined(_LIBCPP_OBJECT_FORMAT_ELF) && !defined(__NVPTX__) # define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 -# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) \ - __attribute__((__section__("__lcxx_override"))) _LIBCPP_WEAK type name arglist +# define OVERRIDABLE_FUNCTION __attribute__((__section__("__lcxx_override"))) _LIBCPP_WEAK // This is very similar to what we do for Mach-O above. The ELF linker will implicitly define // variables with those names corresponding to the start and the end of the section. @@ -129,7 +127,7 @@ _LIBCPP_END_NAMESPACE_STD #else # define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 0 -# define _LIBCPP_OVERRIDABLE_FUNCTION(type, name, arglist) _LIBCPP_WEAK type name arglist +# define OVERRIDABLE_FUNCTION _LIBCPP_WEAK #endif diff --git a/lib/libcxx/src/iostream.cpp b/lib/libcxx/src/iostream.cpp @@ -16,24 +16,40 @@ _LIBCPP_BEGIN_NAMESPACE_STD +// This file implements the various stream objects provided inside <iostream>. We're doing some ODR violations in here, +// so this quite fragile. Specifically, the size of the stream objects (i.e. cout, cin etc.) needs to stay the same. +// For that reason, we have `stream` and `stream_data` separated into two objects. The public `stream` objects only +// contain the actual stream, while the private `stream_data` objects contains the `basic_streambuf` we're using as well +// as the mbstate_t. `stream_data` objects are only accessible within the library, so they aren't ABI sensitive and we +// can change them as we want. + +template <class StreamT> +union stream { + constexpr stream() {} + stream(const stream&) = delete; + stream& operator=(const stream&) = delete; + constexpr ~stream() {} + + StreamT value; +}; + template <class StreamT, class BufferT> union stream_data { constexpr stream_data() {} constexpr ~stream_data() {} struct { - // The stream has to be the first element, since that's referenced by the stream declarations in <iostream> - StreamT stream; BufferT buffer; mbstate_t mb; }; - - void init(FILE* stdstream) { - mb = {}; - std::construct_at(&buffer, stdstream, &mb); - std::construct_at(&stream, &buffer); - } }; +template <class StreamT, class BufferT> +void init_stream(FILE* stdstream, stream<StreamT>& stream, stream_data<StreamT, BufferT>& data) { + data.mb = {}; + std::construct_at(&data.buffer, stdstream, &data.mb); + std::construct_at(&stream.value, &data.buffer); +} + #define CHAR_MANGLING_char "D" #define CHAR_MANGLING_wchar_t "_W" #define CHAR_MANGLING(CharT) CHAR_MANGLING_##CharT @@ -46,25 +62,28 @@ union stream_data { #ifdef _LIBCPP_ABI_MICROSOFT # define STREAM(StreamT, BufferT, CharT, var) \ - STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var __asm__( \ + STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var##_data; \ + _LIBCPP_EXPORTED_FROM_ABI STRING_DATA_CONSTINIT stream<StreamT<CharT>> var __asm__( \ "?" #var "@" ABI_NAMESPACE_STR "@std@@3V?$" #StreamT \ "@" CHAR_MANGLING(CharT) "U?$char_traits@" CHAR_MANGLING(CharT) "@" ABI_NAMESPACE_STR "@std@@@12@A") #else -# define STREAM(StreamT, BufferT, CharT, var) STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var +# define STREAM(StreamT, BufferT, CharT, var) \ + STRING_DATA_CONSTINIT stream_data<StreamT<CharT>, BufferT<CharT>> var##_data; \ + _LIBCPP_EXPORTED_FROM_ABI STRING_DATA_CONSTINIT stream<StreamT<CharT>> var #endif // These definitions and the declarations in <iostream> technically cause ODR violations, since they have different // types (stream_data and {i,o}stream respectively). This means that <iostream> should never be included in this TU. -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, char, cin); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cout); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, cerr); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, char, clog); +STREAM(basic_istream, __stdinbuf, char, cin); +STREAM(basic_ostream, __stdoutbuf, char, cout); +STREAM(basic_ostream, __stdoutbuf, char, cerr); +STREAM(basic_ostream, __stdoutbuf, char, clog); #if _LIBCPP_HAS_WIDE_CHARACTERS -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_istream, __stdinbuf, wchar_t, wcin); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr); -_LIBCPP_EXPORTED_FROM_ABI STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog); +STREAM(basic_istream, __stdinbuf, wchar_t, wcin); +STREAM(basic_ostream, __stdoutbuf, wchar_t, wcout); +STREAM(basic_ostream, __stdoutbuf, wchar_t, wcerr); +STREAM(basic_ostream, __stdoutbuf, wchar_t, wclog); #endif // _LIBCPP_HAS_WIDE_CHARACTERS // Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority @@ -98,34 +117,34 @@ public: DoIOSInit::DoIOSInit() { force_locale_initialization(); - cin.init(stdin); - cout.init(stdout); - cerr.init(stderr); - clog.init(stderr); + init_stream(stdin, cin, cin_data); + init_stream(stdout, cout, cout_data); + init_stream(stderr, cerr, cerr_data); + init_stream(stderr, clog, clog_data); - cin.stream.tie(&cout.stream); - std::unitbuf(cerr.stream); - cerr.stream.tie(&cout.stream); + cin.value.tie(&cout.value); + std::unitbuf(cerr.value); + cerr.value.tie(&cout.value); #if _LIBCPP_HAS_WIDE_CHARACTERS - wcin.init(stdin); - wcout.init(stdout); - wcerr.init(stderr); - wclog.init(stderr); - - wcin.stream.tie(&wcout.stream); - std::unitbuf(wcerr.stream); - wcerr.stream.tie(&wcout.stream); + init_stream(stdin, wcin, wcin_data); + init_stream(stdout, wcout, wcout_data); + init_stream(stderr, wcerr, wcerr_data); + init_stream(stderr, wclog, wclog_data); + + wcin.value.tie(&wcout.value); + std::unitbuf(wcerr.value); + wcerr.value.tie(&wcout.value); #endif } DoIOSInit::~DoIOSInit() { - cout.stream.flush(); - clog.stream.flush(); + cout.value.flush(); + clog.value.flush(); #if _LIBCPP_HAS_WIDE_CHARACTERS - wcout.stream.flush(); - wclog.stream.flush(); + wcout.value.flush(); + wclog.value.flush(); #endif } diff --git a/lib/libcxx/src/locale.cpp b/lib/libcxx/src/locale.cpp @@ -60,9 +60,8 @@ struct __libcpp_unique_locale { __locale::__locale_t __loc_; -private: - __libcpp_unique_locale(__libcpp_unique_locale const&); - __libcpp_unique_locale& operator=(__libcpp_unique_locale const&); + __libcpp_unique_locale(__libcpp_unique_locale const&) = delete; + __libcpp_unique_locale& operator=(__libcpp_unique_locale const&) = delete; }; #ifdef __cloc_defined @@ -88,16 +87,6 @@ T& make(Args... args) { return *obj; } -template <typename T, size_t N> -inline constexpr size_t countof(const T (&)[N]) { - return N; -} - -template <typename T> -inline constexpr size_t countof(const T* const begin, const T* const end) { - return static_cast<size_t>(end - begin); -} - string build_name(const string& other, const string& one, locale::category c) { if (other == "*" || one == "*") return "*"; @@ -215,63 +204,58 @@ locale::__imp::__imp(size_t refs) : facet(refs), facets_(N), name_("C") { } locale::__imp::__imp(const string& name, size_t refs) : facet(refs), facets_(N), name_(name) { -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - facets_ = locale::classic().__locale_->facets_; + __exception_guard guard([&] { for (unsigned i = 0; i < facets_.size(); ++i) if (facets_[i]) - facets_[i]->__add_shared(); - install(new collate_byname<char>(name_)); + facets_[i]->__release_shared(); + }); + facets_ = locale::classic().__locale_->facets_; + for (unsigned i = 0; i < facets_.size(); ++i) + if (facets_[i]) + facets_[i]->__add_shared(); + install(new collate_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new collate_byname<wchar_t>(name_)); + install(new collate_byname<wchar_t>(name_)); #endif - install(new ctype_byname<char>(name_)); + install(new ctype_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new ctype_byname<wchar_t>(name_)); + install(new ctype_byname<wchar_t>(name_)); #endif - install(new codecvt_byname<char, char, mbstate_t>(name_)); + install(new codecvt_byname<char, char, mbstate_t>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new codecvt_byname<wchar_t, char, mbstate_t>(name_)); + install(new codecvt_byname<wchar_t, char, mbstate_t>(name_)); #endif - _LIBCPP_SUPPRESS_DEPRECATED_PUSH - install(new codecvt_byname<char16_t, char, mbstate_t>(name_)); - install(new codecvt_byname<char32_t, char, mbstate_t>(name_)); - _LIBCPP_SUPPRESS_DEPRECATED_POP + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + install(new codecvt_byname<char16_t, char, mbstate_t>(name_)); + install(new codecvt_byname<char32_t, char, mbstate_t>(name_)); + _LIBCPP_SUPPRESS_DEPRECATED_POP #if _LIBCPP_HAS_CHAR8_T - install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name_)); - install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name_)); + install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name_)); + install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name_)); #endif - install(new numpunct_byname<char>(name_)); + install(new numpunct_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new numpunct_byname<wchar_t>(name_)); + install(new numpunct_byname<wchar_t>(name_)); #endif - install(new moneypunct_byname<char, false>(name_)); - install(new moneypunct_byname<char, true>(name_)); + install(new moneypunct_byname<char, false>(name_)); + install(new moneypunct_byname<char, true>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new moneypunct_byname<wchar_t, false>(name_)); - install(new moneypunct_byname<wchar_t, true>(name_)); + install(new moneypunct_byname<wchar_t, false>(name_)); + install(new moneypunct_byname<wchar_t, true>(name_)); #endif - install(new time_get_byname<char>(name_)); + install(new time_get_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new time_get_byname<wchar_t>(name_)); + install(new time_get_byname<wchar_t>(name_)); #endif - install(new time_put_byname<char>(name_)); + install(new time_put_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new time_put_byname<wchar_t>(name_)); + install(new time_put_byname<wchar_t>(name_)); #endif - install(new messages_byname<char>(name_)); + install(new messages_byname<char>(name_)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new messages_byname<wchar_t>(name_)); + install(new messages_byname<wchar_t>(name_)); #endif -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - for (unsigned i = 0; i < facets_.size(); ++i) - if (facets_[i]) - facets_[i]->__release_shared(); - throw; - } -#endif // _LIBCPP_HAS_EXCEPTIONS + guard.__complete(); } locale::__imp::__imp(const __imp& other) : facets_(max<size_t>(N, other.facets_.size())), name_(other.name_) { @@ -287,71 +271,66 @@ locale::__imp::__imp(const __imp& other, const string& name, locale::category c) for (unsigned i = 0; i < facets_.size(); ++i) if (facets_[i]) facets_[i]->__add_shared(); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - if (c & locale::collate) { - install(new collate_byname<char>(name)); + __exception_guard guard([&] { + for (unsigned i = 0; i < facets_.size(); ++i) + if (facets_[i]) + facets_[i]->__release_shared(); + }); + if (c & locale::collate) { + install(new collate_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new collate_byname<wchar_t>(name)); + install(new collate_byname<wchar_t>(name)); #endif - } - if (c & locale::ctype) { - install(new ctype_byname<char>(name)); + } + if (c & locale::ctype) { + install(new ctype_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new ctype_byname<wchar_t>(name)); + install(new ctype_byname<wchar_t>(name)); #endif - install(new codecvt_byname<char, char, mbstate_t>(name)); + install(new codecvt_byname<char, char, mbstate_t>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new codecvt_byname<wchar_t, char, mbstate_t>(name)); + install(new codecvt_byname<wchar_t, char, mbstate_t>(name)); #endif - _LIBCPP_SUPPRESS_DEPRECATED_PUSH - install(new codecvt_byname<char16_t, char, mbstate_t>(name)); - install(new codecvt_byname<char32_t, char, mbstate_t>(name)); - _LIBCPP_SUPPRESS_DEPRECATED_POP + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + install(new codecvt_byname<char16_t, char, mbstate_t>(name)); + install(new codecvt_byname<char32_t, char, mbstate_t>(name)); + _LIBCPP_SUPPRESS_DEPRECATED_POP #if _LIBCPP_HAS_CHAR8_T - install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name)); - install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name)); + install(new codecvt_byname<char16_t, char8_t, mbstate_t>(name)); + install(new codecvt_byname<char32_t, char8_t, mbstate_t>(name)); #endif - } - if (c & locale::monetary) { - install(new moneypunct_byname<char, false>(name)); - install(new moneypunct_byname<char, true>(name)); + } + if (c & locale::monetary) { + install(new moneypunct_byname<char, false>(name)); + install(new moneypunct_byname<char, true>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new moneypunct_byname<wchar_t, false>(name)); - install(new moneypunct_byname<wchar_t, true>(name)); + install(new moneypunct_byname<wchar_t, false>(name)); + install(new moneypunct_byname<wchar_t, true>(name)); #endif - } - if (c & locale::numeric) { - install(new numpunct_byname<char>(name)); + } + if (c & locale::numeric) { + install(new numpunct_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new numpunct_byname<wchar_t>(name)); + install(new numpunct_byname<wchar_t>(name)); #endif - } - if (c & locale::time) { - install(new time_get_byname<char>(name)); + } + if (c & locale::time) { + install(new time_get_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new time_get_byname<wchar_t>(name)); + install(new time_get_byname<wchar_t>(name)); #endif - install(new time_put_byname<char>(name)); + install(new time_put_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new time_put_byname<wchar_t>(name)); + install(new time_put_byname<wchar_t>(name)); #endif - } - if (c & locale::messages) { - install(new messages_byname<char>(name)); + } + if (c & locale::messages) { + install(new messages_byname<char>(name)); #if _LIBCPP_HAS_WIDE_CHARACTERS - install(new messages_byname<wchar_t>(name)); + install(new messages_byname<wchar_t>(name)); #endif - } -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - for (unsigned i = 0; i < facets_.size(); ++i) - if (facets_[i]) - facets_[i]->__release_shared(); - throw; } -#endif // _LIBCPP_HAS_EXCEPTIONS + guard.__complete(); } template <class F> @@ -366,87 +345,83 @@ locale::__imp::__imp(const __imp& other, const __imp& one, locale::category c) for (unsigned i = 0; i < facets_.size(); ++i) if (facets_[i]) facets_[i]->__add_shared(); -#if _LIBCPP_HAS_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_EXCEPTIONS - if (c & locale::collate) { - install_from<std::collate<char> >(one); + __exception_guard guard([&] { + for (unsigned i = 0; i < facets_.size(); ++i) + if (facets_[i]) + facets_[i]->__release_shared(); + }); + + if (c & locale::collate) { + install_from<std::collate<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<std::collate<wchar_t> >(one); + install_from<std::collate<wchar_t> >(one); #endif - } - if (c & locale::ctype) { - install_from<std::ctype<char> >(one); + } + if (c & locale::ctype) { + install_from<std::ctype<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<std::ctype<wchar_t> >(one); + install_from<std::ctype<wchar_t> >(one); #endif - install_from<std::codecvt<char, char, mbstate_t> >(one); - _LIBCPP_SUPPRESS_DEPRECATED_PUSH - install_from<std::codecvt<char16_t, char, mbstate_t> >(one); - install_from<std::codecvt<char32_t, char, mbstate_t> >(one); - _LIBCPP_SUPPRESS_DEPRECATED_POP + install_from<std::codecvt<char, char, mbstate_t> >(one); + _LIBCPP_SUPPRESS_DEPRECATED_PUSH + install_from<std::codecvt<char16_t, char, mbstate_t> >(one); + install_from<std::codecvt<char32_t, char, mbstate_t> >(one); + _LIBCPP_SUPPRESS_DEPRECATED_POP #if _LIBCPP_HAS_CHAR8_T - install_from<std::codecvt<char16_t, char8_t, mbstate_t> >(one); - install_from<std::codecvt<char32_t, char8_t, mbstate_t> >(one); + install_from<std::codecvt<char16_t, char8_t, mbstate_t> >(one); + install_from<std::codecvt<char32_t, char8_t, mbstate_t> >(one); #endif #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<std::codecvt<wchar_t, char, mbstate_t> >(one); + install_from<std::codecvt<wchar_t, char, mbstate_t> >(one); #endif - } - if (c & locale::monetary) { - install_from<moneypunct<char, false> >(one); - install_from<moneypunct<char, true> >(one); + } + if (c & locale::monetary) { + install_from<moneypunct<char, false> >(one); + install_from<moneypunct<char, true> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<moneypunct<wchar_t, false> >(one); - install_from<moneypunct<wchar_t, true> >(one); + install_from<moneypunct<wchar_t, false> >(one); + install_from<moneypunct<wchar_t, true> >(one); #endif - install_from<money_get<char> >(one); + install_from<money_get<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<money_get<wchar_t> >(one); + install_from<money_get<wchar_t> >(one); #endif - install_from<money_put<char> >(one); + install_from<money_put<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<money_put<wchar_t> >(one); + install_from<money_put<wchar_t> >(one); #endif - } - if (c & locale::numeric) { - install_from<numpunct<char> >(one); + } + if (c & locale::numeric) { + install_from<numpunct<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<numpunct<wchar_t> >(one); + install_from<numpunct<wchar_t> >(one); #endif - install_from<num_get<char> >(one); + install_from<num_get<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<num_get<wchar_t> >(one); + install_from<num_get<wchar_t> >(one); #endif - install_from<num_put<char> >(one); + install_from<num_put<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<num_put<wchar_t> >(one); + install_from<num_put<wchar_t> >(one); #endif - } - if (c & locale::time) { - install_from<time_get<char> >(one); + } + if (c & locale::time) { + install_from<time_get<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<time_get<wchar_t> >(one); + install_from<time_get<wchar_t> >(one); #endif - install_from<time_put<char> >(one); + install_from<time_put<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<time_put<wchar_t> >(one); + install_from<time_put<wchar_t> >(one); #endif - } - if (c & locale::messages) { - install_from<std::messages<char> >(one); + } + if (c & locale::messages) { + install_from<std::messages<char> >(one); #if _LIBCPP_HAS_WIDE_CHARACTERS - install_from<std::messages<wchar_t> >(one); + install_from<std::messages<wchar_t> >(one); #endif - } -#if _LIBCPP_HAS_EXCEPTIONS - } catch (...) { - for (unsigned i = 0; i < facets_.size(); ++i) - if (facets_[i]) - facets_[i]->__release_shared(); - throw; } -#endif // _LIBCPP_HAS_EXCEPTIONS + guard.__complete(); } locale::__imp::__imp(const __imp& other, facet* f, long id) @@ -933,7 +908,7 @@ const ctype<char>::mask* ctype<char>::classic_table() noexcept { return __pctype_func(); # elif defined(__EMSCRIPTEN__) return *__ctype_b_loc(); -# elif defined(_NEWLIB_VERSION) +# elif _LIBCPP_LIBC_NEWLIB // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1]. return _ctype_ + 1; # elif defined(_AIX) @@ -3961,13 +3936,7 @@ wstring numpunct<wchar_t>::do_falsename() const { return L"false"; } // numpunct_byname<char> -numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs) : numpunct<char>(refs) { __init(nm); } - -numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs) : numpunct<char>(refs) { __init(nm.c_str()); } - -numpunct_byname<char>::~numpunct_byname() {} - -void numpunct_byname<char>::__init(const char* nm) { +numpunct_byname<char>::numpunct_byname(const char* nm, size_t refs) : numpunct<char>(refs) { typedef numpunct<char> base; if (strcmp(nm, "C") != 0) { __libcpp_unique_locale loc(nm); @@ -3988,18 +3957,14 @@ void numpunct_byname<char>::__init(const char* nm) { } } -// numpunct_byname<wchar_t> - -#if _LIBCPP_HAS_WIDE_CHARACTERS -numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs) : numpunct<wchar_t>(refs) { __init(nm); } +numpunct_byname<char>::numpunct_byname(const string& nm, size_t refs) : numpunct_byname<char>(nm.c_str(), refs) {} -numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs) : numpunct<wchar_t>(refs) { - __init(nm.c_str()); -} +numpunct_byname<char>::~numpunct_byname() {} -numpunct_byname<wchar_t>::~numpunct_byname() {} +// numpunct_byname<wchar_t> -void numpunct_byname<wchar_t>::__init(const char* nm) { +#if _LIBCPP_HAS_WIDE_CHARACTERS +numpunct_byname<wchar_t>::numpunct_byname(const char* nm, size_t refs) : numpunct<wchar_t>(refs) { if (strcmp(nm, "C") != 0) { __libcpp_unique_locale loc(nm); if (!loc) @@ -4016,6 +3981,10 @@ void numpunct_byname<wchar_t>::__init(const char* nm) { // localization for truename and falsename is not available } } + +numpunct_byname<wchar_t>::numpunct_byname(const string& nm, size_t refs) : numpunct_byname<wchar_t>(nm.c_str(), refs) {} + +numpunct_byname<wchar_t>::~numpunct_byname() {} #endif // _LIBCPP_HAS_WIDE_CHARACTERS // num_get helpers @@ -4383,7 +4352,7 @@ string __time_get_storage<char>::__analyze(char fmt, const ctype<char>& ct) { char f[3] = {0}; f[0] = '%'; f[1] = fmt; - size_t n = __locale::__strftime(buf, countof(buf), f, &t, __loc_); + size_t n = __locale::__strftime(buf, std::size(buf), f, &t, __loc_); char* bb = buf; char* be = buf + n; string result; @@ -4514,12 +4483,12 @@ wstring __time_get_storage<wchar_t>::__analyze(char fmt, const ctype<wchar_t>& c char f[3] = {0}; f[0] = '%'; f[1] = fmt; - __locale::__strftime(buf, countof(buf), f, &t, __loc_); + __locale::__strftime(buf, std::size(buf), f, &t, __loc_); wchar_t wbuf[100]; wchar_t* wbb = wbuf; mbstate_t mb = {0}; const char* bb = buf; - size_t j = __locale::__mbsrtowcs(wbb, &bb, countof(wbuf), &mb, __loc_); + size_t j = __locale::__mbsrtowcs(wbb, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wchar_t* wbe = wbb + j; @@ -4640,25 +4609,25 @@ void __time_get_storage<char>::init(const ctype<char>& ct) { // __weeks_ for (int i = 0; i < 7; ++i) { t.tm_wday = i; - __locale::__strftime(buf, countof(buf), "%A", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%A", &t, __loc_); __weeks_[i] = buf; - __locale::__strftime(buf, countof(buf), "%a", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%a", &t, __loc_); __weeks_[i + 7] = buf; } // __months_ for (int i = 0; i < 12; ++i) { t.tm_mon = i; - __locale::__strftime(buf, countof(buf), "%B", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%B", &t, __loc_); __months_[i] = buf; - __locale::__strftime(buf, countof(buf), "%b", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%b", &t, __loc_); __months_[i + 12] = buf; } // __am_pm_ t.tm_hour = 1; - __locale::__strftime(buf, countof(buf), "%p", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%p", &t, __loc_); __am_pm_[0] = buf; t.tm_hour = 13; - __locale::__strftime(buf, countof(buf), "%p", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%p", &t, __loc_); __am_pm_[1] = buf; __c_ = __analyze('c', ct); __r_ = __analyze('r', ct); @@ -4677,18 +4646,18 @@ void __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) { // __weeks_ for (int i = 0; i < 7; ++i) { t.tm_wday = i; - __locale::__strftime(buf, countof(buf), "%A", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%A", &t, __loc_); mb = mbstate_t(); const char* bb = buf; - size_t j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + size_t j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1) || j == 0) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; __weeks_[i].assign(wbuf, wbe); - __locale::__strftime(buf, countof(buf), "%a", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%a", &t, __loc_); mb = mbstate_t(); bb = buf; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1) || j == 0) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -4697,18 +4666,18 @@ void __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) { // __months_ for (int i = 0; i < 12; ++i) { t.tm_mon = i; - __locale::__strftime(buf, countof(buf), "%B", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%B", &t, __loc_); mb = mbstate_t(); const char* bb = buf; - size_t j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + size_t j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1) || j == 0) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; __months_[i].assign(wbuf, wbe); - __locale::__strftime(buf, countof(buf), "%b", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%b", &t, __loc_); mb = mbstate_t(); bb = buf; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1) || j == 0) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -4716,19 +4685,19 @@ void __time_get_storage<wchar_t>::init(const ctype<wchar_t>& ct) { } // __am_pm_ t.tm_hour = 1; - __locale::__strftime(buf, countof(buf), "%p", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%p", &t, __loc_); mb = mbstate_t(); const char* bb = buf; - size_t j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + size_t j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; __am_pm_[0].assign(wbuf, wbe); t.tm_hour = 13; - __locale::__strftime(buf, countof(buf), "%p", &t, __loc_); + __locale::__strftime(buf, std::size(buf), "%p", &t, __loc_); mb = mbstate_t(); bb = buf; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, __loc_); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, __loc_); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -4957,7 +4926,7 @@ void __time_put::__do_put(char* __nb, char*& __ne, const tm* __tm, char __fmt, c char fmt[] = {'%', __fmt, __mod, 0}; if (__mod != 0) swap(fmt[1], fmt[2]); - size_t n = __locale::__strftime(__nb, countof(__nb, __ne), fmt, __tm, __loc_); + size_t n = __locale::__strftime(__nb, std::distance(__nb, __ne), fmt, __tm, __loc_); __ne = __nb + n; } @@ -4968,7 +4937,7 @@ void __time_put::__do_put(wchar_t* __wb, wchar_t*& __we, const tm* __tm, char __ __do_put(__nar, __ne, __tm, __fmt, __mod); mbstate_t mb = {0}; const char* __nb = __nar; - size_t j = __locale::__mbsrtowcs(__wb, &__nb, countof(__wb, __we), &mb, __loc_); + size_t j = __locale::__mbsrtowcs(__wb, &__nb, std::distance(__wb, __we), &mb, __loc_); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); __we = __wb + j; @@ -5443,7 +5412,7 @@ void moneypunct_byname<wchar_t, false>::init(const char* nm) { wchar_t wbuf[100]; mbstate_t mb = {0}; const char* bb = lc->currency_symbol; - size_t j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + size_t j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wchar_t* wbe = wbuf + j; @@ -5457,7 +5426,7 @@ void moneypunct_byname<wchar_t, false>::init(const char* nm) { else { mb = mbstate_t(); bb = lc->positive_sign; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5468,7 +5437,7 @@ void moneypunct_byname<wchar_t, false>::init(const char* nm) { else { mb = mbstate_t(); bb = lc->negative_sign; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5498,7 +5467,7 @@ void moneypunct_byname<wchar_t, true>::init(const char* nm) { wchar_t wbuf[100]; mbstate_t mb = {0}; const char* bb = lc->int_curr_symbol; - size_t j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + size_t j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wchar_t* wbe = wbuf + j; @@ -5516,7 +5485,7 @@ void moneypunct_byname<wchar_t, true>::init(const char* nm) { else { mb = mbstate_t(); bb = lc->positive_sign; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5531,7 +5500,7 @@ void moneypunct_byname<wchar_t, true>::init(const char* nm) { else { mb = mbstate_t(); bb = lc->negative_sign; - j = __locale::__mbsrtowcs(wbuf, &bb, countof(wbuf), &mb, loc.get()); + j = __locale::__mbsrtowcs(wbuf, &bb, std::size(wbuf), &mb, loc.get()); if (j == size_t(-1)) std::__throw_runtime_error("locale not supported"); wbe = wbuf + j; @@ -5571,6 +5540,54 @@ string __num_get<_CharT>::__stage2_int_prep(ios_base& __iob, _CharT* __atoms, _C return __np.grouping(); } +template <class _CharT> +int __num_get<_CharT>::__stage2_int_loop( + _CharT __ct, + int __base, + char* __a, + char*& __a_end, + unsigned& __dc, + _CharT __thousands_sep, + const string& __grouping, + unsigned* __g, + unsigned*& __g_end, + _CharT* __atoms) { + if (__a_end == __a && (__ct == __atoms[24] || __ct == __atoms[25])) { + *__a_end++ = __ct == __atoms[24] ? '+' : '-'; + __dc = 0; + return 0; + } + if (__grouping.size() != 0 && __ct == __thousands_sep) { + if (__g_end - __g < __num_get_buf_sz) { + *__g_end++ = __dc; + __dc = 0; + } + return 0; + } + ptrdiff_t __f = __atoms_offset(__atoms, __ct); + if (__f >= 24) + return -1; + switch (__base) { + case 8: + case 10: + if (__f >= __base) + return -1; + break; + case 16: + if (__f < 22) + break; + if (__a_end != __a && __a_end - __a <= 2 && __a_end[-1] == '0') { + __dc = 0; + *__a_end++ = __src[__f]; + return 0; + } + return -1; + } + *__a_end++ = __src[__f]; + ++__dc; + return 0; +} + template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<char>; _LIBCPP_IF_WIDE_CHARACTERS(template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS collate<wchar_t>;) diff --git a/lib/libcxx/src/memory.cpp b/lib/libcxx/src/memory.cpp @@ -7,7 +7,8 @@ //===----------------------------------------------------------------------===// #include <__config> -#ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS +#if !defined(_LIBCPP_OBJECT_FORMAT_COFF) && !defined(_LIBCPP_OBJECT_FORMAT_XCOFF) && \ + _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 5 # define _LIBCPP_SHARED_PTR_DEFINE_LEGACY_INLINE_FUNCTIONS #endif @@ -132,19 +133,16 @@ __sp_mut& __get_sp_mut(const void* p) { #endif // _LIBCPP_HAS_THREADS -void* align(size_t alignment, size_t size, void*& ptr, size_t& space) { - void* r = nullptr; - if (size <= space) { - char* p1 = static_cast<char*>(ptr); - char* p2 = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(p1 + (alignment - 1)) & -alignment); - size_t d = static_cast<size_t>(p2 - p1); - if (d <= space - size) { - r = p2; - ptr = r; - space -= d; - } - } - return r; +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21 + +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmissing-prototypes") +// This function only exists for ABI compatibility and we therefore don't provide a declaration in the headers +_LIBCPP_EXPORTED_FROM_ABI void* align(size_t alignment, size_t size, void*& ptr, size_t& space) { + return __align_inline::align(alignment, size, ptr, space); } +_LIBCPP_DIAGNOSTIC_POP + +#endif _LIBCPP_END_NAMESPACE_STD diff --git a/lib/libcxx/src/mutex_destructor.cpp b/lib/libcxx/src/mutex_destructor.cpp @@ -19,7 +19,7 @@ #include <__config> #include <__thread/support.h> -#if _LIBCPP_ABI_VERSION == 1 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 || !_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION # define NEEDS_MUTEX_DESTRUCTOR #endif diff --git a/lib/libcxx/src/new.cpp b/lib/libcxx/src/new.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "include/aligned_alloc.h" #include "include/overridable_function.h" #include <__assert> -#include <__memory/aligned_alloc.h> #include <cstddef> #include <cstdlib> #include <new> @@ -43,7 +43,7 @@ static void* operator_new_impl(std::size_t size) { return p; } -_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size)) _THROW_BAD_ALLOC { +OVERRIDABLE_FUNCTION void* operator new(std::size_t size) _THROW_BAD_ALLOC { void* p = operator_new_impl(size); if (p == nullptr) __throw_bad_alloc_shim(); @@ -74,7 +74,7 @@ _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { # endif } -_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size)) _THROW_BAD_ALLOC { return ::operator new(size); } +OVERRIDABLE_FUNCTION void* operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); } _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { # if !_LIBCPP_HAS_EXCEPTIONS @@ -134,7 +134,7 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm return p; } -_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new, (std::size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC { +OVERRIDABLE_FUNCTION void* operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { void* p = operator_new_aligned_impl(size, alignment); if (p == nullptr) __throw_bad_alloc_shim(); @@ -165,7 +165,7 @@ _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const s # endif } -_LIBCPP_OVERRIDABLE_FUNCTION(void*, operator new[], (size_t size, std::align_val_t alignment)) _THROW_BAD_ALLOC { +OVERRIDABLE_FUNCTION void* operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { return ::operator new(size, alignment); } diff --git a/lib/libcxx/src/optional.cpp b/lib/libcxx/src/optional.cpp @@ -19,6 +19,8 @@ const char* bad_optional_access::what() const noexcept { return "bad_optional_ac #include <__config> +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7 + // Preserve std::experimental::bad_optional_access for ABI compatibility // Even though it no longer exists in a header file _LIBCPP_BEGIN_NAMESPACE_EXPERIMENTAL @@ -34,3 +36,5 @@ public: bad_optional_access::~bad_optional_access() noexcept = default; _LIBCPP_END_NAMESPACE_EXPERIMENTAL + +#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 7 diff --git a/lib/libcxx/src/print.cpp b/lib/libcxx/src/print.cpp @@ -22,6 +22,14 @@ # include <windows.h> #elif __has_include(<unistd.h>) # include <unistd.h> +# if defined(_NEWLIB_VERSION) +# if defined(_POSIX_C_SOURCE) && __has_include(<stdio.h>) +# include <stdio.h> +# define HAS_FILENO_AND_ISATTY +# endif +# else +# define HAS_FILENO_AND_ISATTY +# endif #endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -56,7 +64,7 @@ __write_to_windows_console([[maybe_unused]] FILE* __stream, [[maybe_unused]] wst } # endif // _LIBCPP_HAS_WIDE_CHARACTERS -#elif __has_include(<unistd.h>) // !_LIBCPP_WIN32API +#elif defined(HAS_FILENO_AND_ISATTY) // !_LIBCPP_WIN32API _LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream) { return isatty(fileno(__stream)); } #endif diff --git a/lib/libcxx/src/random.cpp b/lib/libcxx/src/random.cpp @@ -31,8 +31,6 @@ # include <linux/random.h> # include <sys/ioctl.h> # endif -#elif defined(_LIBCPP_USING_NACL_RANDOM) -# include <nacl/nacl_random.h> #elif defined(_LIBCPP_USING_FUCHSIA_CPRNG) # include <zircon/syscalls.h> #endif @@ -93,30 +91,6 @@ unsigned random_device::operator()() { return r; } -#elif defined(_LIBCPP_USING_NACL_RANDOM) - -random_device::random_device(const string& __token) { - if (__token != "/dev/urandom") - std::__throw_system_error(ENOENT, ("random device not supported " + __token).c_str()); - int error = nacl_secure_random_init(); - if (error) - std::__throw_system_error(error, ("random device failed to open " + __token).c_str()); -} - -random_device::~random_device() {} - -unsigned random_device::operator()() { - unsigned r; - size_t n = sizeof(r); - size_t bytes_written; - int error = nacl_secure_random(&r, n, &bytes_written); - if (error != 0) - std::__throw_system_error(error, "random_device failed getting bytes"); - else if (bytes_written != n) - std::__throw_runtime_error("random_device failed to obtain enough bytes"); - return r; -} - #elif defined(_LIBCPP_USING_WIN32_RANDOM) random_device::random_device(const string& __token) { diff --git a/lib/libcxx/src/string.cpp b/lib/libcxx/src/string.cpp @@ -20,7 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14 template <bool> struct __basic_string_common; @@ -35,45 +35,30 @@ struct __basic_string_common<true> { void __basic_string_common<true>::__throw_length_error() const { std::__throw_length_error("basic_string"); } void __basic_string_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("basic_string"); } -#endif // _LIBCPP_ABI_DO_NOT_EXPORT_BASIC_STRING_COMMON +#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 14 // Define legacy ABI functions // --------------------------- -#ifndef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21 +// This initializes the string with [__s, __s + __sz), but capacity() == __reserve. Assumes that __reserve >= __sz. template <class _CharT, class _Traits, class _Allocator> void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz, size_type __reserve) { - if (__libcpp_is_constant_evaluated()) - __rep_ = __rep(); - if (__reserve > max_size()) - __throw_length_error(); - pointer __p; - if (__fits_in_sso(__reserve)) { - __set_short_size(__sz); - __p = __get_short_pointer(); - } else { - auto __allocation = std::__allocate_at_least(__alloc_, __recommend(__reserve) + 1); - __p = __allocation.ptr; - __begin_lifetime(__p, __allocation.count); - __set_long_pointer(__p); - __set_long_cap(__allocation.count); - __set_long_size(__sz); - } + pointer __p = __init_internal_buffer(__reserve); + __annotate_delete(); + __set_size(__sz); traits_type::copy(std::__to_address(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); __annotate_new(__sz); } -# define STRING_LEGACY_API(CharT) \ - template _LIBCPP_EXPORTED_FROM_ABI void basic_string<CharT>::__init(const value_type*, size_type, size_type) - -STRING_LEGACY_API(char); +template _LIBCPP_EXPORTED_FROM_ABI void basic_string<char>::__init(const value_type*, size_type, size_type); # if _LIBCPP_HAS_WIDE_CHARACTERS -STRING_LEGACY_API(wchar_t); +template _LIBCPP_EXPORTED_FROM_ABI void basic_string<wchar_t>::__init(const value_type*, size_type, size_type); # endif -#endif // _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION +#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 21 #define _LIBCPP_EXTERN_TEMPLATE_DEFINE(...) template _LIBCPP_EXPORTED_FROM_ABI __VA_ARGS__; #ifdef _LIBCPP_ABI_STRING_OPTIMIZED_EXTERNAL_INSTANTIATION diff --git a/lib/libcxx/src/support/runtime/exception_fallback.ipp b/lib/libcxx/src/support/runtime/exception_fallback.ipp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include <__verbose_abort> +#include <exception> +#include "include/atomic_support.h" namespace std { diff --git a/lib/libcxx/src/support/runtime/exception_glibcxx.ipp b/lib/libcxx/src/support/runtime/exception_glibcxx.ipp @@ -11,6 +11,9 @@ # error header can only be used when targeting libstdc++ or libsupc++ #endif +#include <exception> +#include <new> + namespace std { bad_alloc::bad_alloc() noexcept {} diff --git a/lib/libcxx/src/support/runtime/exception_libcxxabi.ipp b/lib/libcxx/src/support/runtime/exception_libcxxabi.ipp @@ -7,6 +7,10 @@ // //===----------------------------------------------------------------------===// +#include <exception> + +#include <cxxabi.h> + #ifndef _LIBCPPABI_VERSION # error this header can only be used with libc++abi #endif @@ -17,9 +21,9 @@ bool uncaught_exception() noexcept { return uncaught_exceptions() > 0; } int uncaught_exceptions() noexcept { #if _LIBCPPABI_VERSION > 1001 - return __cxa_uncaught_exceptions(); + return abi::__cxa_uncaught_exceptions(); #else - return __cxa_uncaught_exception() ? 1 : 0; + return abi::__cxa_uncaught_exception() ? 1 : 0; #endif } diff --git a/lib/libcxx/src/support/runtime/exception_libcxxrt.ipp b/lib/libcxx/src/support/runtime/exception_libcxxrt.ipp @@ -11,6 +11,8 @@ # error this header may only be used when targeting libcxxrt #endif +#include <exception> + namespace std { bad_exception::~bad_exception() noexcept {} diff --git a/lib/libcxx/src/support/runtime/exception_msvc.ipp b/lib/libcxx/src/support/runtime/exception_msvc.ipp @@ -12,6 +12,8 @@ #endif #include <__verbose_abort> +#include <exception> +#include <new> extern "C" { typedef void(__cdecl* terminate_handler)(); diff --git a/lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/lib/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp @@ -7,22 +7,21 @@ // //===----------------------------------------------------------------------===// -#ifndef HAVE_DEPENDENT_EH_ABI -# error this header may only be used with libc++abi or libcxxrt -#endif +#include <cxxabi.h> +#include <exception> namespace std { -exception_ptr::~exception_ptr() noexcept { __cxa_decrement_exception_refcount(__ptr_); } +exception_ptr::~exception_ptr() noexcept { abi::__cxa_decrement_exception_refcount(__ptr_); } exception_ptr::exception_ptr(const exception_ptr& other) noexcept : __ptr_(other.__ptr_) { - __cxa_increment_exception_refcount(__ptr_); + abi::__cxa_increment_exception_refcount(__ptr_); } exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept { if (__ptr_ != other.__ptr_) { - __cxa_increment_exception_refcount(other.__ptr_); - __cxa_decrement_exception_refcount(__ptr_); + abi::__cxa_increment_exception_refcount(other.__ptr_); + abi::__cxa_decrement_exception_refcount(__ptr_); __ptr_ = other.__ptr_; } return *this; @@ -31,7 +30,7 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept { exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept { exception_ptr ptr; ptr.__ptr_ = __e; - __cxa_increment_exception_refcount(ptr.__ptr_); + abi::__cxa_increment_exception_refcount(ptr.__ptr_); return ptr; } @@ -51,12 +50,12 @@ exception_ptr current_exception() noexcept { // this whole function would be just: // return exception_ptr(__cxa_current_primary_exception()); exception_ptr ptr; - ptr.__ptr_ = __cxa_current_primary_exception(); + ptr.__ptr_ = abi::__cxa_current_primary_exception(); return ptr; } void rethrow_exception(exception_ptr p) { - __cxa_rethrow_primary_exception(p.__ptr_); + abi::__cxa_rethrow_primary_exception(p.__ptr_); // if p.__ptr_ is NULL, above returns so we terminate terminate(); } diff --git a/lib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/lib/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp @@ -16,6 +16,8 @@ // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr) // function. +#include <exception> + namespace std { namespace __exception_ptr { diff --git a/lib/libcxx/src/support/runtime/exception_pointer_msvc.ipp b/lib/libcxx/src/support/runtime/exception_pointer_msvc.ipp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include <exception> #include <stdio.h> #include <stdlib.h> diff --git a/lib/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp b/lib/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include <__verbose_abort> +#include <exception> namespace std { diff --git a/lib/libcxx/src/support/win32/locale_win32.cpp b/lib/libcxx/src/support/win32/locale_win32.cpp @@ -144,7 +144,7 @@ int __snprintf(char* ret, size_t n, __locale_t loc, const char* format, ...) { // Like sprintf, but when return value >= 0 it returns // a pointer to a malloc'd string in *sptr. // If return >= 0, use free to delete *sptr. -int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) { +static int __libcpp_vasprintf(char** sptr, const char* __restrict format, va_list ap) { *sptr = nullptr; // Query the count required. va_list ap_copy; diff --git a/lib/libcxx/src/system_error.cpp b/lib/libcxx/src/system_error.cpp @@ -95,6 +95,8 @@ std::optional<errc> __win_err_to_errc(int err) { return errc::no_lock_available; case ERROR_NEGATIVE_SEEK: return errc::invalid_argument; + case ERROR_NETNAME_DELETED: + return errc::no_such_file_or_directory; case ERROR_NOACCESS: return errc::permission_denied; case ERROR_NOT_ENOUGH_MEMORY: diff --git a/lib/libcxx/src/thread.cpp b/lib/libcxx/src/thread.cpp @@ -74,9 +74,7 @@ unsigned thread::hardware_concurrency() noexcept { return 0; return static_cast<unsigned>(result); #elif defined(_LIBCPP_WIN32API) - SYSTEM_INFO info; - GetSystemInfo(&info); - return info.dwNumberOfProcessors; + return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS)); #else // defined(CTL_HW) && defined(HW_NCPU) // TODO: grovel through /proc or check cpuid on x86 and similar // instructions on other architectures. diff --git a/lib/libcxx/src/valarray.cpp b/lib/libcxx/src/valarray.cpp @@ -10,8 +10,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -// These two symbols are part of the v1 ABI but not part of the >=v2 ABI. -#if _LIBCPP_ABI_VERSION == 1 +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 9 template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::valarray(size_t); template _LIBCPP_EXPORTED_FROM_ABI valarray<size_t>::~valarray(); #endif diff --git a/lib/libcxx/src/vector.cpp b/lib/libcxx/src/vector.cpp @@ -10,7 +10,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#ifndef _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON +#if _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15 template <bool> struct __vector_base_common; @@ -25,6 +25,6 @@ void __vector_base_common<true>::__throw_length_error() const { std::__throw_len void __vector_base_common<true>::__throw_out_of_range() const { std::__throw_out_of_range("vector"); } -#endif // _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON +#endif // _LIBCPP_AVAILABILITY_MINIMUM_HEADER_VERSION < 15 _LIBCPP_END_NAMESPACE_STD diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig @@ -538,11 +538,20 @@ pub fn addCxxArgs( // Compilation.addCCArgs. This option makes it use serial backend which // is simple and works everywhere. try cflags.append("-D_LIBCPP_PSTL_BACKEND_SERIAL"); - try cflags.append(switch (optimize_mode) { - .Debug => "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG", - .ReleaseFast, .ReleaseSmall => "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE", - .ReleaseSafe => "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST", - }); + switch (optimize_mode) { + .Debug => { + try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG"); + try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE"); + }, + .ReleaseFast, .ReleaseSmall => { + try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE"); + try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_IGNORE"); + }, + .ReleaseSafe => { + try cflags.append("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST"); + try cflags.append("-D_LIBCPP_ASSERTION_SEMANTIC_DEFAULT=_LIBCPP_ASSERTION_SEMANTIC_ENFORCE"); + }, + } if (target.isGnuLibC()) { // glibc 2.16 introduced aligned_alloc if (target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {