Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions libcxx/include/__flat_map/flat_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,15 @@ class flat_map {
__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());
}
Expand Down Expand Up @@ -736,14 +745,17 @@ class flat_map {
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 {
Expand Down Expand Up @@ -876,7 +888,8 @@ class flat_map {
__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);
}

Expand Down
23 changes: 18 additions & 5 deletions libcxx/include/__flat_map/flat_multimap.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,15 @@ class flat_multimap {
__append_sort_merge</*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_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());
}
Expand Down Expand Up @@ -628,13 +637,17 @@ class flat_multimap {
return iterator(std::move(__key_it), std::move(__mapped_it));
}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void swap(flat_multimap& __y) noexcept {
// warning: The spec has unconditional noexcept, which means that
// if any of the following functions throw an exception,
// std::terminate will be called
_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 _LIBCPP_CONSTEXPR_SINCE_CXX26 void clear() noexcept {
Expand Down Expand Up @@ -771,7 +784,7 @@ class flat_multimap {
}

friend _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 void
swap(flat_multimap& __x, flat_multimap& __y) noexcept {
swap(flat_multimap& __x, flat_multimap& __y) noexcept(noexcept(__x.swap(__y))) {
__x.swap(__y);
}

Expand Down
27 changes: 20 additions & 7 deletions libcxx/include/__flat_set/flat_multiset.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,15 @@ class flat_multiset {
__append_sort_merge</*WasSorted = */ false>(std::forward<_Range>(__range));
}

template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI void insert_range(sorted_equivalent_t, _Range&& __range) {
if constexpr (ranges::sized_range<_Range>) {
__reserve(ranges::size(__range));
}

__append_sort_merge</*WasSorted = */ true>(std::forward<_Range>(__range));
}

_LIBCPP_HIDE_FROM_ABI 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) {
Expand Down Expand Up @@ -454,13 +463,15 @@ class flat_multiset {
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 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(); }
Expand Down Expand Up @@ -578,7 +589,9 @@ class flat_multiset {
__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 void swap(flat_multiset& __x, flat_multiset& __y) noexcept(noexcept(__x.swap(__y))) {
__x.swap(__y);
}

private:
template <bool _WasSorted, class... _Args>
Expand All @@ -590,7 +603,7 @@ class flat_multiset {
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();
Expand Down
24 changes: 18 additions & 6 deletions libcxx/include/__flat_set/flat_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,15 @@ class flat_set {
__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());
}
Expand Down Expand Up @@ -516,13 +525,15 @@ class flat_set {
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(); }
Expand Down Expand Up @@ -647,7 +658,8 @@ class flat_set {
__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);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20

// <flat_map>

// template<container-compatible-range<value_type> R>
// void insert_range(sorted_unique, R&& rg);

#include <algorithm>
#include <deque>
#include <flat_map>
#include <functional>
#include <ranges>
#include <vector>

#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "MoveOnly.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"

// test constraint container-compatible-range
template <class M, class R>
concept CanInsertRangeSortedUnique = requires(M m, R&& r) { m.insert_range(std::sorted_unique, std::forward<R>(r)); };

using Map = std::flat_map<int, double>;

static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<int, double>*>>);
static_assert(CanInsertRangeSortedUnique<Map, std::ranges::subrange<std::pair<short, double>*>>);
static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<int*>>);
static_assert(!CanInsertRangeSortedUnique<Map, std::ranges::subrange<double*>>);

template <class KeyContainer, class ValueContainer>
constexpr void test() {
using Key = typename KeyContainer::value_type;
using Value = typename ValueContainer::value_type;

{
using P = std::pair<int, int>;
using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
using It = forward_iterator<const P*>;
M m = {{10, 1}, {8, 2}, {5, 3}, {2, 4}, {1, 5}};
P ar[] = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
std::ranges::subrange r = {It(ar), It(ar + 5)};
static_assert(std::ranges::common_range<decltype(r)>);
m.insert_range(std::sorted_unique, r);
assert((m == M{{1, 5}, {2, 4}, {3, 1}, {4, 3}, {5, 3}, {8, 2}, {9, 6}, {10, 1}}));
}
{
using P = std::pair<int, int>;
using M = std::flat_map<Key, Value, std::greater<>, KeyContainer, ValueContainer>;
using It = cpp20_input_iterator<const P*>;
M m = {{8, 1}, {5, 2}, {3, 3}, {2, 4}};
P ar[] = {{9, 6}, {5, 5}, {4, 3}, {3, 1}, {1, 2}};
std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 5))};
static_assert(!std::ranges::common_range<decltype(r)>);
m.insert_range(std::sorted_unique, r);
assert((m == M{{1, 2}, {2, 4}, {3, 3}, {4, 3}, {5, 2}, {8, 1}, {9, 6}}));
}
{
// was empty
using P = std::pair<int, int>;
using M = std::flat_map<Key, Value, std::less<Key>, KeyContainer, ValueContainer>;
M m;
P ar[] = {{1, 2}, {3, 1}, {4, 3}, {5, 5}, {9, 6}};
m.insert_range(std::sorted_unique, ar);
assert(std::ranges::equal(m, ar));
}
}

constexpr bool test() {
test<std::vector<int>, std::vector<int>>();
#ifndef __cpp_lib_constexpr_deque
if (!TEST_IS_CONSTANT_EVALUATED)
#endif
{
test<std::deque<int>, std::vector<int>>();
}
test<MinSequenceContainer<int>, MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>, std::vector<int, min_allocator<int>>>();
{
// Items are forwarded correctly from the input range
std::pair<MoveOnly, MoveOnly> a[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
std::flat_map<MoveOnly, MoveOnly> m;
m.insert_range(std::sorted_unique, a | std::views::as_rvalue);
std::pair<MoveOnly, MoveOnly> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
assert(std::ranges::equal(m, expected));
}
{
// The element type of the range doesn't need to be std::pair
std::pair<int, int> pa[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
std::vector<std::reference_wrapper<std::pair<int, int>>> a(pa, pa + 4);
std::flat_map<int, int> m;
m.insert_range(std::sorted_unique, a);
std::pair<int, int> expected[] = {{1, 1}, {3, 3}, {4, 4}, {5, 5}};
assert(std::ranges::equal(m, expected));
}
if (!TEST_IS_CONSTANT_EVALUATED) {
auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(std::sorted_unique, newValues); };
test_insert_range_exception_guarantee(insert_func);
}

return true;
}

int main(int, char**) {
test();
#if TEST_STD_VER >= 26
static_assert(test());
#endif

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// `check_assertion.h` requires Unix headers and regex support.
// REQUIRES: has-unix-headers
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions

Expand All @@ -17,7 +15,7 @@
// void swap(flat_map& y) noexcept;
// friend void swap(flat_map& x, flat_map& y) noexcept

// Test that std::terminate is called if any exception is thrown during swap
// Test that the variants are hold if any exception is thrown during swap

#include <flat_map>
#include <cassert>
Expand All @@ -27,7 +25,6 @@

#include "test_macros.h"
#include "../helpers.h"
#include "check_assertion.h"

template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
Expand All @@ -42,8 +39,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m1.emplace(2, 2);
m2.emplace(3, 3);
m2.emplace(4, 4);
// swap is noexcept
EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
try {
swap_function(m1, m2);
assert(false);
} catch (int) {
check_invariant(m1);
check_invariant(m2);
LIBCPP_ASSERT(m1.size() == 0);
LIBCPP_ASSERT(m2.size() == 0);
}
}

{
Expand All @@ -58,8 +62,15 @@ void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
m2.emplace(3, 3);
m2.emplace(4, 4);

// swap is noexcept
EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
try {
swap_function(m1, m2);
assert(false);
} catch (int) {
check_invariant(m1);
check_invariant(m2);
LIBCPP_ASSERT(m1.size() == 0);
LIBCPP_ASSERT(m2.size() == 0);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};

static_assert(NoExceptAdlSwap<std::flat_map<int, int>>);

static_assert(NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, std::vector<int>, std::vector<int>>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(
NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
!NoExceptAdlSwap<std::flat_map<int, int, std::less<int>, ThrowOnMoveContainer<int>, ThrowOnMoveContainer<int>>>);
#endif

template <class KeyContainer, class ValueContainer>
Expand Down
Loading
Loading