[libc++] implement std::flat_set (#125241)

Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
This commit is contained in:
Hui 2025-03-23 14:45:21 +00:00 committed by GitHub
parent 0b181de206
commit 2f1416bbcd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
96 changed files with 9420 additions and 10 deletions

View File

@ -43,6 +43,7 @@ Implemented Papers
- P1361R2: Integration of chrono with text formatting (`Github <https://github.com/llvm/llvm-project/issues/100014>`__)
- P2255R2: A type trait to detect reference binding to temporary (implemented the type traits only) (`Github <https://github.com/llvm/llvm-project/issues/105180>`__)
- P2562R1: ``constexpr`` Stable Sorting (`Github <https://github.com/llvm/llvm-project/issues/105360>`__)
- P1222R4: A Standard ``flat_set`` is partially implemented and ``flat_set`` is provided (`Github <https://github.com/llvm/llvm-project/issues/105193>`__)
Improvements and New Features
-----------------------------

View File

@ -54,7 +54,7 @@
"`P0009R18 <https://wg21.link/P0009R18>`__","mdspan: A Non-Owning Multidimensional Array Reference","2022-07 (Virtual)","|Complete|","18",""
"`P0429R9 <https://wg21.link/P0429R9>`__","A Standard ``flat_map``","2022-07 (Virtual)","|Complete|","20",""
"`P1169R4 <https://wg21.link/P1169R4>`__","``static operator()``","2022-07 (Virtual)","|Complete|","16",""
"`P1222R4 <https://wg21.link/P1222R4>`__","A Standard ``flat_set``","2022-07 (Virtual)","","",""
"`P1222R4 <https://wg21.link/P1222R4>`__","A Standard ``flat_set``","2022-07 (Virtual)","|In progress|","",""
"`P1223R5 <https://wg21.link/P1223R5>`__","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","2022-07 (Virtual)","|Complete|","19",""
"`P1467R9 <https://wg21.link/P1467R9>`__","Extended ``floating-point`` types and standard names","2022-07 (Virtual)","","",""
"`P1642R11 <https://wg21.link/P1642R11>`__","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","2022-07 (Virtual)","","",""

1 Paper # Paper Name Meeting Status First released version Notes
54 `P0009R18 <https://wg21.link/P0009R18>`__ mdspan: A Non-Owning Multidimensional Array Reference 2022-07 (Virtual) |Complete| 18
55 `P0429R9 <https://wg21.link/P0429R9>`__ A Standard ``flat_map`` 2022-07 (Virtual) |Complete| 20
56 `P1169R4 <https://wg21.link/P1169R4>`__ ``static operator()`` 2022-07 (Virtual) |Complete| 16
57 `P1222R4 <https://wg21.link/P1222R4>`__ A Standard ``flat_set`` 2022-07 (Virtual) |In progress|
58 `P1223R5 <https://wg21.link/P1223R5>`__ ``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()`` 2022-07 (Virtual) |Complete| 19
59 `P1467R9 <https://wg21.link/P1467R9>`__ Extended ``floating-point`` types and standard names 2022-07 (Virtual)
60 `P1642R11 <https://wg21.link/P1642R11>`__ Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]`` 2022-07 (Virtual)

View File

@ -369,6 +369,8 @@ set(files
__flat_map/sorted_equivalent.h
__flat_map/sorted_unique.h
__flat_map/utils.h
__flat_set/flat_set.h
__flat_set/ra_iterator.h
__format/buffer.h
__format/concepts.h
__format/container_adaptor.h
@ -995,6 +997,7 @@ set(files
fenv.h
filesystem
flat_map
flat_set
float.h
format
forward_list

View File

@ -0,0 +1,846 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___FLAT_SET_FLAT_SET_H
#define _LIBCPP___FLAT_SET_FLAT_SET_H
#include <__algorithm/lexicographical_compare_three_way.h>
#include <__algorithm/min.h>
#include <__algorithm/ranges_adjacent_find.h>
#include <__algorithm/ranges_equal.h>
#include <__algorithm/ranges_inplace_merge.h>
#include <__algorithm/ranges_lower_bound.h>
#include <__algorithm/ranges_partition_point.h>
#include <__algorithm/ranges_sort.h>
#include <__algorithm/ranges_unique.h>
#include <__algorithm/ranges_upper_bound.h>
#include <__algorithm/remove_if.h>
#include <__assert>
#include <__compare/synth_three_way.h>
#include <__concepts/swappable.h>
#include <__config>
#include <__cstddef/ptrdiff_t.h>
#include <__flat_map/sorted_unique.h>
#include <__flat_set/ra_iterator.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>
#include <__memory/uses_allocator_construction.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/container_compatible_range.h>
#include <__ranges/drop_view.h>
#include <__ranges/from_range.h>
#include <__ranges/ref_view.h>
#include <__ranges/size.h>
#include <__ranges/subrange.h>
#include <__type_traits/conjunction.h>
#include <__type_traits/container_traits.h>
#include <__type_traits/invoke.h>
#include <__type_traits/is_allocator.h>
#include <__type_traits/is_const.h>
#include <__type_traits/is_nothrow_constructible.h>
#include <__type_traits/is_same.h>
#include <__type_traits/remove_reference.h>
#include <__utility/as_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>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
#if _LIBCPP_STD_VER >= 23
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Key, class _Compare = less<_Key>, class _KeyContainer = vector<_Key>>
class flat_set {
template <class, class, class>
friend class flat_set;
static_assert(is_same_v<_Key, typename _KeyContainer::value_type>);
static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
using __key_iterator _LIBCPP_NODEBUG = typename _KeyContainer::const_iterator;
public:
// types
using key_type = _Key;
using value_type = _Key;
using key_compare = __type_identity_t<_Compare>;
using value_compare = _Compare;
using reference = value_type&;
using const_reference = const value_type&;
using size_type = typename _KeyContainer::size_type;
using difference_type = typename _KeyContainer::difference_type;
using iterator = __ra_iterator<flat_set, typename _KeyContainer::const_iterator>;
using const_iterator = iterator;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using container_type = _KeyContainer;
public:
// [flat.set.cons], construct/copy/destroy
_LIBCPP_HIDE_FROM_ABI
flat_set() noexcept(is_nothrow_default_constructible_v<_KeyContainer> && is_nothrow_default_constructible_v<_Compare>)
: __keys_(), __compare_() {}
_LIBCPP_HIDE_FROM_ABI flat_set(const flat_set&) = default;
_LIBCPP_HIDE_FROM_ABI flat_set(flat_set&& __other) noexcept(
is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)
# if _LIBCPP_HAS_EXCEPTIONS
try
# endif // _LIBCPP_HAS_EXCEPTIONS
: __keys_(std::move(__other.__keys_)), __compare_(std::move(__other.__compare_)) {
__other.clear();
# if _LIBCPP_HAS_EXCEPTIONS
} catch (...) {
__other.clear();
// gcc does not like the `throw` keyword in a conditionally noexcept function
if constexpr (!(is_nothrow_move_constructible_v<_KeyContainer> && is_nothrow_move_constructible_v<_Compare>)) {
throw;
}
# endif // _LIBCPP_HAS_EXCEPTIONS
}
_LIBCPP_HIDE_FROM_ABI explicit flat_set(const key_compare& __comp) : __keys_(), __compare_(__comp) {}
_LIBCPP_HIDE_FROM_ABI explicit flat_set(container_type __keys, const key_compare& __comp = key_compare())
: __keys_(std::move(__keys)), __compare_(__comp) {
__sort_and_unique();
}
_LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, container_type __keys, const key_compare& __comp = key_compare())
: __keys_(std::move(__keys)), __compare_(__comp) {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
_LIBCPP_HIDE_FROM_ABI
flat_set(_InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare())
: __keys_(), __compare_(__comp) {
insert(__first, __last);
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const key_compare& __comp = key_compare())
: __keys_(__first, __last), __compare_(__comp) {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg)
: flat_set(from_range, std::forward<_Range>(__rg), key_compare()) {}
template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI flat_set(from_range_t, _Range&& __rg, const key_compare& __comp) : flat_set(__comp) {
insert_range(std::forward<_Range>(__rg));
}
_LIBCPP_HIDE_FROM_ABI flat_set(initializer_list<value_type> __il, const key_compare& __comp = key_compare())
: flat_set(__il.begin(), __il.end(), __comp) {}
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_t, initializer_list<value_type> __il, const key_compare& __comp = key_compare())
: flat_set(sorted_unique, __il.begin(), __il.end(), __comp) {}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI explicit flat_set(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_set(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_set(const container_type& __keys, const _Allocator& __alloc)
: __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_() {
__sort_and_unique();
}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI flat_set(const container_type& __keys, const key_compare& __comp, const _Allocator& __alloc)
: __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_(__comp) {
__sort_and_unique();
}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, const container_type& __keys, const _Allocator& __alloc)
: __keys_(std::make_obj_using_allocator<container_type>(__alloc, __keys)), __compare_() {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_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(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI flat_set(const flat_set& __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_set(flat_set&& __other, const _Allocator& __alloc)
# if _LIBCPP_HAS_EXCEPTIONS
try
# endif // _LIBCPP_HAS_EXCEPTIONS
: __keys_(std::make_obj_using_allocator<container_type>(__alloc, std::move(__other.__keys_))),
__compare_(std::move(__other.__compare_)) {
__other.clear();
# if _LIBCPP_HAS_EXCEPTIONS
} catch (...) {
__other.clear();
throw;
# endif // _LIBCPP_HAS_EXCEPTIONS
}
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value)
_LIBCPP_HIDE_FROM_ABI flat_set(_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
flat_set(_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);
}
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value)
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_t, _InputIterator __first, _InputIterator __last, const _Allocator& __alloc)
: __keys_(std::make_obj_using_allocator<container_type>(__alloc, __first, __last)), __compare_() {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <class _InputIterator, class _Allocator>
requires(__has_input_iterator_category<_InputIterator>::value && uses_allocator<container_type, _Allocator>::value)
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_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(
__is_sorted_and_unique(__keys_), "Either the key container is not sorted or it contains duplicates");
}
template <_ContainerCompatibleRange<value_type> _Range, class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI flat_set(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_set(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_set(initializer_list<value_type> __il, const _Allocator& __alloc)
: flat_set(__il.begin(), __il.end(), __alloc) {}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI
flat_set(initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc)
: flat_set(__il.begin(), __il.end(), __comp, __alloc) {}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI flat_set(sorted_unique_t, initializer_list<value_type> __il, const _Allocator& __alloc)
: flat_set(sorted_unique, __il.begin(), __il.end(), __alloc) {}
template <class _Allocator>
requires uses_allocator<container_type, _Allocator>::value
_LIBCPP_HIDE_FROM_ABI
flat_set(sorted_unique_t, initializer_list<value_type> __il, const key_compare& __comp, const _Allocator& __alloc)
: flat_set(sorted_unique, __il.begin(), __il.end(), __comp, __alloc) {}
_LIBCPP_HIDE_FROM_ABI flat_set& operator=(initializer_list<value_type> __il) {
clear();
insert(__il);
return *this;
}
_LIBCPP_HIDE_FROM_ABI flat_set& operator=(const flat_set&) = default;
_LIBCPP_HIDE_FROM_ABI flat_set& operator=(flat_set&& __other) noexcept(
is_nothrow_move_assignable_v<_KeyContainer> && is_nothrow_move_assignable_v<_Compare>) {
// No matter what happens, we always want to clear the other container before returning
// since we moved from it
auto __clear_other_guard = std::__make_scope_guard([&]() noexcept { __other.clear() /* noexcept */; });
{
// If an exception is thrown, we have no choice but to clear *this to preserve invariants
auto __on_exception = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
__keys_ = std::move(__other.__keys_);
__compare_ = std::move(__other.__compare_);
__on_exception.__complete();
}
return *this;
}
// iterators
_LIBCPP_HIDE_FROM_ABI iterator begin() noexcept { return 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()); }
_LIBCPP_HIDE_FROM_ABI reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
_LIBCPP_HIDE_FROM_ABI const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
_LIBCPP_HIDE_FROM_ABI reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
_LIBCPP_HIDE_FROM_ABI const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
_LIBCPP_HIDE_FROM_ABI const_iterator cbegin() const noexcept { return begin(); }
_LIBCPP_HIDE_FROM_ABI const_iterator cend() const noexcept { return end(); }
_LIBCPP_HIDE_FROM_ABI const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
_LIBCPP_HIDE_FROM_ABI const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
// [flat.set.capacity], capacity
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool empty() const noexcept { return __keys_.empty(); }
_LIBCPP_HIDE_FROM_ABI size_type size() const noexcept { return __keys_.size(); }
_LIBCPP_HIDE_FROM_ABI size_type max_size() const noexcept { return __keys_.max_size(); }
// [flat.set.modifiers], modifiers
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> emplace(_Args&&... __args) {
if constexpr (sizeof...(__args) == 1 && (is_same_v<remove_cvref_t<_Args>, _Key> && ...)) {
return __emplace(std::forward<_Args>(__args)...);
} else {
return __emplace(_Key(std::forward<_Args>(__args)...));
}
}
template <class... _Args>
_LIBCPP_HIDE_FROM_ABI 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 {
return __emplace_hint(std::move(__hint), _Key(std::forward<_Args>(__args)...));
}
}
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(const value_type& __x) { return emplace(__x); }
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(value_type&& __x) { return emplace(std::move(__x)); }
template <class _Kp>
requires(__is_transparent_v<_Compare> && is_constructible_v<value_type, _Kp>)
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> insert(_Kp&& __x) {
return emplace(std::forward<_Kp>(__x));
}
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, const value_type& __x) {
return emplace_hint(__hint, __x);
}
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, value_type&& __x) {
return emplace_hint(__hint, std::move(__x));
}
template <class _Kp>
requires(__is_transparent_v<_Compare> && is_constructible_v<value_type, _Kp>)
_LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, _Kp&& __x) {
return emplace_hint(__hint, std::forward<_Kp>(__x));
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
_LIBCPP_HIDE_FROM_ABI void insert(_InputIterator __first, _InputIterator __last) {
if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) {
__reserve(__last - __first);
}
__append_sort_merge_unique</*WasSorted = */ false>(std::move(__first), std::move(__last));
}
template <class _InputIterator>
requires __has_input_iterator_category<_InputIterator>::value
_LIBCPP_HIDE_FROM_ABI void insert(sorted_unique_t, _InputIterator __first, _InputIterator __last) {
if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>) {
__reserve(__last - __first);
}
__append_sort_merge_unique</*WasSorted = */ true>(std::move(__first), std::move(__last));
}
template <_ContainerCompatibleRange<value_type> _Range>
_LIBCPP_HIDE_FROM_ABI void insert_range(_Range&& __range) {
if constexpr (ranges::sized_range<_Range>) {
__reserve(ranges::size(__range));
}
__append_sort_merge_unique</*WasSorted = */ false>(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_unique_t, initializer_list<value_type> __il) {
insert(sorted_unique, __il.begin(), __il.end());
}
_LIBCPP_HIDE_FROM_ABI container_type extract() && {
auto __guard = std::__make_scope_guard([&]() noexcept { clear() /* noexcept */; });
auto __ret = std::move(__keys_);
return __ret;
}
_LIBCPP_HIDE_FROM_ABI void replace(container_type&& __keys) {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__keys), "Either the key container is not sorted or it contains duplicates");
auto __guard = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
__keys_ = std::move(__keys);
__guard.__complete();
}
_LIBCPP_HIDE_FROM_ABI iterator erase(iterator __position) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
auto __key_iter = __keys_.erase(__position.__base());
__on_failure.__complete();
return iterator(__key_iter);
}
// The following overload is the same as the iterator overload
// iterator erase(const_iterator __position);
_LIBCPP_HIDE_FROM_ABI size_type erase(const key_type& __x) {
auto __iter = find(__x);
if (__iter != end()) {
erase(__iter);
return 1;
}
return 0;
}
template <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) {
auto [__first, __last] = equal_range(__x);
auto __res = __last - __first;
erase(__first, __last);
return __res;
}
_LIBCPP_HIDE_FROM_ABI iterator erase(const_iterator __first, const_iterator __last) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
auto __key_it = __keys_.erase(__first.__base(), __last.__base());
__on_failure.__complete();
return iterator(std::move(__key_it));
}
_LIBCPP_HIDE_FROM_ABI void swap(flat_set& __y) noexcept {
// warning: The spec has unconditional noexcept, which means that
// if any of the following functions throw an exception,
// std::terminate will be called.
// This is discussed in P2767, which hasn't been voted on yet.
ranges::swap(__compare_, __y.__compare_);
ranges::swap(__keys_, __y.__keys_);
}
_LIBCPP_HIDE_FROM_ABI void clear() noexcept { __keys_.clear(); }
// observers
_LIBCPP_HIDE_FROM_ABI key_compare key_comp() const { return __compare_; }
_LIBCPP_HIDE_FROM_ABI value_compare value_comp() const { return __compare_; }
// set operations
_LIBCPP_HIDE_FROM_ABI iterator find(const key_type& __x) { return __find_impl(*this, __x); }
_LIBCPP_HIDE_FROM_ABI const_iterator find(const key_type& __x) const { return __find_impl(*this, __x); }
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI 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 {
return __find_impl(*this, __x);
}
_LIBCPP_HIDE_FROM_ABI 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 size_type count(const _Kp& __x) const {
return contains(__x) ? 1 : 0;
}
_LIBCPP_HIDE_FROM_ABI bool contains(const key_type& __x) const { return find(__x) != end(); }
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI bool contains(const _Kp& __x) const {
return find(__x) != end();
}
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const key_type& __x) {
return iterator(ranges::lower_bound(std::as_const(__keys_), __x, __compare_));
}
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const key_type& __x) const {
return const_iterator(ranges::lower_bound(__keys_, __x, __compare_));
}
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI iterator lower_bound(const _Kp& __x) {
return iterator(ranges::lower_bound(std::as_const(__keys_), __x, __compare_));
}
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI const_iterator lower_bound(const _Kp& __x) const {
return const_iterator(ranges::lower_bound(__keys_, __x, __compare_));
}
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const key_type& __x) {
return iterator(ranges::upper_bound(std::as_const(__keys_), __x, __compare_));
}
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const key_type& __x) const {
return const_iterator(ranges::upper_bound(__keys_, __x, __compare_));
}
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI iterator upper_bound(const _Kp& __x) {
return iterator(ranges::upper_bound(std::as_const(__keys_), __x, __compare_));
}
template <class _Kp>
requires __is_transparent_v<_Compare>
_LIBCPP_HIDE_FROM_ABI const_iterator upper_bound(const _Kp& __x) const {
return const_iterator(ranges::upper_bound(__keys_, __x, __compare_));
}
_LIBCPP_HIDE_FROM_ABI 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 {
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) {
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 {
return __equal_range_impl(*this, __x);
}
friend _LIBCPP_HIDE_FROM_ABI bool operator==(const flat_set& __x, const flat_set& __y) {
return ranges::equal(__x, __y);
}
friend _LIBCPP_HIDE_FROM_ABI auto operator<=>(const flat_set& __x, const flat_set& __y) {
return std::lexicographical_compare_three_way(
__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way);
}
friend _LIBCPP_HIDE_FROM_ABI void swap(flat_set& __x, flat_set& __y) noexcept { __x.swap(__y); }
private:
_LIBCPP_HIDE_FROM_ABI bool __is_sorted_and_unique(auto&& __key_container) const {
auto __greater_or_equal_to = [this](const auto& __x, const auto& __y) { return !__compare_(__x, __y); };
return ranges::adjacent_find(__key_container, __greater_or_equal_to) == ranges::end(__key_container);
}
// This function is only used in constructors. So there is not exception handling in this function.
// If the function exits via an exception, there will be no flat_set object constructed, thus, there
// is no invariant state to preserve
_LIBCPP_HIDE_FROM_ABI void __sort_and_unique() {
ranges::sort(__keys_, __compare_);
auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin();
__keys_.erase(__dup_start, __keys_.end());
}
template <class _InputIterator>
_LIBCPP_HIDE_FROM_ABI void __append(_InputIterator __first, _InputIterator __last) {
__keys_.insert(__keys_.end(), std::move(__first), std::move(__last));
}
template <class _Range>
_LIBCPP_HIDE_FROM_ABI void __append(_Range&& __rng) {
if constexpr (requires { __keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng)); }) {
// C++23 Sequence Container should have insert_range member function
// Note that not all Sequence Containers provide append_range.
__keys_.insert_range(__keys_.end(), std::forward<_Range>(__rng));
} else if constexpr (ranges::common_range<_Range>) {
__keys_.insert(__keys_.end(), ranges::begin(__rng), ranges::end(__rng));
} else {
for (auto&& __x : __rng) {
__keys_.insert(__keys_.end(), std::forward<decltype(__x)>(__x));
}
}
}
template <bool _WasSorted, class... _Args>
_LIBCPP_HIDE_FROM_ABI void __append_sort_merge_unique(_Args&&... __args) {
auto __on_failure = std::__make_exception_guard([&]() noexcept { clear() /* noexcept */; });
size_type __old_size = size();
__append(std::forward<_Args>(__args)...);
if (size() != __old_size) {
if constexpr (!_WasSorted) {
ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_);
} else {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(__is_sorted_and_unique(__keys_ | ranges::views::drop(__old_size)),
"Either the key container is not sorted or it contains duplicates");
}
ranges::inplace_merge(__keys_.begin(), __keys_.begin() + __old_size, __keys_.end(), __compare_);
auto __dup_start = ranges::unique(__keys_, __key_equiv(__compare_)).begin();
__keys_.erase(__dup_start, __keys_.end());
}
__on_failure.__complete();
}
template <class _Self, class _Kp>
_LIBCPP_HIDE_FROM_ABI static auto __find_impl(_Self&& __self, const _Kp& __key) {
auto __it = __self.lower_bound(__key);
auto __last = __self.end();
if (__it == __last || __self.__compare_(__key, *__it)) {
return __last;
}
return __it;
}
template <class _Self, class _Kp>
_LIBCPP_HIDE_FROM_ABI 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 __it = ranges::lower_bound(__self.__keys_, __key, __self.__compare_);
auto __last = __self.__keys_.end();
if (__it == __last || __self.__compare_(__key, *__it)) {
return std::make_pair(__iter(__it), __iter(__it));
}
return std::make_pair(__iter(__it), __iter(std::next(__it)));
}
template <class _KeyArg>
_LIBCPP_HIDE_FROM_ABI iterator __emplace_exact_pos(const_iterator __it, _KeyArg&& __key) {
auto __on_failure = std::__make_exception_guard([&]() noexcept {
if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) {
clear() /* noexcept */;
}
});
auto __key_it = __keys_.emplace(__it.__base(), std::forward<_KeyArg>(__key));
__on_failure.__complete();
return iterator(std::move(__key_it));
}
template <class _Kp>
_LIBCPP_HIDE_FROM_ABI pair<iterator, bool> __emplace(_Kp&& __key) {
auto __it = lower_bound(__key);
if (__it == end() || __compare_(__key, *__it)) {
return pair<iterator, bool>(__emplace_exact_pos(__it, std::forward<_Kp>(__key)), true);
} else {
return pair<iterator, bool>(std::move(__it), false);
}
}
template <class _Kp>
_LIBCPP_HIDE_FROM_ABI bool __is_hint_correct(const_iterator __hint, _Kp&& __key) {
if (__hint != cbegin() && !__compare_(*std::prev(__hint), __key)) {
return false;
}
if (__hint != cend() && __compare_(*__hint, __key)) {
return false;
}
return true;
}
template <class _Kp>
_LIBCPP_HIDE_FROM_ABI iterator __emplace_hint(const_iterator __hint, _Kp&& __key) {
if (__is_hint_correct(__hint, __key)) {
if (__hint == cend() || __compare_(__key, *__hint)) {
return __emplace_exact_pos(__hint, std::forward<_Kp>(__key));
} else {
// we already have an equal key
return __hint;
}
} else {
return __emplace(std::forward<_Kp>(__key)).first;
}
}
_LIBCPP_HIDE_FROM_ABI void __reserve(size_t __size) {
if constexpr (requires { __keys_.reserve(__size); }) {
__keys_.reserve(__size);
}
}
template <class _Key2, class _Compare2, class _KeyContainer2, class _Predicate>
friend typename flat_set<_Key2, _Compare2, _KeyContainer2>::size_type
erase_if(flat_set<_Key2, _Compare2, _KeyContainer2>&, _Predicate);
_KeyContainer __keys_;
_LIBCPP_NO_UNIQUE_ADDRESS key_compare __compare_;
struct __key_equiv {
_LIBCPP_HIDE_FROM_ABI __key_equiv(key_compare __c) : __comp_(__c) {}
_LIBCPP_HIDE_FROM_ABI bool operator()(const_reference __x, const_reference __y) const {
return !__comp_(__x, __y) && !__comp_(__y, __x);
}
key_compare __comp_;
};
};
template <class _KeyContainer, class _Compare = less<typename _KeyContainer::value_type>>
requires(!__is_allocator<_Compare>::value && !__is_allocator<_KeyContainer>::value &&
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)
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 &&
uses_allocator_v<_KeyContainer, _Allocator> &&
is_invocable_v<const _Compare&,
const typename _KeyContainer::value_type&,
const typename _KeyContainer::value_type&>)
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 &&
is_invocable_v<const _Compare&,
const typename _KeyContainer::value_type&,
const 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>
requires(uses_allocator_v<_KeyContainer, _Allocator> && !__is_allocator<_KeyContainer>::value)
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 &&
uses_allocator_v<_KeyContainer, _Allocator> &&
is_invocable_v<const _Compare&,
const typename _KeyContainer::value_type&,
const typename _KeyContainer::value_type&>)
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)
flat_set(_InputIterator, _InputIterator, _Compare = _Compare())
-> flat_set<__iter_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)
flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare())
-> flat_set<__iter_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>>
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>>
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)
flat_set(initializer_list<_Key>, _Compare = _Compare()) -> flat_set<_Key, _Compare>;
template <class _Key, class _Compare = less<_Key>>
requires(!__is_allocator<_Compare>::value)
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>
: bool_constant<uses_allocator_v<_KeyContainer, _Allocator>> {};
template <class _Key, class _Compare, class _KeyContainer, class _Predicate>
_LIBCPP_HIDE_FROM_ABI typename flat_set<_Key, _Compare, _KeyContainer>::size_type
erase_if(flat_set<_Key, _Compare, _KeyContainer>& __flat_set, _Predicate __pred) {
auto __guard = std::__make_exception_guard([&] { __flat_set.clear(); });
auto __it = std::remove_if(__flat_set.__keys_.begin(), __flat_set.__keys_.end(), [&](const auto& __e) -> bool {
return static_cast<bool>(__pred(__e));
});
auto __res = __flat_set.__keys_.end() - __it;
__flat_set.__keys_.erase(__it, __flat_set.__keys_.end());
__guard.__complete();
return __res;
}
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FLAT_SET_FLAT_SET_H

View File

@ -0,0 +1,157 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP___FLAT_SET_RA_ITERATOR_H
#define _LIBCPP___FLAT_SET_RA_ITERATOR_H
#include "__type_traits/is_same.h"
#include <__compare/three_way_comparable.h>
#include <__config>
#include <__iterator/incrementable_traits.h>
#include <__iterator/iterator_traits.h>
#include <__type_traits/is_constructible.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
#if _LIBCPP_STD_VER >= 23
_LIBCPP_BEGIN_NAMESPACE_STD
/**
* __ra_iterator is a random access iterator that wraps an underlying iterator.
* It also stores the underlying container type in its type so that algorithms
* can optimize based on the underlying container type, and to avoid inadvertently
* mixing iterators coming from different containers..
*/
template <class _Container, class _Iterator>
struct __ra_iterator {
private:
_Iterator __iter_;
friend _Container;
// note: checking the concept random_access_iterator does not work for incomplete types
static_assert(_IsSame<typename iterator_traits<_Iterator>::iterator_category, random_access_iterator_tag>::value,
"Underlying iterator must be a random access iterator");
public:
using iterator_concept = random_access_iterator_tag; // deliberately lower contiguous_iterator
using iterator_category = random_access_iterator_tag;
using value_type = iter_value_t<_Iterator>;
using difference_type = iter_difference_t<_Iterator>;
_LIBCPP_HIDE_FROM_ABI __ra_iterator()
requires is_default_constructible_v<_Iterator>
= default;
_LIBCPP_HIDE_FROM_ABI explicit constexpr __ra_iterator(_Iterator __iter) : __iter_(std::move(__iter)) {}
_LIBCPP_HIDE_FROM_ABI constexpr _Iterator __base() const noexcept(noexcept(_Iterator(__iter_))) { return __iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const { return *__iter_; }
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator->() const
requires requires { __iter_.operator->(); }
{
return __iter_.operator->();
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator& operator++() {
++__iter_;
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator operator++(int) {
__ra_iterator __tmp(*this);
++*this;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator& operator--() {
--__iter_;
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator operator--(int) {
__ra_iterator __tmp(*this);
--*this;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator& operator+=(difference_type __x) {
__iter_ += __x;
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr __ra_iterator& operator-=(difference_type __x) {
__iter_ -= __x;
return *this;
}
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const { return *(*this + __n); }
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __ra_iterator& __x, const __ra_iterator& __y) {
return __x.__iter_ == __y.__iter_;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<(const __ra_iterator& __x, const __ra_iterator& __y) {
return __x.__iter_ < __y.__iter_;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>(const __ra_iterator& __x, const __ra_iterator& __y) {
return __y < __x;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator<=(const __ra_iterator& __x, const __ra_iterator& __y) {
return !(__y < __x);
}
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator>=(const __ra_iterator& __x, const __ra_iterator& __y) {
return !(__x < __y);
}
_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __ra_iterator& __x, const __ra_iterator& __y)
requires three_way_comparable<_Iterator>
{
return __x.__iter_ <=> __y.__iter_;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __ra_iterator operator+(const __ra_iterator& __i, difference_type __n) {
auto __tmp = __i;
__tmp += __n;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __ra_iterator operator+(difference_type __n, const __ra_iterator& __i) {
return __i + __n;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr __ra_iterator operator-(const __ra_iterator& __i, difference_type __n) {
auto __tmp = __i;
__tmp -= __n;
return __tmp;
}
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __ra_iterator& __x, const __ra_iterator& __y) {
return __x.__iter_ - __y.__iter_;
}
};
_LIBCPP_END_NAMESPACE_STD
#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_POP_MACROS
#endif // _LIBCPP___FLAT_SET_RA_ITERATOR_H

59
libcxx/include/flat_set Normal file
View File

@ -0,0 +1,59 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_FLAT_SET
#define _LIBCPP_FLAT_SET
/*
Header <flat_set> synopsis
#include <compare> // see [compare.syn]
#include <initializer_list> // see [initializer.list.syn]
namespace std {
// [flat.set], class template flat_set
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_set;
struct sorted_unique_t { explicit sorted_unique_t() = default; };
inline constexpr sorted_unique_t sorted_unique{};
template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_set<Key, Compare, 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);
}
*/
#if __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
# include <__cxx03/__config>
#else
# include <__config>
# if _LIBCPP_STD_VER >= 23
# include <__flat_map/sorted_unique.h>
# include <__flat_set/flat_set.h>
# endif
// for feature-test macros
# include <version>
// standard required includes
# include <compare>
# include <initializer_list>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
# endif
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
#endif // _LIBCPP_FLAT_SET

View File

@ -1296,6 +1296,19 @@ module std [system] {
export *
}
module flat_set {
module flat_set {
header "__flat_set/flat_set.h"
export std.vector.vector
export std.vector.fwd
}
module ra_iterator { header "__flat_set/ra_iterator.h" }
header "flat_set"
export std.flat_map.sorted_unique
export *
}
module format {
module buffer {
header "__format/buffer.h"

View File

@ -53,9 +53,6 @@ module;
# if __has_include(<debugging>)
# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<debugging>)
# if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_set>)
# if __has_include(<generator>)
# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<generator>)

View File

@ -65,6 +65,7 @@ module;
#include <expected>
#include <filesystem>
#include <flat_map>
#include <flat_set>
#include <format>
#include <forward_list>
#if _LIBCPP_HAS_LOCALIZATION
@ -162,9 +163,6 @@ module;
# if __has_include(<debugging>)
# error "please update the header information for <debugging> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<debugging>)
# if __has_include(<flat_set>)
# error "please update the header information for <flat_set> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<flat_set>)
# if __has_include(<generator>)
# error "please update the header information for <generator> in headers_not_available in utils/libcxx/header_information.py"
# endif // __has_include(<generator>)

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
export namespace std {
#if 0
#if _LIBCPP_STD_VER >= 23
// [flat.set], class template flat_­set
using std::flat_set;
@ -19,7 +19,9 @@ export namespace std {
// [flat.set.erasure], erasure for flat_­set
using std::erase_if;
#endif // _LIBCPP_STD_VER >= 23
#if 0
// [flat.multiset], class template flat_­multiset
using std::flat_multiset;

View File

@ -0,0 +1,226 @@
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: libcpp-hardening-mode=none
// REQUIRES: libcpp-hardening-mode=debug
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
// <flat_set>
// flat_set(container_type , const key_compare& __comp = key_compare())
// flat_set(const container_type& , const _Allocator& )
// flat_set(const container_type& , const key_compare&, const _Allocator& )
// void replace(container_type&& )
//
#include <flat_set>
#include <functional>
#include <initializer_list>
#include <memory>
#include <utility>
#include <vector>
#include "check_assertion.h"
int main(int, char**) {
using M = std::flat_set<int>;
TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}); }()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}); }()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {2, 2, 3}, std::less<int>{}); }()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(([] { M m(std::sorted_unique, {4, 2, 3}, std::less<int>{}); }()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector keys{2, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, keys, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector keys{4, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, keys, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector keys{2, 2, 3};
const std::allocator<int> alloc{};
const std::less<int> comp{};
M m(std::sorted_unique, keys, comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector keys{4, 2, 3};
const std::allocator<int> alloc{};
const std::less<int> comp{};
M m(std::sorted_unique, keys, comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{2, 2, 3};
const std::less<int> comp{};
M m(std::sorted_unique, v.begin(), v.end(), comp);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{4, 2, 3};
const std::less<int> comp{};
M m(std::sorted_unique, v.begin(), v.end(), comp);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{2, 2, 3};
const std::less<int> comp{};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v.begin(), v.end(), comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{4, 2, 3};
const std::less<int> comp{};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v.begin(), v.end(), comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{2, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v.begin(), v.end(), alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{4, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v.begin(), v.end(), alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{2, 2, 3};
const std::less<int> comp{};
M m(std::sorted_unique, v, comp);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{4, 2, 3};
const std::less<int> comp{};
M m(std::sorted_unique, v, comp);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{2, 2, 3};
const std::less<int> comp{};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v, comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{4, 2, 3};
const std::less<int> comp{};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v, comp, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{2, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{4, 2, 3};
const std::allocator<int> alloc{};
M m(std::sorted_unique, v, alloc);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{2, 2, 3};
M m;
m.insert(std::sorted_unique, v.begin(), v.end());
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
const std::vector<int> v{4, 2, 3};
M m;
m.insert(std::sorted_unique, v.begin(), v.end());
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{2, 2, 3};
M m;
m.insert(std::sorted_unique, v);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::initializer_list<int> v{4, 2, 3};
M m;
m.insert(std::sorted_unique, v);
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::vector keys{1, 1, 3};
M m;
m.replace(std::move(keys));
}()),
"Either the key container is not sorted or it contains duplicates");
TEST_LIBCPP_ASSERT_FAILURE(
([] {
std::vector keys{2, 1, 3};
M m;
m.replace(std::move(keys));
}()),
"Either the key container is not sorted or it contains duplicates");
return 0;
}

View File

@ -0,0 +1,42 @@
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// test that iterators from different types of flat_set are not compatible
#include <deque>
#include <functional>
#include <flat_set>
#include <type_traits>
using Iter1 = std::flat_set<int>::iterator;
using Iter2 = std::flat_set<double>::iterator;
using Iter3 = std::flat_set<int, std::greater<>>::iterator;
using Iter4 = std::flat_set<int, std::less<int>, std::deque<int>>::iterator;
static_assert(std::is_convertible_v<Iter1, Iter1>);
static_assert(!std::is_convertible_v<Iter1, Iter2>);
static_assert(!std::is_convertible_v<Iter1, Iter3>);
static_assert(!std::is_convertible_v<Iter1, Iter4>);
static_assert(!std::is_convertible_v<Iter2, Iter1>);
static_assert(std::is_convertible_v<Iter2, Iter2>);
static_assert(!std::is_convertible_v<Iter2, Iter3>);
static_assert(!std::is_convertible_v<Iter2, Iter4>);
static_assert(!std::is_convertible_v<Iter3, Iter1>);
static_assert(!std::is_convertible_v<Iter3, Iter2>);
static_assert(std::is_convertible_v<Iter3, Iter3>);
static_assert(!std::is_convertible_v<Iter3, Iter4>);
static_assert(!std::is_convertible_v<Iter4, Iter1>);
static_assert(!std::is_convertible_v<Iter4, Iter2>);
static_assert(!std::is_convertible_v<Iter4, Iter3>);
static_assert(std::is_convertible_v<Iter4, Iter4>);

View File

@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// [[nodiscard]] bool empty() const noexcept;
#include <flat_set>
void f() {
std::flat_set<int> c;
c.empty(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}

View File

@ -683,6 +683,14 @@ flat_map initializer_list
flat_map limits
flat_map type_traits
flat_map version
flat_set cmath
flat_set compare
flat_set cstddef
flat_set cstdint
flat_set initializer_list
flat_set limits
flat_set type_traits
flat_set version
format algorithm
format array
format atomic

1 algorithm atomic
683 flat_map limits
684 flat_map type_traits
685 flat_map version
686 flat_set cmath
687 flat_set compare
688 flat_set cstddef
689 flat_set cstdint
690 flat_set initializer_list
691 flat_set limits
692 flat_set type_traits
693 flat_set version
694 format algorithm
695 format array
696 format atomic

View File

@ -683,6 +683,14 @@ flat_map initializer_list
flat_map limits
flat_map type_traits
flat_map version
flat_set cmath
flat_set compare
flat_set cstddef
flat_set cstdint
flat_set initializer_list
flat_set limits
flat_set type_traits
flat_set version
format algorithm
format array
format atomic

1 algorithm atomic
683 flat_map limits
684 flat_map type_traits
685 flat_map version
686 flat_set cmath
687 flat_set compare
688 flat_set cstddef
689 flat_set cstdint
690 flat_set initializer_list
691 flat_set limits
692 flat_set type_traits
693 flat_set version
694 format algorithm
695 format array
696 format atomic

View File

@ -701,6 +701,14 @@ flat_map initializer_list
flat_map limits
flat_map type_traits
flat_map version
flat_set cmath
flat_set compare
flat_set cstddef
flat_set cstdint
flat_set initializer_list
flat_set limits
flat_set type_traits
flat_set version
format algorithm
format array
format atomic

1 algorithm atomic
701 flat_map limits
702 flat_map type_traits
703 flat_map version
704 flat_set cmath
705 flat_set compare
706 flat_set cstddef
707 flat_set cstdint
708 flat_set initializer_list
709 flat_set limits
710 flat_set type_traits
711 flat_set version
712 format algorithm
713 format array
714 format atomic

View File

@ -709,6 +709,14 @@ flat_map initializer_list
flat_map limits
flat_map type_traits
flat_map version
flat_set cmath
flat_set compare
flat_set cstddef
flat_set cstdint
flat_set initializer_list
flat_set limits
flat_set type_traits
flat_set version
format algorithm
format array
format atomic

1 algorithm atomic
709 flat_map limits
710 flat_map type_traits
711 flat_map version
712 flat_set cmath
713 flat_set compare
714 flat_set cstddef
715 flat_set cstdint
716 flat_set initializer_list
717 flat_set limits
718 flat_set type_traits
719 flat_set version
720 format algorithm
721 format array
722 format atomic

View File

@ -705,6 +705,14 @@ flat_map initializer_list
flat_map limits
flat_map type_traits
flat_map version
flat_set cmath
flat_set compare
flat_set cstddef
flat_set cstdint
flat_set initializer_list
flat_set limits
flat_set type_traits
flat_set version
format algorithm
format array
format atomic

1 algorithm atomic
705 flat_map limits
706 flat_map type_traits
707 flat_map version
708 flat_set cmath
709 flat_set compare
710 flat_set cstddef
711 flat_set cstdint
712 flat_set initializer_list
713 flat_set limits
714 flat_set type_traits
715 flat_set version
716 format algorithm
717 format array
718 format atomic

View File

@ -345,6 +345,19 @@ flat_map optional
flat_map stdexcept
flat_map tuple
flat_map version
flat_set cctype
flat_set climits
flat_set compare
flat_set cstdint
flat_set cstring
flat_set cwchar
flat_set cwctype
flat_set initializer_list
flat_set limits
flat_set optional
flat_set stdexcept
flat_set tuple
flat_set version
format array
format cctype
format cerrno
@ -556,7 +569,6 @@ istream ios
istream iosfwd
istream limits
istream locale
istream ratio
istream stdexcept
istream streambuf

1 algorithm cctype
345 flat_map stdexcept
346 flat_map tuple
347 flat_map version
348 flat_set cctype
349 flat_set climits
350 flat_set compare
351 flat_set cstdint
352 flat_set cstring
353 flat_set cwchar
354 flat_set cwctype
355 flat_set initializer_list
356 flat_set limits
357 flat_set optional
358 flat_set stdexcept
359 flat_set tuple
360 flat_set version
361 format array
362 format cctype
363 format cerrno
569 istream iosfwd
570 istream limits
571 istream locale
istream ratio
572 istream stdexcept istream ratio
573 istream streambuf istream stdexcept
574 istream string istream streambuf

View File

@ -345,6 +345,19 @@ flat_map optional
flat_map stdexcept
flat_map tuple
flat_map version
flat_set cctype
flat_set climits
flat_set compare
flat_set cstdint
flat_set cstring
flat_set cwchar
flat_set cwctype
flat_set initializer_list
flat_set limits
flat_set optional
flat_set stdexcept
flat_set tuple
flat_set version
format array
format cctype
format cerrno

1 algorithm cctype
345 flat_map stdexcept
346 flat_map tuple
347 flat_map version
348 flat_set cctype
349 flat_set climits
350 flat_set compare
351 flat_set cstdint
352 flat_set cstring
353 flat_set cwchar
354 flat_set cwctype
355 flat_set initializer_list
356 flat_set limits
357 flat_set optional
358 flat_set stdexcept
359 flat_set tuple
360 flat_set version
361 format array
362 format cctype
363 format cerrno

View File

@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// [[nodiscard]] bool empty() const noexcept;
#include <flat_set>
#include <cassert>
#include <deque>
#include <functional>
#include <utility>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<int>, KeyContainer>;
M m;
ASSERT_SAME_TYPE(decltype(m.empty()), bool);
ASSERT_NOEXCEPT(m.empty());
assert(m.empty());
assert(std::as_const(m).empty());
m = {1};
assert(!m.empty());
m.clear();
assert(m.empty());
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// size_type max_size() const noexcept;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <limits>
#include <type_traits>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_allocator.h"
#include "test_macros.h"
void test() {
{
using A1 = limited_allocator<int, 10>;
using C = std::flat_set<int, std::less<int>, std::vector<int, A1>>;
ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t);
ASSERT_SAME_TYPE(C::size_type, std::size_t);
const C c;
ASSERT_NOEXCEPT(c.max_size());
ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type);
assert(c.max_size() <= 10);
LIBCPP_ASSERT(c.max_size() == 10);
}
{
using A = limited_allocator<int, (size_t)-1>;
using C = std::flat_set<int, std::less<int>, std::vector<int, A>>;
ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t);
ASSERT_SAME_TYPE(C::size_type, std::size_t);
const C::size_type max_dist = static_cast<C::size_type>(std::numeric_limits<C::difference_type>::max());
const C c;
ASSERT_NOEXCEPT(c.max_size());
ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type);
assert(c.max_size() <= max_dist);
LIBCPP_ASSERT(c.max_size() == max_dist);
}
{
typedef std::flat_set<char> C;
ASSERT_SAME_TYPE(C::difference_type, std::ptrdiff_t);
ASSERT_SAME_TYPE(C::size_type, std::size_t);
const C::size_type max_dist = static_cast<C::size_type>(std::numeric_limits<C::difference_type>::max());
const C c;
ASSERT_NOEXCEPT(c.max_size());
ASSERT_SAME_TYPE(decltype(c.max_size()), C::size_type);
assert(c.max_size() <= max_dist);
assert(c.max_size() <= alloc_max_size(std::allocator<char>()));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// size_type size() const noexcept;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using M = std::flat_set<int, std::less<int>, KeyContainer>;
using S = typename M::size_type;
{
const M m = {1, 1, 4, 5, 5};
ASSERT_SAME_TYPE(decltype(m.size()), S);
ASSERT_NOEXCEPT(m.size());
assert(m.size() == 3);
}
{
const M m = {1};
ASSERT_SAME_TYPE(decltype(m.size()), S);
ASSERT_NOEXCEPT(m.size());
assert(m.size() == 1);
}
{
const M m;
ASSERT_SAME_TYPE(decltype(m.size()), S);
ASSERT_NOEXCEPT(m.size());
assert(m.size() == 0);
}
{
M m;
S s = 1000000;
for (auto i = 0u; i < s; ++i) {
m.emplace(i);
}
ASSERT_SAME_TYPE(decltype(m.size()), S);
ASSERT_NOEXCEPT(m.size());
assert(m.size() == s);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class Allocator>
// explicit flat_set(const Allocator& a);
#include <cassert>
#include <flat_set>
#include <functional>
#include <vector>
#include "test_macros.h"
#include "test_allocator.h"
#include "../../../test_compare.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, const A1&>);
static_assert(std::is_constructible_v<M2, const A2&>);
static_assert(!std::is_constructible_v<M1, const A2&>);
static_assert(!std::is_constructible_v<M2, const A1&>);
}
{
// explicit
using M = std::flat_set<int, std::less<int>, std::vector<int, test_allocator<int>>>;
static_assert(std::is_constructible_v<M, test_allocator<int>>);
static_assert(!std::is_convertible_v<test_allocator<int>, M>);
}
{
using A = test_allocator<short>;
using M = std::flat_set<int, std::less<int>, std::vector<int, test_allocator<int>>>;
M m(A(0, 5));
assert(m.empty());
assert(m.begin() == m.end());
auto v = std::move(m).extract();
assert(v.get_allocator().get_id() == 5);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set& operator=(initializer_list<value_type> il);
#include <algorithm>
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
{
M m = {8, 10};
assert(m.size() == 2);
std::same_as<M&> decltype(auto) r = m = {3, 1, 2, 2, 3, 4, 3, 5, 6, 5};
assert(&r == &m);
int expected[] = {1, 2, 3, 4, 5, 6};
assert(std::ranges::equal(m, expected));
}
{
M m = {10, 8};
assert(m.size() == 2);
std::same_as<M&> decltype(auto) r = m = {3};
assert(&r == &m);
int expected[] = {3};
assert(std::ranges::equal(m, expected));
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,87 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// explicit flat_set(const key_compare& comp);
// template <class Alloc>
// flat_set(const key_compare& comp, const Alloc& a);
#include <deque>
#include <flat_set>
#include <functional>
#include <type_traits>
#include <vector>
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, const C&, const A1&>);
}
{
using C = test_less<int>;
auto m = std::flat_set<int, C>(C(3));
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp() == C(3));
}
{
// The one-argument ctor is explicit.
using C = test_less<int>;
static_assert(std::is_constructible_v<std::flat_set<int, C>, C>);
static_assert(!std::is_convertible_v<C, std::flat_set<int, C>>);
static_assert(std::is_constructible_v<std::flat_set<int>, std::less<int>>);
static_assert(!std::is_convertible_v<std::less<int>, std::flat_set<int>>);
}
{
using C = test_less<int>;
using A1 = test_allocator<int>;
auto m = std::flat_set<int, C, std::vector<int, A1>>(C(4), A1(5));
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp() == C(4));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == A1(5));
}
{
// explicit(false)
using C = test_less<int>;
using A1 = test_allocator<int>;
std::flat_set<int, C, std::deque<int, A1>> m = {C(4), A1(5)};
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp() == C(4));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == A1(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,157 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// explicit flat_set(container_type key_cont, const key_compare& comp = key_compare());
// template<class Allocator>
// flat_set(const container_type& key_cont, const Allocator& a);
// template<class Alloc>
// flat_set(const container_type& key_cont, const key_compare& comp, const Alloc& a);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <type_traits>
#include <vector>
#include "min_allocator.h"
#include "MoveOnly.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
template <class T>
void conversion_test(T);
template <class T, class... Args>
concept ImplicitlyConstructible = requires(Args&&... args) { conversion_test<T>({std::forward<Args>(args)...}); };
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, const V1&, const A1&>);
static_assert(std::is_constructible_v<M2, const V2&, const A2&>);
static_assert(!std::is_constructible_v<M1, const V1&, const A2&>);
static_assert(!std::is_constructible_v<M2, const V2&, const A1&>);
static_assert(std::is_constructible_v<M1, const V1&, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, const V2&, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, const V1&, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, const V2&, const C&, const A1&>);
}
{
// flat_set(container_type)
using M = std::flat_set<int>;
std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
auto m = M(ks);
assert(std::ranges::equal(m, std::vector<int>{1, 2, 3}));
// explicit
static_assert(std::is_constructible_v<M, const std::vector<int>&>);
static_assert(!ImplicitlyConstructible<M, const std::vector<int>&>);
}
{
// flat_set(container_type)
// move-only
MoveOnly expected[] = {3, 2, 1};
using Ks = std::deque<MoveOnly, min_allocator<MoveOnly>>;
using M = std::flat_set<MoveOnly, std::greater<MoveOnly>, Ks>;
Ks ks;
ks.push_back(1);
ks.push_back(3);
ks.push_back(2);
auto m = M(std::move(ks));
assert(ks.empty()); // it was moved-from
assert(std::ranges::equal(m, expected));
}
{
// flat_set(container_type)
// container's allocator is used
using A = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A>>;
auto ks = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
auto m = M(std::move(ks));
assert(ks.empty()); // it was moved-from
assert((m == M{1, 2, 3}));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == A(5));
}
{
// flat_set(container_type , key_compare)
using C = test_less<int>;
using M = std::flat_set<int, C>;
std::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
auto m = M(ks, C(4));
assert(std::ranges::equal(m, std::vector<int>{1, 2, 3}));
assert(m.key_comp() == C(4));
// explicit
static_assert(std::is_constructible_v<M, const std::vector<int>&, const C&>);
static_assert(!ImplicitlyConstructible<M, const std::vector<int>&, const C&>);
}
{
// flat_set(container_type , const Allocator&)
using A = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A>>;
auto ks = std::deque<int, A>({1, 1, 1, 2, 2, 3, 2, 3, 3}, A(5));
auto m = M(ks, A(4)); // replaces the allocators
assert(!ks.empty()); // it was an lvalue above
assert((m == M{1, 2, 3}));
auto keys = M(m).extract();
assert(keys.get_allocator() == A(4));
// explicit(false)
static_assert(ImplicitlyConstructible<M, const std::deque<int, A>&, const A&>);
M m2 = {ks, A(4)}; // implicit ctor
assert(!ks.empty()); // it was an lvalue above
assert(m2 == m);
auto keys2 = std::move(m).extract();
assert(keys2.get_allocator() == A(4));
}
{
// flat_set(container_type , key_compare, const Allocator&)
using C = test_less<int>;
using A = test_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A>>;
std::vector<int, A> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
auto m = M(ks, C(4), A(5));
assert(std::ranges::equal(m, std::vector<int, A>{1, 2, 3}));
assert(m.key_comp() == C(4));
auto m_copy = m;
auto keys = std::move(m_copy).extract();
assert(keys.get_allocator() == A(5));
// explicit(false)
static_assert(ImplicitlyConstructible<M, const std::vector<int, A>&, const A&>);
M m2 = {ks, C(4), A(5)};
assert(m2 == m);
assert(m2.key_comp() == C(4));
keys = std::move(m2).extract();
assert(keys.get_allocator() == A(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(const flat_set& m);
#include <algorithm>
#include <cassert>
#include <flat_set>
#include <vector>
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
void test() {
{
using C = test_less<int>;
std::vector<int, test_allocator<int>> ks({1, 3, 5}, test_allocator<int>(6));
using M = std::flat_set<int, C, decltype(ks)>;
auto mo = M(ks, C(5));
auto m = mo;
assert(m.key_comp() == C(5));
assert(std::ranges::equal(m, ks));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == test_allocator<int>(6));
// mo is unchanged
assert(mo.key_comp() == C(5));
assert(std::ranges::equal(mo, ks));
auto keys2 = std::move(mo).extract();
assert(keys2.get_allocator() == test_allocator<int>(6));
}
{
using C = test_less<int>;
using Ks = std::vector<int, other_allocator<int>>;
auto ks = Ks({1, 3, 5}, other_allocator<int>(6));
using M = std::flat_set<int, C, Ks>;
auto mo = M(Ks(ks, other_allocator<int>(6)), C(5));
auto m = mo;
assert(m.key_comp() == C(5));
assert(std::ranges::equal(m, ks));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == other_allocator<int>(-2));
// mo is unchanged
assert(mo.key_comp() == C(5));
assert(std::ranges::equal(mo, ks));
auto keys2 = std::move(mo).extract();
assert(keys2.get_allocator() == other_allocator<int>(6));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(const flat_set&, const allocator_type&);
#include <algorithm>
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, const M1&, const A1&>);
static_assert(std::is_constructible_v<M2, const M2&, const A2&>);
static_assert(!std::is_constructible_v<M1, const M1&, const A2&>);
static_assert(!std::is_constructible_v<M2, const M2&, const A1&>);
}
{
using C = test_less<int>;
std::vector<int, test_allocator<int>> ks({1, 3, 5}, test_allocator<int>(6));
using M = std::flat_set<int, C, decltype(ks)>;
auto mo = M(ks, C(5));
auto m = M(mo, test_allocator<int>(3));
assert(m.key_comp() == C(5));
assert(std::ranges::equal(m, ks));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == test_allocator<int>(3));
// mo is unchanged
assert(mo.key_comp() == C(5));
assert(std::ranges::equal(mo, ks));
auto keys2 = std::move(mo).extract();
assert(keys2.get_allocator() == test_allocator<int>(6));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set& operator=(const flat_set& m);
#include <algorithm>
#include <flat_set>
#include <functional>
#include <vector>
#include "operator_hijacker.h"
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
void test() {
{
// test_allocator is not propagated
using C = test_less<int>;
std::vector<int, test_allocator<int>> ks({1, 3, 5}, test_allocator<int>(6));
using M = std::flat_set<int, C, decltype(ks)>;
auto mo = M(ks, C(5));
auto m = M({{3, 4, 5}}, C(3), test_allocator<int>(2));
m = mo;
assert(m.key_comp() == C(5));
assert(std::ranges::equal(m, ks));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == test_allocator<int>(2));
// mo is unchanged
assert(mo.key_comp() == C(5));
assert(std::ranges::equal(mo, ks));
auto keys2 = std::move(mo).extract();
assert(keys2.get_allocator() == test_allocator<int>(6));
}
{
// other_allocator is propagated
using C = test_less<int>;
using Ks = std::vector<int, other_allocator<int>>;
auto ks = Ks({1, 3, 5}, other_allocator<int>(6));
using M = std::flat_set<int, C, Ks>;
auto mo = M(Ks(ks, other_allocator<int>(6)), C(5));
auto m = M({3, 4, 5}, C(3), other_allocator<int>(2));
m = mo;
assert(m.key_comp() == C(5));
assert(std::ranges::equal(m, ks));
auto keys = std::move(m).extract();
assert(keys.get_allocator() == other_allocator<int>(6));
// mo is unchanged
assert(mo.key_comp() == C(5));
assert(std::ranges::equal(mo, ks));
auto keys2 = std::move(mo).extract();
assert(keys2.get_allocator() == other_allocator<int>(6));
}
{
// comparator is copied and invariant is preserved
using M = std::flat_set<int, std::function<bool(int, int)>>;
M mo = M({1, 2}, std::less<int>());
M m = M({1, 2}, std::greater<int>());
assert(m.key_comp()(2, 1) == true);
assert(m != mo);
m = mo;
assert(m.key_comp()(2, 1) == false);
assert(m == mo);
}
{
// self-assignment
using M = std::flat_set<int>;
M m = {{1, 2}};
m = static_cast<const M&>(m);
assert((m == M{{1, 2}}));
}
{
// Validate whether the container can be copy-assigned (move-assigned, swapped)
// with an ADL-hijacking operator&
std::flat_set<operator_hijacker> so;
std::flat_set<operator_hijacker> s;
s = so;
s = std::move(so);
swap(s, so);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// Test CTAD on cases where deduction should fail.
#include <flat_set>
#include <functional>
#include <memory>
#include <utility>
#include <vector>
struct NotAnAllocator {
friend bool operator<(NotAnAllocator, NotAnAllocator) { return false; }
};
template <class... Args>
concept CanDeductFlatSet = requires { std::flat_set(std::declval<Args>()...); };
static_assert(CanDeductFlatSet<std::vector<int>>);
// cannot deduce Key and T from nothing
static_assert(!CanDeductFlatSet<>);
// cannot deduce Key and T from just (Compare)
static_assert(!CanDeductFlatSet<std::less<int>>);
// cannot deduce Key and T from just (Compare, Allocator)
static_assert(!CanDeductFlatSet<std::less<int>, std::allocator<int>>);
// cannot deduce Key and T from just (Allocator)
static_assert(!CanDeductFlatSet<std::allocator<int>>);
// cannot convert from some arbitrary unrelated type
static_assert(!CanDeductFlatSet<NotAnAllocator>);

View File

@ -0,0 +1,386 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
#include <algorithm>
#include <cassert>
#include <climits>
#include <deque>
#include <initializer_list>
#include <list>
#include <flat_set>
#include <functional>
#include <ranges>
#include <type_traits>
#include <utility>
#include <vector>
#include "deduction_guides_sfinae_checks.h"
#include "test_allocator.h"
void test() {
{
// deduction guide generated from
// flat_set(const flat_set&)
std::flat_set<long> source = {1, 2};
std::flat_set s(source);
ASSERT_SAME_TYPE(decltype(s), decltype(source));
assert(s == source);
}
{
// deduction guide generated from
// flat_set(const flat_set&)
std::flat_set<short, std::greater<short>> source = {1, 2};
std::flat_set s{source}; // braces instead of parens
ASSERT_SAME_TYPE(decltype(s), decltype(source));
assert(s == source);
}
{
// deduction guide generated from
// flat_set(const flat_set&, const Allocator&)
std::flat_set<long, std::greater<long>> source = {1, 2};
std::flat_set s(source, std::allocator<int>());
ASSERT_SAME_TYPE(decltype(s), decltype(source));
assert(s == source);
}
{
// various overloads that takes a container
std::deque<int, test_allocator<int>> ks({1, 2, 1, INT_MAX, 3}, test_allocator<int>(0, 42));
std::deque<int, test_allocator<int>> sorted_ks({1, 2, 3, INT_MAX}, test_allocator<int>(0, 42));
int expected[] = {1, 2, 3, INT_MAX};
{
// template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
// flat_set(KeyContainer, Compare = Compare())
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::flat_set s(ks);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
{
// 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>;
std::flat_set s(std::sorted_unique, sorted_ks);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
{
// template<class KeyContainer, class Allocator>
// flat_set(KeyContainer, Allocator)
// -> flat_set<typename KeyContainer::value_type,
// less<typename KeyContainer::value_type>, KeyContainer>;
std::flat_set s(ks, test_allocator<long>(0, 44));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 44);
}
{
// template<class KeyContainer, class Allocator>
// flat_set(sorted_unique_t, KeyContainer, Allocator)
// -> flat_set<typename KeyContainer::value_type,
// less<typename KeyContainer::value_type>, KeyContainer>;
std::flat_set s(std::sorted_unique, sorted_ks, test_allocator<long>(0, 44));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 44);
}
}
{
// various overloads that takes a container and a comparator
std::deque<int, test_allocator<int>> ks({1, 2, 1, INT_MAX, 3}, test_allocator<int>(0, 42));
std::deque<int, test_allocator<int>> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator<int>(0, 42));
int expected[] = {INT_MAX, 3, 2, 1};
{
// template<class KeyContainer, class Compare = less<typename KeyContainer::value_type>>
// flat_set(KeyContainer, Compare = Compare())
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::flat_set s(ks, std::greater<int>());
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
{
// 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>;
std::flat_set s(std::sorted_unique, sorted_ks, std::greater<int>());
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
{
// template<class KeyContainer, class Compare, class Allocator>
// flat_set(KeyContainer, Compare, Allocator)
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::flat_set s(ks, std::greater<int>(), test_allocator<long>(0, 44));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 44);
}
{
// template<class KeyContainer, class Compare, class Allocator>
// flat_set(sorted_unique_t, KeyContainer, Compare, Allocator)
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::flat_set s(std::sorted_unique, sorted_ks, std::greater<int>(), test_allocator<long>(0, 44));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, decltype(ks)>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 44);
}
}
{
// overloads that take pair of iterators
int arr[] = {1, 2, 1, INT_MAX, 3};
int sorted_arr[] = {1, 2, 3, INT_MAX};
const int arrc[] = {1, 2, 1, INT_MAX, 3};
const int sorted_arrc[] = {1, 2, 3, INT_MAX};
{
// template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
// flat_set(InputIterator, InputIterator, Compare = Compare())
// -> flat_set<iter-value-type<InputIterator>, Compare>;
std::flat_set m(std::begin(arr), std::end(arr));
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// const
std::flat_set m(std::begin(arrc), std::end(arrc));
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// 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>;
std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr));
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// const
std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc));
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// from flat_set::iterator
std::flat_set<int> mo;
std::flat_set m(mo.begin(), mo.end());
ASSERT_SAME_TYPE(decltype(m), decltype(mo));
}
{
// from flat_set::const_iterator
std::flat_set<int> mo;
std::flat_set m(mo.cbegin(), mo.cend());
ASSERT_SAME_TYPE(decltype(m), decltype(mo));
}
{
// This does not deduce to flat_set(InputIterator, InputIterator)
// But deduces to flat_set(initializer_list<int*>)
std::flat_set s = {arr, arr + 3};
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int*>);
assert(s.size() == 2);
}
{
// This deduces to flat_set(sorted_unique_t, InputIterator, InputIterator)
std::flat_set s{std::sorted_unique, sorted_arr, sorted_arr + 3};
static_assert(std::is_same_v<decltype(s), std::flat_set<int>>);
assert(s.size() == 3);
}
}
{
// overloads that take pair of iterators and comparator
int arr[] = {1, 2, 1, INT_MAX, 3};
int sorted_arr[] = {INT_MAX, 3, 2, 1};
const int arrc[] = {1, 2, 1, INT_MAX, 3};
const int sorted_arrc[] = {INT_MAX, 3, 2, 1};
using C = std::greater<long>;
{
// template<class InputIterator, class Compare = less<iter-value-type<InputIterator>>>
// flat_set(InputIterator, InputIterator, Compare = Compare())
// -> flat_set<iter-value-type<InputIterator>, Compare>;
std::flat_set m(std::begin(arr), std::end(arr), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// const
std::flat_set m(std::begin(arrc), std::end(arrc), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// 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>;
std::flat_set m(std::sorted_unique, std::begin(sorted_arr), std::end(sorted_arr), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// const
std::flat_set m(std::sorted_unique, std::begin(sorted_arrc), std::end(sorted_arrc), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// from flat_set::iterator
std::flat_set<int> mo;
std::flat_set m(mo.begin(), mo.end(), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
}
{
// from flat_set::const_iterator
std::flat_set<int> mo;
std::flat_set m(mo.cbegin(), mo.cend(), C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
}
}
{
// overloads that take an initializer_list
const int sorted_arr[] = {1, 2, 3, INT_MAX};
{
// template<class Key, class Compare = less<Key>>
// flat_set(initializer_list<Key>, Compare = Compare())
// -> flat_set<Key, Compare>;
std::flat_set m{1, 2, 1, INT_MAX, 3};
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// template<class Key, class Compare = less<Key>>
// flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare())
// -> flat_set<Key, Compare>;
std::flat_set m(std::sorted_unique, {1, 2, 3, INT_MAX});
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// one argument/element of an int -> should be treated as an initializer_list<int>
std::flat_set s = {1};
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int>);
assert(s.size() == 1);
}
{
// two of the flat_sets -> should be treated as an initializer_list<flat_set<int>>
using M = std::flat_set<int>;
M m;
std::flat_set s{m, m}; // flat_set(initializer_list<M>)
ASSERT_SAME_TYPE(decltype(s), std::flat_set<M>);
assert(s.size() == 1);
}
}
{
// overloads that take an initializer_list and a comparator
const int sorted_arr[] = {INT_MAX, 3, 2, 1};
using C = std::greater<long>;
{
// template<class Key, class Compare = less<Key>>
// flat_set(initializer_list<Key>, Compare = Compare())
// -> flat_set<Key, Compare>;
std::flat_set m({1, 2, 1, INT_MAX, 3}, C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
{
// template<class Key, class Compare = less<Key>>
// flat_set(sorted_unique_t, initializer_list<Key>, Compare = Compare())
// -> flat_set<Key, Compare>;
std::flat_set m(std::sorted_unique, {INT_MAX, 3, 2, 1}, C());
ASSERT_SAME_TYPE(decltype(m), std::flat_set<int, C>);
assert(std::ranges::equal(m, sorted_arr));
}
}
{
// from_range without comparator
std::list<int> r = {1, 2, 1, INT_MAX, 3};
const int expected[] = {1, 2, 3, INT_MAX};
{
// 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>>>>;
std::flat_set s(std::from_range, r);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>>);
assert(std::ranges::equal(s, expected));
}
{
// 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>>>>;
std::flat_set s(std::from_range, r, test_allocator<long>(0, 42));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, std::vector<int, test_allocator<int>>>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
}
{
// from_range with comparator
std::list<int> r = {1, 2, 1, INT_MAX, 3};
const int expected[] = {INT_MAX, 3, 2, 1};
{
// 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>>>>;
std::flat_set s(std::from_range, r, std::greater<int>());
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>>);
assert(std::ranges::equal(s, expected));
}
{
// 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>>>>;
std::flat_set s(std::from_range, r, std::greater<int>(), test_allocator<long>(0, 42));
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, std::vector<int, test_allocator<int>>>);
assert(std::ranges::equal(s, expected));
assert(std::move(s).extract().get_allocator().get_id() == 42);
}
}
AssociativeContainerDeductionGuidesSfinaeAway<std::flat_set, std::flat_set<int>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,104 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: availability-pmr-missing
// <flat_set>
#include <algorithm>
#include <cassert>
#include <climits>
#include <deque>
#include <initializer_list>
#include <list>
#include <flat_set>
#include <functional>
#include <memory_resource>
#include <ranges>
#include <type_traits>
#include <utility>
#include <vector>
#include "test_allocator.h"
using P = std::pair<int, long>;
using PC = std::pair<const int, long>;
int main(int, char**) {
{
std::deque<int, test_allocator<int>> ks({1, 2, 1, INT_MAX, 3}, test_allocator<int>(0, 42));
std::deque<int, test_allocator<int>> sorted_ks({1, 2, 3, INT_MAX}, test_allocator<int>(0, 42));
const int expected[] = {1, 2, 3, INT_MAX};
{
// template<class KeyContainer, class Allocator>
// flat_set(KeyContainer, Allocator)
// -> flat_set<typename KeyContainer::value_type,
// less<typename KeyContainer::value_type>, KeyContainer>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::monotonic_buffer_resource mr2;
std::pmr::deque<int> pks(ks.begin(), ks.end(), &mr);
std::flat_set s(std::move(pks), &mr2);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, std::pmr::deque<int>>);
assert(std::ranges::equal(s, expected));
auto keys = std::move(s).extract();
assert(keys.get_allocator().resource() == &mr2);
}
{
// template<class KeyContainer, class Allocator>
// flat_set(sorted_unique_t, KeyContainer, Allocator)
// -> flat_set<typename KeyContainer::value_type,
// less<typename KeyContainer::value_type>, KeyContainer>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::monotonic_buffer_resource mr2;
std::pmr::deque<int> pks(sorted_ks.begin(), sorted_ks.end(), &mr);
std::flat_set s(std::sorted_unique, std::move(pks), &mr2);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::less<int>, std::pmr::deque<int>>);
assert(std::ranges::equal(s, expected));
auto keys = std::move(s).extract();
assert(keys.get_allocator().resource() == &mr2);
}
}
{
std::deque<int, test_allocator<int>> ks({1, 2, 1, INT_MAX, 3}, test_allocator<int>(0, 42));
std::deque<int, test_allocator<int>> sorted_ks({INT_MAX, 3, 2, 1}, test_allocator<int>(0, 42));
const int expected[] = {INT_MAX, 3, 2, 1};
{
// template<class KeyContainer, class Compare, class Allocator>
// flat_set(KeyContainer, Compare, Allocator)
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::monotonic_buffer_resource mr2;
std::pmr::deque<int> pks(ks.begin(), ks.end(), &mr);
std::flat_set s(std::move(pks), std::greater<int>(), &mr2);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, std::pmr::deque<int>>);
assert(std::ranges::equal(s, expected));
auto keys = std::move(s).extract();
assert(keys.get_allocator().resource() == &mr2);
}
{
// template<class KeyContainer, class Compare, class Allocator>
// flat_set(sorted_unique_t, KeyContainer, Compare, Allocator)
// -> flat_set<typename KeyContainer::value_type, Compare, KeyContainer>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::monotonic_buffer_resource mr2;
std::pmr::deque<int> pks(sorted_ks.begin(), sorted_ks.end(), &mr);
std::flat_set s(std::sorted_unique, std::move(pks), std::greater<int>(), &mr2);
ASSERT_SAME_TYPE(decltype(s), std::flat_set<int, std::greater<int>, std::pmr::deque<int>>);
assert(std::ranges::equal(s, expected));
auto keys = std::move(s).extract();
assert(keys.get_allocator().resource() == &mr2);
}
}
return 0;
}

View File

@ -0,0 +1,96 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set();
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <type_traits>
#include <vector>
#include "min_allocator.h"
#include "MoveOnly.h"
#include "test_allocator.h"
#include "test_macros.h"
struct DefaultCtableComp {
explicit DefaultCtableComp() { default_constructed_ = true; }
bool operator()(int, int) const { return false; }
bool default_constructed_ = false;
};
struct ThrowingCtorComp {
ThrowingCtorComp() noexcept(false) {}
bool operator()(const auto&, const auto&) const { return false; }
};
void test() {
{
std::flat_set<int> m;
assert(m.empty());
}
{
// explicit(false)
std::flat_set<int> m = {};
assert(m.empty());
}
{
std::flat_set<int, DefaultCtableComp, std::deque<int, min_allocator<int>>> m;
assert(m.empty());
assert(m.begin() == m.end());
assert(m.key_comp().default_constructed_);
}
{
using A1 = explicit_allocator<int>;
{
std::flat_set<int, DefaultCtableComp, std::vector<int, A1>> m;
assert(m.empty());
assert(m.key_comp().default_constructed_);
}
{
A1 a1;
std::flat_set<int, DefaultCtableComp, std::vector<int, A1>> m(a1);
assert(m.empty());
assert(m.key_comp().default_constructed_);
}
}
#if defined(_LIBCPP_VERSION)
{
using C = std::flat_set<MoveOnly>;
static_assert(std::is_nothrow_default_constructible_v<C>);
C c;
}
{
using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, test_allocator<MoveOnly>>>;
static_assert(std::is_nothrow_default_constructible_v<C>);
C c;
}
#endif // _LIBCPP_VERSION
{
using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, other_allocator<MoveOnly>>>;
static_assert(!std::is_nothrow_default_constructible_v<C>);
C c;
}
{
using C = std::flat_set<MoveOnly, ThrowingCtorComp>;
static_assert(!std::is_nothrow_default_constructible_v<C>);
C c;
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// ~flat_set();
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "test_macros.h"
#include "MoveOnly.h"
#include "test_allocator.h"
struct ThrowingDtorComp {
bool operator()(const auto&, const auto&) const;
~ThrowingDtorComp() noexcept(false) {}
};
void test() {
{
using C = std::flat_set<MoveOnly, MoveOnly>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
{
using V = std::vector<MoveOnly, test_allocator<MoveOnly>>;
using C = std::flat_set<MoveOnly, std::less<MoveOnly>, V>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
{
using V = std::deque<MoveOnly, other_allocator<MoveOnly>>;
using C = std::flat_set<MoveOnly, std::greater<MoveOnly>, V>;
static_assert(std::is_nothrow_destructible_v<C>);
C c;
}
#if defined(_LIBCPP_VERSION)
{
using C = std::flat_set<MoveOnly, ThrowingDtorComp>;
static_assert(!std::is_nothrow_destructible_v<C>);
C c;
}
#endif // _LIBCPP_VERSION
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,155 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(initializer_list<value_type> il, const key_compare& comp = key_compare());
// template<class Alloc>
// flat_set(initializer_list<value_type> il, const Alloc& a);
// template<class Alloc>
// flat_set(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <type_traits>
#include <vector>
#include "test_macros.h"
#include "min_allocator.h"
#include "test_allocator.h"
#include "../../../test_compare.h"
struct DefaultCtableComp {
explicit DefaultCtableComp() { default_constructed_ = true; }
bool operator()(int, int) const { return false; }
bool default_constructed_ = false;
};
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
using IL = std::initializer_list<int>;
static_assert(std::is_constructible_v<M1, IL, const A1&>);
static_assert(std::is_constructible_v<M2, IL, const A2&>);
static_assert(!std::is_constructible_v<M1, IL, const A2&>);
static_assert(!std::is_constructible_v<M2, IL, const A1&>);
static_assert(std::is_constructible_v<M1, IL, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, IL, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, IL, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, IL, const C&, const A1&>);
}
{
// initializer_list<value_type> needs to match exactly
using M = std::flat_set<int>;
using C = typename M::key_compare;
static_assert(std::is_constructible_v<M, std::initializer_list<int>>);
static_assert(std::is_constructible_v<M, std::initializer_list<int>, C>);
static_assert(std::is_constructible_v<M, std::initializer_list<int>, C, std::allocator<int>>);
static_assert(std::is_constructible_v<M, std::initializer_list<int>, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, C>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, C, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, C>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, C, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::initializer_list<const int>, std::allocator<int>>);
}
int expected[] = {1, 2, 3, 5};
{
// flat_set(initializer_list<value_type>);
using M = std::flat_set<int>;
std::initializer_list<int> il = {5, 2, 2, 3, 1, 3};
M m(il);
assert(std::equal(m.begin(), m.end(), expected, expected + 4));
}
{
// flat_set(initializer_list<value_type>);
// explicit(false)
using M = std::flat_set<int>;
M m = {5, 2, 2, 3, 1, 3};
assert(std::equal(m.begin(), m.end(), expected, expected + 4));
}
{
// flat_set(initializer_list<value_type>);
using M = std::flat_set<int, std::greater<int>, std::deque<int, min_allocator<int>>>;
M m = {5, 2, 2, 3, 1, 3};
assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4));
}
{
using A = explicit_allocator<int>;
{
// flat_set(initializer_list<value_type>);
// different comparator
using M = std::flat_set<int, DefaultCtableComp, std::vector<int, A>>;
M m = {1, 2, 3};
assert(m.size() == 1);
LIBCPP_ASSERT(*m.begin() == 1);
assert(m.key_comp().default_constructed_);
}
{
// flat_set(initializer_list<value_type>, const Allocator&);
using M = std::flat_set<int, std::greater<int>, std::deque<int, A>>;
A a;
M m({5, 2, 2, 3, 1, 3}, a);
assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4));
}
}
{
// flat_set(initializer_list<value_type>, const key_compare&);
using C = test_less<int>;
using M = std::flat_set<int, C>;
auto m = M({5, 2, 2, 3, 1, 3}, C(10));
assert(std::equal(m.begin(), m.end(), expected, expected + 4));
assert(m.key_comp() == C(10));
// explicit(false)
M m2 = {{5, 2, 2, 1, 3, 3}, C(10)};
assert(m2 == m);
assert(m2.key_comp() == C(10));
}
{
// flat_set(initializer_list<value_type>, const key_compare&);
// Sorting uses the comparator that was passed in
using M = std::flat_set<int, std::function<bool(int, int)>, std::deque<int, min_allocator<int>>>;
auto m = M({5, 2, 2, 1, 3, 1}, std::greater<int>());
assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4));
assert(m.key_comp()(2, 1) == true);
}
{
// flat_set(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
using A = explicit_allocator<int>;
using M = std::flat_set<int, std::greater<int>, std::deque<int, A>>;
A a;
M m({5, 2, 2, 3, 1, 3}, {}, a);
assert(std::equal(m.rbegin(), m.rend(), expected, expected + 4));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,140 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class InputIterator>
// flat_set(InputIterator first, InputIterator last, const key_compare& comp = key_compare());
// template<class InputIterator, class Allocator>
// flat_set(InputIterator first, InputIterator last, const Allocator& a);
// template<class InputIterator, class Allocator>
// flat_set(InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
using Iter1 = typename M1::iterator;
using Iter2 = typename M2::iterator;
static_assert(std::is_constructible_v<M1, Iter1, Iter1, const A1&>);
static_assert(std::is_constructible_v<M2, Iter2, Iter2, const A2&>);
static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const A2&>);
static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const A1&>);
static_assert(std::is_constructible_v<M1, Iter1, Iter1, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, Iter2, Iter2, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, Iter1, Iter1, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, Iter2, Iter2, const C&, const A1&>);
}
int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3};
int expected[] = {1, 2, 3};
{
// flat_set(InputIterator , InputIterator)
// cpp17_input_iterator
using M = std::flat_set<int>;
auto m = M(cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 9));
assert(std::ranges::equal(m, expected));
// explicit(false)
M m2 = {cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 9)};
assert(m2 == m);
}
{
// flat_set(InputIterator , InputIterator)
// greater
using M = std::flat_set<int, std::greater<int>, std::deque<int, min_allocator<int>>>;
auto m = M(cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 9));
assert(std::ranges::equal(m, std::deque<int, min_allocator<int>>{3, 2, 1}));
}
{
// flat_set(InputIterator , InputIterator)
// Test when the operands are of array type (also contiguous iterator type)
using M = std::flat_set<int, std::greater<int>, std::vector<int, min_allocator<int>>>;
auto m = M(ar, ar);
assert(m.empty());
}
{
// flat_set(InputIterator , InputIterator, const key_compare&)
using C = test_less<int>;
using M = std::flat_set<int, C, std::vector<int>>;
auto m = M(ar, ar + 9, C(3));
assert(std::ranges::equal(m, expected));
assert(m.key_comp() == C(3));
// explicit(false)
M m2 = {ar, ar + 9, C(3)};
assert(m2 == m);
assert(m2.key_comp() == C(3));
}
{
// flat_set(InputIterator , InputIterator, const Allocator&)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::vector<int, A1>>;
auto m = M(ar, ar + 9, A1(5));
assert(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(InputIterator , InputIterator, const Allocator&)
// explicit(false)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::vector<int, A1>>;
M m = {ar, ar + 9, A1(5)}; // implicit ctor
assert(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&)
using C = test_less<int>;
using A1 = test_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A1>>;
auto m = M(ar, ar + 9, C(3), A1(5));
assert(std::ranges::equal(m, expected));
assert(m.key_comp() == C(3));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(InputIterator , InputIterator, const key_compare&, const Allocator&)
// explicit(false)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A1>>;
M m = {ar, ar + 9, {}, A1(5)}; // implicit ctor
assert(std::ranges::equal(m, expected));
LIBCPP_ASSERT(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,188 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(flat_set&&);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "../helpers.h"
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
#include "min_allocator.h"
void test() {
{
using C = test_less<int>;
using A = test_allocator<int>;
using M = std::flat_set<int, C, std::deque<int, A>>;
M mo = M({1, 2, 3}, C(5), A(7));
M m = std::move(mo);
assert((m == M{1, 2, 3}));
assert(m.key_comp() == C(5));
assert(std::move(m).extract().get_allocator() == A(7));
assert(mo.empty());
assert(mo.key_comp() == C(5));
assert(std::move(mo).extract().get_allocator().get_id() == test_alloc_base::moved_value);
}
{
using C = test_less<int>;
using A = min_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A>>;
M mo = M({1, 2, 3}, C(5), A());
M m = std::move(mo);
assert((m == M{1, 2, 3}));
assert(m.key_comp() == C(5));
assert(std::move(m).extract().get_allocator() == A());
assert(mo.empty());
assert(mo.key_comp() == C(5));
assert(std::move(mo).extract().get_allocator() == A());
}
{
// A moved-from flat_set maintains its class invariant in the presence of moved-from comparators.
using M = std::flat_set<int, std::function<bool(int, int)>>;
M mo = M({1, 2, 3}, std::less<int>());
M m = std::move(mo);
assert(m.size() == 3);
assert(std::is_sorted(m.begin(), m.end(), m.value_comp()));
assert(m.key_comp()(1, 2) == true);
assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));
LIBCPP_ASSERT(m.key_comp()(1, 2) == true);
LIBCPP_ASSERT(mo.empty());
mo.insert({1, 2, 3}); // insert has no preconditions
assert(m == mo);
}
{
// moved-from object maintains invariant if the underlying container does not clear after move
using M = std::flat_set<int, std::less<>, CopyOnlyVector<int>>;
M m1 = M({1, 2, 3});
M m2 = std::move(m1);
assert(m2.size() == 3);
check_invariant(m1);
LIBCPP_ASSERT(m1.empty());
LIBCPP_ASSERT(m1.size() == 0);
}
}
template <class T>
struct ThrowingMoveAllocator {
using value_type = T;
explicit ThrowingMoveAllocator() = default;
ThrowingMoveAllocator(const ThrowingMoveAllocator&) = default;
ThrowingMoveAllocator(ThrowingMoveAllocator&&) noexcept(false) {}
T* allocate(std::ptrdiff_t n) { return std::allocator<T>().allocate(n); }
void deallocate(T* p, std::ptrdiff_t n) { return std::allocator<T>().deallocate(p, n); }
friend bool operator==(ThrowingMoveAllocator, ThrowingMoveAllocator) = default;
};
struct ThrowingMoveComp {
ThrowingMoveComp() = default;
ThrowingMoveComp(const ThrowingMoveComp&) noexcept(true) {}
ThrowingMoveComp(ThrowingMoveComp&&) noexcept(false) {}
bool operator()(const auto&, const auto&) const { return false; }
};
struct MoveSensitiveComp {
MoveSensitiveComp() noexcept(false) = default;
MoveSensitiveComp(const MoveSensitiveComp&) noexcept = default;
MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; }
MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept(false) = default;
MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) {
rhs.is_moved_from_ = true;
return *this;
}
bool operator()(const auto&, const auto&) const { return false; }
bool is_moved_from_ = false;
};
void test_move_noexcept() {
{
using C = std::flat_set<int>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v<C>);
C c;
C d = std::move(c);
}
{
using C = std::flat_set<int, std::less<int>, std::deque<int, test_allocator<int>>>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_constructible_v<C>);
C c;
C d = std::move(c);
}
#if _LIBCPP_VERSION
{
// Container fails to be nothrow-move-constructible; this relies on libc++'s support for non-nothrow-copyable allocators
using C = std::flat_set<int, std::less<int>, std::deque<int, ThrowingMoveAllocator<int>>>;
static_assert(!std::is_nothrow_move_constructible_v<std::deque<int, ThrowingMoveAllocator<int>>>);
static_assert(!std::is_nothrow_move_constructible_v<C>);
C c;
C d = std::move(c);
}
#endif // _LIBCPP_VERSION
{
// Comparator fails to be nothrow-move-constructible
using C = std::flat_set<int, ThrowingMoveComp>;
static_assert(!std::is_nothrow_move_constructible_v<C>);
C c;
C d = std::move(c);
}
}
#if !defined(TEST_HAS_NO_EXCEPTIONS)
static int countdown = 0;
struct EvilContainer : std::vector<int> {
EvilContainer() = default;
EvilContainer(EvilContainer&& rhs) {
// Throw on move-construction.
if (--countdown == 0) {
rhs.insert(rhs.end(), 0);
rhs.insert(rhs.end(), 0);
throw 42;
}
}
};
void test_move_exception() {
{
using M = std::flat_set<int, std::less<int>, EvilContainer>;
M mo = {1, 2, 3};
countdown = 1;
try {
M m = std::move(mo);
assert(false); // not reached
} catch (int x) {
assert(x == 42);
}
// The source flat_set maintains its class invariant.
check_invariant(mo);
LIBCPP_ASSERT(mo.empty());
}
}
#endif // !defined(TEST_HAS_NO_EXCEPTIONS)
int main(int, char**) {
test();
test_move_noexcept();
#if !defined(TEST_HAS_NO_EXCEPTIONS)
test_move_exception();
#endif
return 0;
}

View File

@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(flat_set&&, const allocator_type&);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <ranges>
#include <vector>
#include "../helpers.h"
#include "test_macros.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, M1&&, const A1&>);
static_assert(std::is_constructible_v<M2, M2&&, const A2&>);
static_assert(!std::is_constructible_v<M1, M1&&, const A2&>);
static_assert(!std::is_constructible_v<M2, M2&&, const A1&>);
}
{
int expected[] = {1, 2, 3};
using C = test_less<int>;
using A = test_allocator<int>;
using M = std::flat_set<int, C, std::deque<int, A>>;
auto mo = M(expected, expected + 3, C(5), A(7));
auto m = M(std::move(mo), A(3));
assert(m.key_comp() == C(5));
assert(m.size() == 3);
auto keys = std::move(m).extract();
assert(keys.get_allocator() == A(3));
assert(std::ranges::equal(keys, expected));
// The original flat_set is moved-from.
assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));
assert(mo.empty());
assert(mo.key_comp() == C(5));
assert(std::move(mo).extract().get_allocator() == A(7));
}
{
// moved-from object maintains invariant if one of underlying container does not clear after move
using M = std::flat_set<int, std::less<>, CopyOnlyVector<int>>;
M m1 = M({1, 2, 3});
M m2(std::move(m1), std::allocator<int>{});
assert(m2.size() == 3);
check_invariant(m1);
LIBCPP_ASSERT(m1.empty());
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,241 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set& operator=(flat_set&&);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "test_macros.h"
#include "MoveOnly.h"
#include "../helpers.h"
#include "../../../test_compare.h"
#include "test_allocator.h"
#include "min_allocator.h"
struct MoveNegates {
int value_ = 0;
MoveNegates() = default;
MoveNegates(int v) : value_(v) {}
MoveNegates(MoveNegates&& rhs) : value_(rhs.value_) { rhs.value_ = -rhs.value_; }
MoveNegates& operator=(MoveNegates&& rhs) {
value_ = rhs.value_;
rhs.value_ = -rhs.value_;
return *this;
}
~MoveNegates() = default;
auto operator<=>(const MoveNegates&) const = default;
};
struct MoveClears {
int value_ = 0;
MoveClears() = default;
MoveClears(int v) : value_(v) {}
MoveClears(MoveClears&& rhs) : value_(rhs.value_) { rhs.value_ = 0; }
MoveClears& operator=(MoveClears&& rhs) {
value_ = rhs.value_;
rhs.value_ = 0;
return *this;
}
~MoveClears() = default;
auto operator<=>(const MoveClears&) const = default;
};
#if !defined(TEST_HAS_NO_EXCEPTIONS)
struct MoveAssignThrows : std::vector<int> {
using std::vector<int>::vector;
MoveAssignThrows& operator=(MoveAssignThrows&& other) {
push_back(0);
push_back(0);
other.push_back(0);
other.push_back(0);
throw 42;
}
};
#endif // TEST_HAS_NO_EXCEPTIONS
void test_move_assign_clears() {
// Preserves the class invariant for the moved-from flat_set.
{
const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8};
using M = std::flat_set<MoveNegates, std::less<MoveNegates>>;
M m = M(expected, expected + 8);
M m2 = M(expected, expected + 3);
m2 = std::move(m);
assert(std::equal(m2.begin(), m2.end(), expected, expected + 8));
LIBCPP_ASSERT(m.empty());
assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted
assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates
m.insert(1);
m.insert(2);
assert(m.contains(1));
assert(m.find(2) != m.end());
}
{
const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8};
using M = std::flat_set<MoveClears, std::less<MoveClears>>;
M m = M(expected, expected + 8);
M m2 = M(expected, expected + 3);
m2 = std::move(m);
assert(std::equal(m2.begin(), m2.end(), expected, expected + 8));
LIBCPP_ASSERT(m.empty());
assert(std::is_sorted(m.begin(), m.end(), m.key_comp())); // still sorted
assert(std::adjacent_find(m.begin(), m.end(), m.key_comp()) == m.end()); // still contains no duplicates
m.insert(1);
m.insert(2);
assert(m.contains(1));
assert(m.find(2) != m.end());
}
{
// moved-from object maintains invariant if one of underlying container does not clear after move
using M = std::flat_set<int, std::less<>, std::vector<int>>;
M m1 = M({1, 2, 3});
M m2 = M({1, 2});
m2 = std::move(m1);
assert(m2.size() == 3);
check_invariant(m1);
LIBCPP_ASSERT(m1.empty());
}
#if !defined(TEST_HAS_NO_EXCEPTIONS)
{
using M = std::flat_set<int, std::less<>, MoveAssignThrows>;
M m1 = {1, 2, 3};
M m2 = {1, 2};
try {
m2 = std::move(m1);
assert(false);
} catch (int e) {
assert(e == 42);
}
check_invariant(m1);
check_invariant(m2);
LIBCPP_ASSERT(m1.empty());
LIBCPP_ASSERT(m2.empty());
}
#endif // TEST_HAS_NO_EXCEPTIONS
}
struct MoveSensitiveComp {
MoveSensitiveComp() noexcept(false) = default;
MoveSensitiveComp(const MoveSensitiveComp&) noexcept(false) = default;
MoveSensitiveComp(MoveSensitiveComp&& rhs) { rhs.is_moved_from_ = true; }
MoveSensitiveComp& operator=(const MoveSensitiveComp&) noexcept = default;
MoveSensitiveComp& operator=(MoveSensitiveComp&& rhs) {
rhs.is_moved_from_ = true;
return *this;
}
bool operator()(const auto&, const auto&) const { return false; }
bool is_moved_from_ = false;
};
struct MoveThrowsComp {
MoveThrowsComp(MoveThrowsComp&&) noexcept(false);
MoveThrowsComp(const MoveThrowsComp&) noexcept(true);
MoveThrowsComp& operator=(MoveThrowsComp&&) noexcept(false);
MoveThrowsComp& operator=(const MoveThrowsComp&) noexcept(true);
bool operator()(const auto&, const auto&) const;
};
void test_move_assign_no_except() {
// This tests a conforming extension
{
using C = std::flat_set<int, int>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);
}
{
using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, test_allocator<MoveOnly>>>;
static_assert(!std::is_nothrow_move_assignable_v<C>);
}
{
using C = std::flat_set<int, std::less<int>, std::vector<int, test_allocator<int>>>;
static_assert(!std::is_nothrow_move_assignable_v<C>);
}
{
using C = std::flat_set<MoveOnly, std::less<MoveOnly>, std::vector<MoveOnly, other_allocator<MoveOnly>>>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);
}
{
using C = std::flat_set<int, std::less<int>, std::vector<int, other_allocator<int>>>;
LIBCPP_STATIC_ASSERT(std::is_nothrow_move_assignable_v<C>);
}
{
// Test with a comparator that throws on move-assignment.
using C = std::flat_set<int, MoveThrowsComp>;
LIBCPP_STATIC_ASSERT(!std::is_nothrow_move_assignable_v<C>);
}
{
// Test with a container that throws on move-assignment.
using C = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
static_assert(!std::is_nothrow_move_assignable_v<C>);
}
}
void test() {
{
using C = test_less<int>;
using A1 = test_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A1>>;
M mo = M({1, 2, 3}, C(5), A1(7));
M m = M({}, C(3), A1(7));
std::same_as<M&> decltype(auto) r = m = std::move(mo);
assert(&r == &m);
assert((m == M{1, 2, 3}));
assert(m.key_comp() == C(5));
auto ks = std::move(m).extract();
assert(ks.get_allocator() == A1(7));
assert(mo.empty());
}
{
using C = test_less<int>;
using A1 = other_allocator<int>;
using M = std::flat_set<int, C, std::deque<int, A1>>;
M mo = M({4, 5}, C(5), A1(7));
M m = M({1, 2, 3, 4}, C(3), A1(7));
std::same_as<M&> decltype(auto) r = m = std::move(mo);
assert(&r == &m);
assert((m == M{4, 5}));
assert(m.key_comp() == C(5));
auto ks = std::move(m).extract();
assert(ks.get_allocator() == A1(7));
assert(mo.empty());
}
{
using A = min_allocator<int>;
using M = std::flat_set<int, std::greater<int>, std::vector<int, A>>;
M mo = M({5, 4, 3}, A());
M m = M({4, 3, 2, 1}, A());
std::same_as<M&> decltype(auto) r = m = std::move(mo);
assert(&r == &m);
assert((m == M{5, 4, 3}));
auto ks = std::move(m).extract();
assert(ks.get_allocator() == A());
assert(mo.empty());
}
}
int main(int, char**) {
test();
test_move_assign_clears();
test_move_assign_no_except();
return 0;
}

View File

@ -0,0 +1,326 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: availability-pmr-missing
// <flat_set>
// Test various constructors with pmr
#include <algorithm>
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <memory_resource>
#include <ranges>
#include <vector>
#include <string>
#include "test_iterators.h"
#include "test_macros.h"
#include "test_allocator.h"
#include "../../../test_compare.h"
void test() {
{
// flat_set(const Allocator& a);
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::polymorphic_allocator<int> pa = &mr;
auto m1 = M(pa);
assert(m1.empty());
assert(std::move(m1).extract().get_allocator() == pa);
auto m2 = M(&mr);
assert(m2.empty());
assert(std::move(m2).extract().get_allocator() == pa);
}
{
// flat_set(const key_compare& comp, const Alloc& a);
using M = std::flat_set<int, std::function<bool(int, int)>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
vm.emplace_back(std::greater<int>());
assert(vm[0] == M{});
assert(vm[0].key_comp()(2, 1) == true);
assert(vm[0].value_comp()(2, 1) == true);
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(const key_container_type& key_cont, const mapped_container_type& mapped_cont,
// const Allocator& a);
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
std::pmr::vector<int> ks = {1, 1, 1, 2, 2, 3, 2, 3, 3};
assert(ks.get_allocator().resource() != &mr);
vm.emplace_back(ks);
assert(ks.size() == 9); // ks' value is unchanged, since it was an lvalue above
assert((vm[0] == M{1, 2, 3}));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(const flat_set&, const allocator_type&);
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr1;
std::pmr::monotonic_buffer_resource mr2;
M mo = M({1, 2, 3}, C(5), &mr1);
M m = {mo, &mr2}; // also test the implicitness of this constructor
assert(m.key_comp() == C(5));
auto keys = std::move(m).extract();
assert((keys == std::pmr::vector<int>{1, 2, 3}));
assert(keys.get_allocator().resource() == &mr2);
// mo is unchanged
assert(mo.key_comp() == C(5));
auto keys2 = std::move(mo).extract();
assert((keys2 == std::pmr::vector<int>{1, 2, 3}));
assert(keys2.get_allocator().resource() == &mr1);
}
{
// flat_set(const flat_set&, const allocator_type&);
using M = std::flat_set<int, std::less<>, std::pmr::vector<int>>;
std::pmr::vector<M> vs;
M m = {1, 2, 3};
vs.push_back(m);
assert(vs[0] == m);
}
{
// flat_set& operator=(const flat_set& m);
// pmr allocator is not propagated
using M = std::flat_set<int, std::less<>, std::pmr::deque<int>>;
std::pmr::monotonic_buffer_resource mr1;
std::pmr::monotonic_buffer_resource mr2;
M mo = M({1, 2, 3}, &mr1);
M m = M({4, 5}, &mr2);
m = mo;
assert((m == M{1, 2, 3}));
assert(std::move(m).extract().get_allocator().resource() == &mr2);
// mo is unchanged
assert((mo == M{1, 2, 3}));
assert(std::move(mo).extract().get_allocator().resource() == &mr1);
}
{
// flat_set(const flat_set& m);
using C = test_less<int>;
std::pmr::monotonic_buffer_resource mr;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
auto mo = M({1, 2, 3}, C(5), &mr);
auto m = mo;
assert(m.key_comp() == C(5));
assert((m == M{1, 2, 3}));
auto ks = std::move(m).extract();
assert(ks.get_allocator().resource() == std::pmr::get_default_resource());
// mo is unchanged
assert(mo.key_comp() == C(5));
assert((mo == M{1, 2, 3}));
auto kso = std::move(mo).extract();
assert(kso.get_allocator().resource() == &mr);
}
{
// flat_set(initializer_list<value_type> il, const Alloc& a);
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
std::initializer_list<M::value_type> il = {3, 1, 4, 1, 5};
vm.emplace_back(il);
assert((vm[0] == M{1, 3, 4, 5}));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(initializer_list<value_type> il, const key_compare& comp, const Alloc& a);
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::deque<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
std::initializer_list<M::value_type> il = {3, 1, 4, 1, 5};
vm.emplace_back(il, C(5));
assert((vm[0] == M{1, 3, 4, 5}));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
assert(vm[0].key_comp() == C(5));
}
{
// flat_set(InputIterator first, InputIterator last, const Allocator& a);
int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3};
int expected[] = {1, 2, 3};
{
// cpp17 iterator
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
vm.emplace_back(cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 9));
assert(std::ranges::equal(vm[0], expected));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
vm.emplace_back(ar, ar);
assert(vm[0].empty());
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
}
{
// flat_set(flat_set&&, const allocator_type&);
int expected[] = {1, 2, 3};
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr1;
std::pmr::monotonic_buffer_resource mr2;
M mo = M({1, 3, 1, 2}, C(5), &mr1);
M m = {std::move(mo), &mr2}; // also test the implicitness of this constructor
assert(m.key_comp() == C(5));
assert(m.size() == 3);
assert(std::equal(m.begin(), m.end(), expected, expected + 3));
assert(std::move(m).extract().get_allocator().resource() == &mr2);
// The original flat_set is moved-from.
assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));
assert(mo.key_comp() == C(5));
assert(std::move(mo).extract().get_allocator().resource() == &mr1);
}
{
// flat_set(flat_set&&, const allocator_type&);
using M = std::flat_set<int, std::less<>, std::pmr::deque<int>>;
std::pmr::vector<M> vs;
M m = {1, 3, 1, 2};
vs.push_back(std::move(m));
assert((std::move(vs[0]).extract() == std::pmr::deque<int>{1, 2, 3}));
}
{
// flat_set& operator=(flat_set&&);
using M = std::flat_set<std::pmr::string, std::less<>, std::pmr::vector<std::pmr::string>>;
std::pmr::monotonic_buffer_resource mr1;
std::pmr::monotonic_buffer_resource mr2;
M mo =
M({"short", "very long string that definitely won't fit in the SSO buffer and therefore becomes empty on move"},
&mr1);
M m = M({"don't care"}, &mr2);
m = std::move(mo);
assert(m.size() == 2);
assert(std::is_sorted(m.begin(), m.end(), m.value_comp()));
assert(m.begin()->get_allocator().resource() == &mr2);
assert(std::is_sorted(mo.begin(), mo.end(), mo.value_comp()));
mo.insert("foo");
assert(mo.begin()->get_allocator().resource() == &mr1);
}
{
// flat_set(from_range_t, R&&, const Alloc&);
int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3};
int expected[] = {1, 2, 3};
{
// input_range
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
using Iter = cpp20_input_iterator<const int*>;
using Sent = sentinel_wrapper<Iter>;
using R = std::ranges::subrange<Iter, Sent>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
vm.emplace_back(std::from_range, R(Iter(ar), Sent(Iter(ar + 9))));
assert(std::ranges::equal(vm[0], expected));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
using R = std::ranges::subrange<const int*>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
vm.emplace_back(std::from_range, R(ar, ar));
assert(vm[0].empty());
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
}
{
// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a);
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
std::pmr::vector<int> ks = {1, 2, 4, 10};
vm.emplace_back(std::sorted_unique, ks);
assert(!ks.empty()); // it was an lvalue above
assert((vm[0] == M{1, 2, 4, 10}));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(sorted_unique_t, const container_type& key_cont,const Alloc& a);
using M = std::flat_set<int, std::less<int>, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
std::pmr::vector<int> ks({1, 2, 4, 10}, &mr);
vm.emplace_back(std::sorted_unique, ks);
assert((vm[0] == M{1, 2, 4, 10}));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
// cpp_17
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
int ar[] = {1, 2, 4, 5};
vm.emplace_back(
std::sorted_unique, cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 4), C(3));
assert((vm[0] == M{1, 2, 4, 5}));
assert(vm[0].key_comp() == C(3));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
int ar[1] = {42};
vm.emplace_back(std::sorted_unique, ar, ar, C(4));
assert(vm[0] == M{});
assert(vm[0].key_comp() == C(4));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(InputIterator first, InputIterator last, const Alloc& a);
// cpp_17
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
int ar[] = {1, 2, 4, 5};
vm.emplace_back(
std::sorted_unique, cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 4), C(3));
assert((vm[0] == M{1, 2, 4, 5}));
assert(vm[0].key_comp() == C(3));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
{
// flat_set(InputIterator first, InputIterator last, const Alloc& a);
using C = test_less<int>;
using M = std::flat_set<int, C, std::pmr::vector<int>>;
std::pmr::monotonic_buffer_resource mr;
std::pmr::vector<M> vm(&mr);
int ar[1] = {42};
vm.emplace_back(std::sorted_unique, ar, ar, C(4));
assert(vm[0] == M{});
assert(vm[0].key_comp() == C(4));
assert(std::move(vm[0]).extract().get_allocator().resource() == &mr);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,177 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<container-compatible-range<value_type> R>
// flat_set(from_range_t, R&&)
// template<container-compatible-range<value_type> R>
// flat_set(from_range_t, R&&, const key_compare&)
// template<container-compatible-range<value_type> R, class Alloc>
// flat_set(from_range_t, R&&, const Alloc&);
// template<container-compatible-range<value_type> R, class Alloc>
// flat_set(from_range_t, R&&, const key_compare&, const Alloc&);
#include <algorithm>
#include <deque>
#include <flat_set>
#include <functional>
#include <string>
#include <vector>
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
// test constraint container-compatible-range
template <class V>
using RangeOf = std::ranges::subrange<V*>;
using Set = std::flat_set<int>;
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<short>>);
static_assert(!std::is_constructible_v<Set, std::from_range_t, RangeOf<std::pair<int, int>>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<int>, std::less<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<short>, std::less<int>>);
static_assert(!std::is_constructible_v<Set, std::from_range_t, RangeOf<std::pair<int, int>>, std::less<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<int>, std::allocator<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<short>, std::allocator<int>>);
static_assert(!std::is_constructible_v<Set, std::from_range_t, RangeOf<std::pair<int, int>>, std::allocator<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<int>, std::less<int>, std::allocator<int>>);
static_assert(std::is_constructible_v<Set, std::from_range_t, RangeOf<int>, std::less<int>, std::allocator<int>>);
static_assert(
!std::
is_constructible_v<Set, std::from_range_t, RangeOf<std::pair<int, int>>, std::less<int>, std::allocator<int>>);
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const A1&>);
static_assert(std::is_constructible_v<M2, std::from_range_t, M2, const A2&>);
static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const A2&>);
static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const A1&>);
static_assert(std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, std::from_range_t, M2, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, std::from_range_t, M1, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, std::from_range_t, M2, const C&, const A1&>);
}
int ar[] = {1, 1, 1, 2, 2, 3, 2, 3, 3};
int expected[] = {1, 2, 3};
{
// flat_set(from_range_t, R&&)
// input_range && !common
using M = std::flat_set<int>;
using Iter = cpp20_input_iterator<const int*>;
using Sent = sentinel_wrapper<Iter>;
using R = std::ranges::subrange<Iter, Sent>;
auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9))));
assert(std::ranges::equal(m, expected));
LIBCPP_ASSERT(std::ranges::equal(m, expected));
// explicit(false)
M m2 = {std::from_range, R(Iter(ar), Sent(Iter(ar + 9)))};
assert(m2 == m);
}
{
// flat_set(from_range_t, R&&)
// greater
using M = std::flat_set<int, std::greater<int>, std::deque<int, min_allocator<int>>>;
using Iter = cpp20_input_iterator<const int*>;
using Sent = sentinel_wrapper<Iter>;
using R = std::ranges::subrange<Iter, Sent>;
auto m = M(std::from_range, R(Iter(ar), Sent(Iter(ar + 9))));
assert(std::ranges::equal(m, std::deque<int, min_allocator<int>>{3, 2, 1}));
}
{
// flat_set(from_range_t, R&&)
// contiguous range
using M = std::flat_set<int>;
using R = std::ranges::subrange<const int*>;
auto m = M(std::from_range, R(ar, ar + 9));
assert(std::ranges::equal(m, expected));
}
{
// flat_set(from_range_t, R&&, const key_compare&)
using C = test_less<int>;
using M = std::flat_set<int, C, std::vector<int>>;
using R = std::ranges::subrange<const int*>;
auto m = M(std::from_range, R(ar, ar + 9), C(3));
assert(std::ranges::equal(m, expected));
assert(m.key_comp() == C(3));
// explicit(false)
M m2 = {std::from_range, R(ar, ar + 9), C(3)};
assert(m2 == m);
assert(m2.key_comp() == C(3));
}
{
// flat_set(from_range_t, R&&, const Allocator&)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::vector<int, A1>>;
using R = std::ranges::subrange<const int*>;
auto m = M(std::from_range, R(ar, ar + 9), A1(5));
assert(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(from_range_t, R&&, const Allocator&)
// explicit(false)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A1>>;
using R = std::ranges::subrange<const int*>;
M m = {std::from_range, R(ar, ar + 9), A1(5)}; // implicit ctor
assert(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(from_range_t, R&&, const key_compare&, const Allocator&)
using C = test_less<int>;
using A1 = test_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A1>>;
using R = std::ranges::subrange<const int*>;
auto m = M(std::from_range, R(ar, ar + 9), C(3), A1(5));
assert(std::ranges::equal(m, expected));
assert(m.key_comp() == C(3));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(from_range_t, R&&, const key_compare&, const Allocator&)
// explicit(false)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A1>>;
using R = std::ranges::subrange<const int*>;
M m = {std::from_range, R(ar, ar + 9), {}, A1(5)}; // implicit ctor
assert(std::ranges::equal(m, expected));
assert(std::move(m).extract().get_allocator() == A1(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,147 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set(sorted_unique_t, container_type key_cont, const key_compare& comp = key_compare());
//
// template<class Alloc>
// flat_set(sorted_unique_t, const container_type& key_cont, const Alloc& a);
// template<class Alloc>
// flat_set(sorted_unique_t, const container_type& key_cont,
// const key_compare& comp, const Alloc& a);
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "min_allocator.h"
#include "MoveOnly.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, const V1&, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, const V2&, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, const V1&, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, const V2&, const A1&>);
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, const V1&, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, const V2&, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, const V1&, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, const V2&, const C&, const A1&>);
}
{
// flat_set(sorted_unique_t, container_type)
using M = std::flat_set<int>;
std::vector<int> ks = {1, 2, 4, 10};
auto ks2 = ks;
auto m = M(std::sorted_unique, ks);
assert((m == M{1, 2, 4, 10}));
m = M(std::sorted_unique, std::move(ks));
assert(ks.empty()); // it was moved-from
assert((m == M{1, 2, 4, 10}));
// explicit(false)
M m2 = {std::sorted_unique, std::move(ks2)};
assert(m == m2);
}
{
// flat_set(sorted_unique_t, container_type)
// non-default container, comparator and allocator type
using Ks = std::deque<int, min_allocator<int>>;
using M = std::flat_set<int, std::greater<int>, Ks>;
Ks ks = {10, 4, 2, 1};
auto m = M(std::sorted_unique, ks);
assert((m == M{1, 2, 4, 10}));
m = M(std::sorted_unique, std::move(ks));
assert(ks.empty()); // it was moved-from
assert((m == M{1, 2, 4, 10}));
}
{
// flat_set(sorted_unique_t, container_type)
// allocator copied into the containers
using A = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A>>;
auto ks = std::deque<int, A>({1, 2, 4, 10}, A(4));
auto m = M(std::sorted_unique, std::move(ks));
assert(ks.empty()); // it was moved-from
assert((m == M{1, 2, 4, 10}));
assert(std::move(m).extract().get_allocator() == A(4));
}
{
// flat_set(sorted_unique_t, container_type , key_compare)
using C = test_less<int>;
using M = std::flat_set<int, C>;
std::vector<int> ks = {1, 2, 4, 10};
auto m = M(std::sorted_unique, ks, C(4));
assert((m == M{1, 2, 4, 10}));
assert(m.key_comp() == C(4));
// explicit(false)
M m2 = {std::sorted_unique, ks, C(4)};
assert(m2 == m);
assert(m2.key_comp() == C(4));
}
{
// flat_set(sorted_unique_t, container_type , key_compare, const Allocator&)
using C = test_less<int>;
using A = test_allocator<int>;
using M = std::flat_set<int, C, std::vector<int, A>>;
std::vector<int, A> ks = {1, 2, 4, 10};
auto m = M(std::sorted_unique, ks, C(4), A(5));
assert((m == M{1, 2, 4, 10}));
assert(m.key_comp() == C(4));
assert(M(m).extract().get_allocator() == A(5));
// explicit(false)
M m2 = {ks, C(4), A(5)};
assert(m2 == m);
assert(m2.key_comp() == C(4));
assert(std::move(m2).extract().get_allocator() == A(5));
}
{
// flat_set(sorted_unique_t, container_type , const Allocator&)
using A = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::deque<int, A>>;
auto ks = std::deque<int, A>({1, 2, 4, 10}, A(4));
auto m = M(std::sorted_unique, ks, A(6)); // replaces the allocators
assert(!ks.empty()); // it was an lvalue above
assert((m == M{1, 2, 4, 10}));
assert(M(m).extract().get_allocator() == A(6));
// explicit(false)
M m2 = {std::sorted_unique, ks, A(6)};
assert(m2 == m);
assert(std::move(m2).extract().get_allocator() == A(6));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,154 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class InputIterator>
// flat_set(sorted_unique_t s, initializer_list<value_type> il,
// const key_compare& comp = key_compare())
// template<class Alloc>
// flat_set(sorted_unique_t, initializer_list<value_type> il, const Alloc& a);
// template<class Alloc>
// flat_set(sorted_unique_t, initializer_list<value_type> il,
// const key_compare& comp, const Alloc& a);
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
template <class T>
std::initializer_list<T> il = {1, 2, 4, 5};
void test() {
const auto il1 = il<int>;
const auto il2 = il<short>;
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
using IL = std::initializer_list<int>;
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, IL, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, IL, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, IL, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, IL, const A1&>);
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, IL, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, IL, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, IL, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, IL, const C&, const A1&>);
}
{
// initializer_list<value_type> needs to match exactly
using M = std::flat_set<int>;
using C = typename M::key_compare;
static_assert(std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<int>>);
static_assert(std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<int>, C>);
static_assert(std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<int>, C, std::allocator<int>>);
static_assert(std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<int>, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>>);
static_assert(!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, C>);
static_assert(
!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, C, std::allocator<int>>);
static_assert(
!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, std::allocator<int>>);
static_assert(!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>>);
static_assert(!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, C>);
static_assert(
!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, C, std::allocator<int>>);
static_assert(
!std::is_constructible_v<M, std::sorted_unique_t, std::initializer_list<const int>, std::allocator<int>>);
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>);
using M = std::flat_set<int>;
auto m = M(std::sorted_unique, il1);
auto expected = M{1, 2, 4, 5};
assert(m == expected);
// explicit(false)
M m2 = {std::sorted_unique, il1};
assert(m2 == m);
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>, const key_compare&);
using M = std::flat_set<int, std::function<bool(int, int)>>;
auto m = M(std::sorted_unique, il1, std::less<int>());
assert(m == M({1, 2, 4, 5}, std::less<>()));
assert(m.key_comp()(1, 2) == true);
// explicit(false)
M m2 = {std::sorted_unique, il1, std::less<int>()};
assert(m2 == m);
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>, const key_compare&);
// greater
using M = std::flat_set<int, std::greater<int>, std::deque<int, min_allocator<int>>>;
std::initializer_list<int> il4{5, 4, 2, 1};
auto m = M(std::sorted_unique, il4, std::greater<int>());
assert((m == M{5, 4, 2, 1}));
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>, const Allocator&)
using A1 = test_allocator<short>;
using M = std::flat_set<short, std::less<int>, std::deque<short, A1>>;
auto m = M(std::sorted_unique, il2, A1(5));
auto expected = M{1, 2, 4, 5};
assert(m == expected);
assert(M(m).extract().get_allocator() == A1(5));
// explicit(false)
M m2 = {std::sorted_unique, il2, A1(5)};
assert(m2 == m);
assert(std::move(m2).extract().get_allocator() == A1(5));
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>, const key_compare&, const Allocator&);
using C = test_less<int>;
using A1 = test_allocator<short>;
using M = std::flat_set<short, C, std::vector<short, A1>>;
auto m = M(std::sorted_unique, il2, C(3), A1(5));
assert((m == M{1, 2, 4, 5}));
assert(m.key_comp() == C(3));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(sorted_unique_t, initializer_list<value_type>, const key_compare&, const Allocator&);
// explicit(false)
using A1 = test_allocator<short>;
using M = std::flat_set<short, std::less<int>, std::deque<short, A1>>;
M m = {std::sorted_unique, il2, {}, A1(5)}; // implicit ctor
assert((m == M{1, 2, 4, 5}));
assert(std::move(m).extract().get_allocator() == A1(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,160 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class InputIterator>
// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp = key_compare());
// template<class InputIterator, class Alloc>
// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Alloc& a);
// template<class InputIterator, class Allocator>
// flat_set(sorted_unique_t, InputIterator first, InputIterator last, const key_compare& comp, const Allocator& a);
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "test_macros.h"
#include "../../../test_compare.h"
void test() {
{
// The constructors in this subclause shall not participate in overload
// resolution unless uses_allocator_v<container_type, Alloc> is true.
using C = test_less<int>;
using A1 = test_allocator<int>;
using A2 = other_allocator<int>;
using V1 = std::vector<int, A1>;
using V2 = std::vector<int, A2>;
using M1 = std::flat_set<int, C, V1>;
using M2 = std::flat_set<int, C, V2>;
using Iter1 = typename M1::iterator;
using Iter2 = typename M2::iterator;
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, Iter1, Iter1, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, Iter2, Iter2, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, Iter1, Iter1, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, Iter2, Iter2, const A1&>);
static_assert(std::is_constructible_v<M1, std::sorted_unique_t, Iter1, Iter1, const C&, const A1&>);
static_assert(std::is_constructible_v<M2, std::sorted_unique_t, Iter2, Iter2, const C&, const A2&>);
static_assert(!std::is_constructible_v<M1, std::sorted_unique_t, Iter1, Iter1, const C&, const A2&>);
static_assert(!std::is_constructible_v<M2, std::sorted_unique_t, Iter2, Iter2, const C&, const A1&>);
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator);
// cpp17_input_iterator
using M = std::flat_set<int>;
int ar[] = {1, 2, 4, 5};
auto m = M(std::sorted_unique, cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 4));
auto expected = M{1, 2, 4, 5};
assert(m == expected);
// explicit(false)
M m2 = {std::sorted_unique, cpp17_input_iterator<const int*>(ar), cpp17_input_iterator<const int*>(ar + 4)};
assert(m2 == m);
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator);
// contiguous iterator
using C = test_less<int>;
using M = std::flat_set<int, C, std::vector<int, min_allocator<int>>>;
int ar[] = {1, 2, 4, 5};
auto m = M(std::sorted_unique, ar, ar + 4);
auto expected = M{1, 2, 4, 5};
assert(m == expected);
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&);
// cpp_17_input_iterator
using M = std::flat_set<int, std::function<bool(int, int)>>;
int ar[] = {1, 2, 4, 5};
auto m = M(std::sorted_unique,
cpp17_input_iterator<const int*>(ar),
cpp17_input_iterator<const int*>(ar + 4),
std::less<int>());
assert(m == M({1, 2, 4, 5}, std::less<>()));
assert(m.key_comp()(1, 2) == true);
// explicit(false)
M m2 = {std::sorted_unique,
cpp17_input_iterator<const int*>(ar),
cpp17_input_iterator<const int*>(ar + 4),
std::less<int>()};
assert(m2 == m);
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&);
// greater
using M = std::flat_set<int, std::greater<int>, std::deque<int, min_allocator<int>>>;
int ar[] = {5, 4, 2, 1};
auto m = M(std::sorted_unique,
cpp17_input_iterator<const int*>(ar),
cpp17_input_iterator<const int*>(ar + 4),
std::greater<int>());
assert((m == M{5, 4, 2, 1}));
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&);
// contiguous iterator
using C = test_less<int>;
using M = std::flat_set<int, C, std::vector<int, min_allocator<int>>>;
int ar[1] = {42};
auto m = M(std::sorted_unique, ar, ar, C(5));
assert(m.empty());
assert(m.key_comp() == C(5));
}
{
// flat_set(sorted_unique_t, InputIterator , InputIterator, const Allocator&)
using A1 = test_allocator<int>;
using M = std::flat_set<int, std::less<int>, std::vector<int, A1>>;
int ar[] = {1, 2, 4, 5};
auto m = M(std::sorted_unique, ar, ar + 4, A1(5));
auto expected = M{1, 2, 4, 5};
assert(m == expected);
assert(M(m).extract().get_allocator() == A1(5));
// explicit(false)
M m2 = {std::sorted_unique, ar, ar + 4, A1(5)};
assert(m2 == m);
assert(std::move(m2).extract().get_allocator() == A1(5));
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&);
using C = test_less<int>;
using A1 = test_allocator<int>;
using M = std::flat_set<int, C, std::deque<int, A1>>;
int ar[] = {1, 2, 4, 5};
auto m = M(std::sorted_unique, ar, ar + 4, C(3), A1(5));
assert((m == M{1, 2, 4, 5}));
assert(m.key_comp() == C(3));
assert(std::move(m).extract().get_allocator() == A1(5));
}
{
// flat_set(sorted_unique_t, InputIterator, InputIterator, const key_compare&, const Allocator&);
// explicit(false)
using A1 = test_allocator<short>;
using M = std::flat_set<short, std::less<int>, std::deque<short, A1>>;
int ar[] = {1, 2, 4, 5};
M m = {std::sorted_unique, ar, ar + 4, {}, A1(5)}; // implicit ctor
assert((m == M{1, 2, 4, 5}));
assert(std::move(m).extract().get_allocator() == A1(5));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,101 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// 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);
#include <deque>
#include <flat_set>
#include <functional>
#include <initializer_list>
#include <vector>
#include "test_macros.h"
#include "test_allocator.h"
#include "min_allocator.h"
// Verify that `flat_set` (like `set`) does NOT support std::erase.
//
template <class S>
concept HasStdErase = requires(S& s, typename S::value_type x) { std::erase(s, x); };
static_assert(HasStdErase<std::vector<int>>);
static_assert(!HasStdErase<std::flat_set<int>>);
template <class M>
M make(std::initializer_list<int> vals) {
M ret;
for (int v : vals)
ret.emplace(v);
return ret;
}
template <class M, class Pred>
void test0(
std::initializer_list<int> vals, Pred p, std::initializer_list<int> expected, std::size_t expected_erased_count) {
M s = make<M>(vals);
ASSERT_SAME_TYPE(typename M::size_type, decltype(std::erase_if(s, p)));
assert(expected_erased_count == std::erase_if(s, p));
assert(s == make<M>(expected));
}
struct NotBool {
bool b;
explicit operator bool() const { return b; }
};
template <class S>
void test_one() {
// Test all the plausible signatures for this predicate.
auto is1 = [](typename S::const_reference v) { return v == 1; };
auto is2 = [](typename S::value_type v) { return v == 2; };
auto is3 = [](const typename S::value_type& v) { return v == 3; };
auto is4 = [](auto v) { return v == 4; };
auto True = [](const auto&) { return true; };
auto False = [](auto&&) { return false; };
auto nonBoolIs1 = [](const auto& v) { return NotBool{v == 1}; };
test0<S>({}, is1, {}, 0);
test0<S>({1}, is1, {}, 1);
test0<S>({1}, is2, {1}, 0);
test0<S>({1, 2}, is1, {2}, 1);
test0<S>({1, 2}, is2, {1}, 1);
test0<S>({1, 2}, is3, {1, 2}, 0);
test0<S>({1, 2, 3}, is1, {2, 3}, 1);
test0<S>({1, 2, 3}, is2, {1, 3}, 1);
test0<S>({1, 2, 3}, is3, {1, 2}, 1);
test0<S>({1, 2, 3}, is4, {1, 2, 3}, 0);
test0<S>({1, 2, 3}, True, {}, 3);
test0<S>({1, 2, 3}, False, {1, 2, 3}, 0);
test0<S>({1, 2, 3}, nonBoolIs1, {2, 3}, 1);
}
void test() {
test_one<std::flat_set<int>>();
test_one<std::flat_set<int, std::less<int>, std::vector<int, min_allocator<int>>>>();
test_one<std::flat_set<int, std::greater<int>, std::vector<int, test_allocator<int>>>>();
test_one<std::flat_set<int, std::less<int>, std::deque<int, min_allocator<int>>>>();
test_one<std::flat_set<int, std::greater<int>, std::deque<int, test_allocator<int>>>>();
test_one<std::flat_set<long>>();
test_one<std::flat_set<double>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,133 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-exceptions
// <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);
// If any member function in [flat.set.defn] exits via an exception, the invariant is restored.
// (This is not a member function, but let's respect the invariant anyway.)
#include <algorithm>
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "../helpers.h"
#include "test_macros.h"
struct Counter {
int c1, c2, throws;
void tick() {
c1 -= 1;
if (c1 == 0) {
c1 = c2;
throws += 1;
throw 42;
}
}
};
Counter g_counter = {0, 0, 0};
struct ThrowingAssignment {
ThrowingAssignment(int i) : i_(i) {}
ThrowingAssignment(const ThrowingAssignment&) = default;
ThrowingAssignment& operator=(const ThrowingAssignment& rhs) {
g_counter.tick();
i_ = rhs.i_;
g_counter.tick();
return *this;
}
operator int() const { return i_; }
int i_;
};
struct ThrowingComparator {
bool operator()(const ThrowingAssignment& a, const ThrowingAssignment& b) const {
g_counter.tick();
return a.i_ < b.i_;
}
};
struct ErasurePredicate {
bool operator()(const auto& x) const { return (3 <= x && x <= 5); }
};
void test() {
const int expected[] = {1, 2, 3, 4, 5, 6, 7, 8};
{
using M = std::flat_set<ThrowingAssignment, ThrowingComparator>;
for (int first_throw = 1; first_throw < 99; ++first_throw) {
for (int second_throw = 1; second_throw < 99; ++second_throw) {
g_counter = {0, 0, 0};
M m = M({1, 2, 3, 4, 5, 6, 7, 8});
try {
g_counter = {first_throw, second_throw, 0};
auto n = std::erase_if(m, ErasurePredicate());
assert(n == 3);
// If it didn't throw at all, we're done.
g_counter = {0, 0, 0};
assert((m == M{1, 2, 6, 7, 8}));
first_throw = 99; // "done"
break;
} catch (int ex) {
assert(ex == 42);
check_invariant(m);
LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8));
if (g_counter.throws == 1) {
// We reached the first throw but not the second throw.
break;
}
}
}
}
}
{
using M = std::flat_set<ThrowingAssignment, ThrowingComparator, std::deque<ThrowingAssignment>>;
for (int first_throw = 1; first_throw < 99; ++first_throw) {
for (int second_throw = 1; second_throw < 99; ++second_throw) {
g_counter = {0, 0, 0};
std::deque<ThrowingAssignment> container = {5, 6, 7, 8};
container.insert(container.begin(), {1, 2, 3, 4});
M m = M(std::move(container));
try {
g_counter = {first_throw, second_throw, 0};
auto n = std::erase_if(m, ErasurePredicate());
assert(n == 3);
// If it didn't throw at all, we're done.
g_counter = {0, 0, 0};
assert((m == M{1, 2, 6, 7, 8}));
first_throw = 99; // "done"
break;
} catch (int ex) {
assert(ex == 42);
check_invariant(m);
LIBCPP_ASSERT(m.empty() || std::equal(m.begin(), m.end(), expected, expected + 8));
if (g_counter.throws == 1) {
// We reached the first throw but not the second throw.
break;
}
}
}
}
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,97 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator begin() noexcept;
// const_iterator begin() const noexcept
// iterator end() noexcept;
// const_iterator end() const noexcept;
//
// const_iterator cbegin() const noexcept;
// const_iterator cend() const noexcept;
#include <cassert>
#include <cstddef>
#include <deque>
#include <flat_set>
#include <functional>
#include <string>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
M m = {1, 2, 3, 4};
const M& cm = m;
ASSERT_SAME_TYPE(decltype(m.begin()), typename M::iterator);
ASSERT_SAME_TYPE(decltype(m.cbegin()), typename M::const_iterator);
ASSERT_SAME_TYPE(decltype(cm.begin()), typename M::const_iterator);
ASSERT_SAME_TYPE(decltype(m.end()), typename M::iterator);
ASSERT_SAME_TYPE(decltype(m.cend()), typename M::const_iterator);
ASSERT_SAME_TYPE(decltype(cm.end()), typename M::const_iterator);
static_assert(noexcept(m.begin()));
static_assert(noexcept(cm.begin()));
static_assert(noexcept(m.cbegin()));
static_assert(noexcept(m.end()));
static_assert(noexcept(cm.end()));
static_assert(noexcept(m.cend()));
assert(m.size() == 4);
assert(std::distance(m.begin(), m.end()) == 4);
assert(std::distance(cm.begin(), cm.end()) == 4);
assert(std::distance(m.cbegin(), m.cend()) == 4);
typename M::iterator i; // default-construct
i = m.begin(); // move-assignment
typename M::const_iterator k = i; // converting constructor
assert(i == k); // comparison
for (int j = 1; j <= 4; ++j, ++i) { // pre-increment
assert(*i == j); // operator*
}
assert(i == m.end());
for (int j = 4; j >= 1; --j) {
--i; // pre-decrement
assert((*i) == j);
}
assert(i == m.begin());
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
{
// N3644 testing
using C = std::flat_set<int>;
C::iterator ii1{}, ii2{};
C::iterator ii4 = ii1;
C::const_iterator cii{};
assert(ii1 == ii2);
assert(ii1 == ii4);
assert(!(ii1 != ii2));
assert((ii1 == cii));
assert((cii == ii1));
assert(!(ii1 != cii));
assert(!(cii != ii1));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,158 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// flat_set iterators should be C++20 random access iterators
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using KI = typename KeyContainer::iterator;
using I = M::iterator;
using CI = M::const_iterator;
using RI = M::reverse_iterator;
using CRI = M::const_reverse_iterator;
static_assert(std::equality_comparable<I>);
static_assert(std::equality_comparable<CI>);
static_assert(std::equality_comparable<RI>);
static_assert(std::equality_comparable<CRI>);
static_assert(std::totally_ordered<I>);
static_assert(std::totally_ordered<CI>);
static_assert(std::totally_ordered<RI>);
static_assert(std::totally_ordered<CRI>);
M m = {1, 2, 3, 4};
I i1 = m.begin();
I i2 = m.begin() + 1;
assert(i1 == i1);
assert(!(i1 != i1));
assert(i1 != i2);
assert(!(i1 == i2));
assert(i1 < i2);
assert(!(i1 < i1));
assert(i1 <= i1);
assert(i1 <= i2);
assert(!(i2 <= i1));
assert(i2 > i1);
assert(!(i2 > i2));
assert(i2 >= i1);
assert(i2 >= i2);
assert(!(i1 >= i2));
CI ci1 = m.cbegin();
CI ci2 = m.cbegin() + 1;
assert(ci1 == ci1);
assert(!(ci1 != ci1));
assert(ci1 != ci2);
assert(!(ci1 == ci2));
assert(ci1 < ci2);
assert(!(ci1 < ci1));
assert(ci1 <= ci1);
assert(ci1 <= ci2);
assert(!(ci2 <= ci1));
assert(ci2 > ci1);
assert(!(ci2 > ci2));
assert(ci2 >= ci1);
assert(ci2 >= ci2);
assert(!(ci1 >= ci2));
RI ri1 = m.rbegin();
RI ri2 = m.rbegin() + 1;
assert(ri1 == ri1);
assert(!(ri1 != ri1));
assert(ri1 != ri2);
assert(!(ri1 == ri2));
assert(ri1 < ri2);
assert(!(ri1 < ri1));
assert(ri1 <= ri1);
assert(ri1 <= ri2);
assert(!(ri2 <= ri1));
assert(ri2 > ri1);
assert(!(ri2 > ri2));
assert(ri2 >= ri1);
assert(ri2 >= ri2);
assert(!(ri1 >= ri2));
CRI cri1 = m.crbegin();
CRI cri2 = m.crbegin() + 1;
assert(cri1 == cri1);
assert(!(cri1 != cri1));
assert(cri1 != cri2);
assert(!(cri1 == cri2));
assert(cri1 < cri2);
assert(!(cri1 < cri1));
assert(cri1 <= cri1);
assert(cri1 <= cri2);
assert(!(cri2 <= cri1));
assert(cri2 > cri1);
assert(!(cri2 > cri2));
assert(cri2 >= cri1);
assert(cri2 >= cri2);
assert(!(cri1 >= cri2));
if constexpr (std::three_way_comparable<KI>) {
static_assert(std::three_way_comparable<I>); // ...of course the wrapped iterators still support <=>.
static_assert(std::three_way_comparable<CI>);
static_assert(std::three_way_comparable<RI>);
static_assert(std::three_way_comparable<CRI>);
static_assert(std::same_as<decltype(I() <=> I()), std::strong_ordering>);
static_assert(std::same_as<decltype(I() <=> CI()), std::strong_ordering>);
static_assert(std::same_as<decltype(CI() <=> CI()), std::strong_ordering>);
static_assert(std::same_as<decltype(RI() <=> RI()), std::strong_ordering>);
static_assert(std::same_as<decltype(RI() <=> CRI()), std::strong_ordering>);
static_assert(std::same_as<decltype(CRI() <=> CRI()), std::strong_ordering>);
assert(i1 <=> i1 == std::strong_ordering::equivalent);
assert(i1 <=> i2 == std::strong_ordering::less);
assert(i2 <=> i1 == std::strong_ordering::greater);
assert(ci1 <=> ci1 == std::strong_ordering::equivalent);
assert(ci1 <=> ci2 == std::strong_ordering::less);
assert(ci2 <=> ci1 == std::strong_ordering::greater);
assert(ri1 <=> ri1 == std::strong_ordering::equivalent);
assert(ri1 <=> ri2 == std::strong_ordering::less);
assert(ri2 <=> ri1 == std::strong_ordering::greater);
assert(cri1 <=> cri1 == std::strong_ordering::equivalent);
assert(cri1 <=> cri2 == std::strong_ordering::less);
assert(cri2 <=> cri1 == std::strong_ordering::greater);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator, const_iterator, reverse_iterator, const_reverse_iterator
#include <flat_set>
#include <deque>
#include <functional>
#include <iterator>
#include <string>
#include <vector>
#include <type_traits>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test() {
using Key = typename KeyContainer::value_type;
using C = std::flat_set<Key, std::less<Key>, KeyContainer>;
using I = C::iterator;
using CI = C::const_iterator;
using RI = C::reverse_iterator;
using CRI = C::const_reverse_iterator;
static_assert(std::random_access_iterator<I>);
static_assert(std::random_access_iterator<CI>);
static_assert(std::random_access_iterator<RI>);
static_assert(std::random_access_iterator<CRI>);
static_assert(!std::contiguous_iterator<RI>);
static_assert(!std::contiguous_iterator<CRI>);
static_assert(!std::indirectly_writable<I, std::pair<int, char>>);
static_assert(!std::indirectly_writable<CI, std::pair<int, char>>);
static_assert(!std::indirectly_writable<RI, std::pair<int, char>>);
static_assert(!std::indirectly_writable<CRI, std::pair<int, char>>);
static_assert(std::sentinel_for<I, I>);
static_assert(std::sentinel_for<I, CI>);
static_assert(!std::sentinel_for<I, RI>);
static_assert(!std::sentinel_for<I, CRI>);
static_assert(std::sentinel_for<CI, I>);
static_assert(std::sentinel_for<CI, CI>);
static_assert(!std::sentinel_for<CI, RI>);
static_assert(!std::sentinel_for<CI, CRI>);
static_assert(!std::sentinel_for<RI, I>);
static_assert(!std::sentinel_for<RI, CI>);
static_assert(std::sentinel_for<RI, RI>);
static_assert(std::sentinel_for<RI, CRI>);
static_assert(!std::sentinel_for<CRI, I>);
static_assert(!std::sentinel_for<CRI, CI>);
static_assert(std::sentinel_for<CRI, RI>);
static_assert(std::sentinel_for<CRI, CRI>);
static_assert(std::indirectly_movable_storable<I, Key*>);
static_assert(std::indirectly_movable_storable<CI, Key*>);
static_assert(std::indirectly_movable_storable<RI, Key*>);
static_assert(std::indirectly_movable_storable<CRI, Key*>);
static_assert(std::is_same_v<typename std::iterator_traits<I>::iterator_category, std::random_access_iterator_tag>);
static_assert(std::is_same_v<typename std::iterator_traits<CI>::iterator_category, std::random_access_iterator_tag>);
static_assert(std::is_same_v<typename std::iterator_traits<RI>::iterator_category, std::random_access_iterator_tag>);
static_assert(std::is_same_v<typename std::iterator_traits<CRI>::iterator_category, std::random_access_iterator_tag>);
}
void test() {
test<std::vector<int>>();
test<std::deque<int>>();
test<MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>>();
}

View File

@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <ranges>
#include <string>
#include <vector>
#include "MinSequenceContainer.h"
#include "min_allocator.h"
template <class KeyContainer>
void test() {
{
using Key = typename KeyContainer::value_type;
using C = std::flat_set<Key, std::less<Key>, KeyContainer>;
static_assert(std::same_as<std::ranges::iterator_t<C>, typename C::iterator>);
static_assert(std::ranges::random_access_range<C>);
static_assert(std::ranges::common_range<C>);
static_assert(std::ranges::input_range<C>);
static_assert(!std::ranges::view<C>);
static_assert(std::ranges::sized_range<C>);
static_assert(!std::ranges::borrowed_range<C>);
static_assert(std::ranges::viewable_range<C>);
static_assert(std::same_as<std::ranges::iterator_t<const C>, typename C::const_iterator>);
static_assert(std::ranges::random_access_range<const C>);
static_assert(std::ranges::common_range<const C>);
static_assert(std::ranges::input_range<const C>);
static_assert(!std::ranges::view<const C>);
static_assert(std::ranges::sized_range<const C>);
static_assert(!std::ranges::borrowed_range<const C>);
static_assert(!std::ranges::viewable_range<const C>);
}
}
void test() {
test<std::vector<int>>();
test<std::deque<int>>();
test<MinSequenceContainer<int>>();
test<std::vector<int, min_allocator<int>>>();
}

View File

@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// reverse_iterator rbegin() noexcept;
// const_reverse_iterator rbegin() const noexcept;
// reverse_iterator rend() noexcept;
// const_reverse_iterator rend() const noexcept;
//
// const_reverse_iterator crbegin() const noexcept;
// const_reverse_iterator crend() const noexcept;
#include <cassert>
#include <cstddef>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include <iterator>
#include "test_macros.h"
#include <iostream>
void test() {
{
using M = std::flat_set<int, std::less<int>, std::deque<int>>;
M m = {1, 2, 3, 4};
const M& cm = m;
ASSERT_SAME_TYPE(decltype(m.rbegin()), M::reverse_iterator);
ASSERT_SAME_TYPE(decltype(m.crbegin()), M::const_reverse_iterator);
ASSERT_SAME_TYPE(decltype(cm.rbegin()), M::const_reverse_iterator);
ASSERT_SAME_TYPE(decltype(m.rend()), M::reverse_iterator);
ASSERT_SAME_TYPE(decltype(m.crend()), M::const_reverse_iterator);
ASSERT_SAME_TYPE(decltype(cm.rend()), M::const_reverse_iterator);
static_assert(noexcept(m.rbegin()));
static_assert(noexcept(cm.rbegin()));
static_assert(noexcept(m.crbegin()));
static_assert(noexcept(m.rend()));
static_assert(noexcept(cm.rend()));
static_assert(noexcept(m.crend()));
assert(m.size() == 4);
assert(std::distance(m.rbegin(), m.rend()) == 4);
assert(std::distance(cm.rbegin(), cm.rend()) == 4);
assert(std::distance(m.crbegin(), m.crend()) == 4);
assert(std::distance(cm.crbegin(), cm.crend()) == 4);
M::reverse_iterator i; // default-construct
ASSERT_SAME_TYPE(decltype(*i), const int&);
i = m.rbegin(); // move-assignment
M::const_reverse_iterator k = i; // converting constructor
assert(i == k); // comparison
for (int j = 4; j >= 1; --j, ++i) { // pre-increment
assert(*i == j);
}
assert(i == m.rend());
for (int j = 1; j <= 4; ++j) {
--i; // pre-decrement
assert(*i == j);
}
assert(i == m.rbegin());
}
{
// N3644 testing
using C = std::flat_set<int>;
C::reverse_iterator ii1{}, ii2{};
C::reverse_iterator ii4 = ii1;
C::const_reverse_iterator cii{};
assert(ii1 == ii2);
assert(ii1 == ii4);
assert(!(ii1 != ii2));
assert((ii1 == cii));
assert((cii == ii1));
assert(!(ii1 != cii));
assert(!(cii != ii1));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// class flat_set
// void clear() noexcept;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// test noexcept
template <class T>
concept NoExceptClear = requires(T t) {
{ t.clear() } noexcept;
};
static_assert(NoExceptClear<std::flat_set<int>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(NoExceptClear<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
{
M m = {1, 2, 3, 4, 5};
assert(m.size() == 5);
ASSERT_NOEXCEPT(m.clear());
ASSERT_SAME_TYPE(decltype(m.clear()), void);
m.clear();
assert(m.size() == 0);
}
{
// was empty
M m;
assert(m.size() == 0);
m.clear();
assert(m.size() == 0);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,146 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class... Args>
// pair<iterator, bool> emplace(Args&&... args);
#include <flat_set>
#include <cassert>
#include <deque>
#include <tuple>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "../../../Emplaceable.h"
#include "DefaultOnly.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using R = std::pair<typename M::iterator, bool>;
{
// was empty
M m;
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 1);
assert(*r.first == 2);
}
{
// key does not exist and inserted at the begin
M m = {3, 5, 6, 7};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 5);
assert(*r.first == 2);
}
{
// key does not exist and inserted in the middle
M m = {0, 1, 3, 4};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(r.second);
assert(r.first == m.begin() + 2);
assert(m.size() == 5);
assert(*r.first == 2);
}
{
// key does not exist and inserted at the end
M m = {0, 1};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(r.second);
assert(r.first == m.begin() + 2);
assert(m.size() == 3);
assert(*r.first == 2);
}
{
// key already exists and original at the begin
M m = {2, 3, 5, 6};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(!r.second);
assert(r.first == m.begin());
assert(m.size() == 4);
assert(*r.first == 2);
}
{
// key already exists and original in the middle
M m = {0, 2, 3, 4};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(!r.second);
assert(r.first == m.begin() + 1);
assert(m.size() == 4);
assert(*r.first == 2);
}
{
// key already exists and original at the end
M m = {0, 1, 2};
std::same_as<R> decltype(auto) r = m.emplace(typename M::value_type(2));
assert(!r.second);
assert(r.first == m.begin() + 2);
assert(m.size() == 3);
assert(*r.first == 2);
}
}
template <class KeyContainer>
void test_emplaceable() {
using M = std::flat_set<Emplaceable, std::less<Emplaceable>, KeyContainer>;
using R = std::pair<typename M::iterator, bool>;
M m;
ASSERT_SAME_TYPE(decltype(m.emplace()), R);
R r = m.emplace(2, 0.0);
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 1);
assert(*m.begin() == Emplaceable(2, 0.0));
r = m.emplace(1, 3.5);
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 2);
assert(*m.begin() == Emplaceable(1, 3.5));
r = m.emplace(1, 3.5);
assert(!r.second);
assert(r.first == m.begin());
assert(m.size() == 2);
assert(*m.begin() == Emplaceable(1, 3.5));
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
test_emplaceable<std::vector<Emplaceable>>();
test_emplaceable<std::deque<Emplaceable>>();
test_emplaceable<MinSequenceContainer<Emplaceable>>();
test_emplaceable<std::vector<Emplaceable, min_allocator<Emplaceable>>>();
}
void test_exception() {
auto emplace_func = [](auto& m, auto key_arg) { m.emplace(key_arg); };
test_emplace_exception_guarantee(emplace_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,159 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class... Args>
// iterator emplace_hint(const_iterator position, Args&&... args);
#include <flat_set>
#include <cassert>
#include <deque>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "../../../Emplaceable.h"
#include "DefaultOnly.h"
#include "min_allocator.h"
#include "../helpers.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using R = M::iterator;
{
// was empty
M m;
std::same_as<R> decltype(auto) r = m.emplace_hint(m.end(), typename M::value_type(2));
assert(r == m.begin());
assert(m.size() == 1);
assert(*r == 2);
}
{
// hints correct at the begin
M m = {3, 4};
auto hint = m.begin();
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin());
assert(m.size() == 3);
assert(*r == 2);
}
{
// hints correct in the middle
M m = {0, 1, 3, 4};
auto hint = m.begin() + 2;
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 2);
assert(m.size() == 5);
assert(*r == 2);
}
{
// hints correct at the end
M m = {0, 1};
auto hint = m.end();
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 2);
assert(m.size() == 3);
assert(*r == 2);
}
{
// hints correct but key already exists
M m = {0, 1, 2, 3, 4};
auto hint = m.begin() + 2;
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 2);
assert(m.size() == 5);
assert(*r == 2);
}
{
// hints incorrectly at the begin
M m = {1, 4};
auto hint = m.begin();
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 1);
assert(m.size() == 3);
assert(*r == 2);
}
{
// hints incorrectly in the middle
M m = {0, 1, 3, 4};
auto hint = m.begin() + 1;
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 2);
assert(m.size() == 5);
assert(*r == 2);
}
{
// hints incorrectly at the end
M m = {0, 3};
auto hint = m.end();
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 1);
assert(m.size() == 3);
assert(*r == 2);
}
{
// hints incorrect and key already exists
M m = {0, 1, 2, 3, 4};
auto hint = m.begin();
std::same_as<R> decltype(auto) r = m.emplace_hint(hint, typename M::value_type(2));
assert(r == m.begin() + 2);
assert(m.size() == 5);
assert(*r == 2);
}
}
template <class KeyContainer>
void test_emplaceable() {
using M = std::flat_set<Emplaceable, std::less<Emplaceable>, KeyContainer>;
using R = M::iterator;
M m;
ASSERT_SAME_TYPE(decltype(m.emplace_hint(m.cbegin())), R);
R r = m.emplace_hint(m.end(), 2, 0.0);
assert(r == m.begin());
assert(m.size() == 1);
assert(*m.begin() == Emplaceable(2, 0.0));
r = m.emplace_hint(m.end(), 1, 3.5);
assert(r == m.begin());
assert(m.size() == 2);
assert(*m.begin() == Emplaceable(1, 3.5));
r = m.emplace_hint(m.end(), 1, 3.5);
assert(r == m.begin());
assert(m.size() == 2);
assert(*m.begin() == Emplaceable(1, 3.5));
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
test_emplaceable<std::vector<Emplaceable>>();
test_emplaceable<std::vector<Emplaceable>>();
test_emplaceable<MinSequenceContainer<Emplaceable>>();
test_emplaceable<std::vector<Emplaceable, min_allocator<Emplaceable>>>();
}
void test_exception() {
auto emplace_func = [](auto& m, auto key_arg) { m.emplace_hint(m.begin(), key_arg); };
test_emplace_exception_guarantee(emplace_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -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
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator erase(iterator position);
// iterator erase(const_iterator position);
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using I = M::iterator;
int ar[] = {
1,
2,
3,
4,
5,
6,
7,
8,
};
M m(ar, ar + sizeof(ar) / sizeof(ar[0]));
auto make = [](std::initializer_list<int> il) {
M m2;
for (int i : il) {
m2.emplace(i);
}
return m2;
};
assert(m.size() == 8);
assert(m == make({1, 2, 3, 4, 5, 6, 7, 8}));
std::same_as<I> decltype(auto) i1 = m.erase(std::next(m.cbegin(), 3));
assert(m.size() == 7);
assert(i1 == std::next(m.begin(), 3));
assert(m == make({1, 2, 3, 5, 6, 7, 8}));
std::same_as<I> decltype(auto) i2 = m.erase(std::next(m.begin(), 0));
assert(m.size() == 6);
assert(i2 == m.begin());
assert(m == make({2, 3, 5, 6, 7, 8}));
std::same_as<I> decltype(auto) i3 = m.erase(std::next(m.cbegin(), 5));
assert(m.size() == 5);
assert(i3 == m.end());
assert(m == make({2, 3, 5, 6, 7}));
std::same_as<I> decltype(auto) i4 = m.erase(std::next(m.begin(), 1));
assert(m.size() == 4);
assert(i4 == std::next(m.begin()));
assert(m == make({2, 5, 6, 7}));
std::same_as<I> decltype(auto) i5 = m.erase(std::next(m.cbegin(), 2));
assert(m.size() == 3);
assert(i5 == std::next(m.begin(), 2));
assert(m == make({2, 5, 7}));
std::same_as<I> decltype(auto) i6 = m.erase(std::next(m.begin(), 2));
assert(m.size() == 2);
assert(i6 == std::next(m.begin(), 2));
assert(m == make({2, 5}));
std::same_as<I> decltype(auto) i7 = m.erase(std::next(m.cbegin(), 0));
assert(m.size() == 1);
assert(i7 == std::next(m.begin(), 0));
assert(m == make({5}));
std::same_as<I> decltype(auto) i8 = m.erase(m.begin());
assert(m.size() == 0);
assert(i8 == m.begin());
assert(i8 == m.end());
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto erase_function = [](auto& m, auto) { m.erase(m.begin() + 2); };
test_erase_exception_guarantee(erase_function);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator erase(const_iterator first, const_iterator last);
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using I = M::iterator;
auto make = [](std::initializer_list<int> il) {
M m;
for (int i : il) {
m.emplace(i);
}
return m;
};
int ar[] = {
1,
2,
3,
4,
5,
6,
7,
8,
};
M m(ar, ar + sizeof(ar) / sizeof(ar[0]));
assert(m.size() == 8);
std::same_as<I> decltype(auto) i1 = m.erase(m.cbegin(), m.cbegin());
assert(m.size() == 8);
assert(i1 == m.begin());
assert(m == make({1, 2, 3, 4, 5, 6, 7, 8}));
std::same_as<I> decltype(auto) i2 = m.erase(m.cbegin(), std::next(m.cbegin(), 2));
assert(m.size() == 6);
assert(i2 == m.begin());
assert(m == make({3, 4, 5, 6, 7, 8}));
std::same_as<I> decltype(auto) i3 = m.erase(std::next(m.cbegin(), 2), std::next(m.cbegin(), 6));
assert(m.size() == 2);
assert(i3 == std::next(m.begin(), 2));
assert(m == make({3, 4}));
std::same_as<I> decltype(auto) i4 = m.erase(m.cbegin(), m.cend());
assert(m.size() == 0);
assert(i4 == m.begin());
assert(i4 == m.end());
// was empty
std::same_as<I> decltype(auto) i5 = m.erase(m.cbegin(), m.cend());
assert(m.size() == 0);
assert(i5 == m.begin());
assert(i5 == m.end());
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto erase_function = [](auto& m, auto) { m.erase(m.begin(), m.begin() + 2); };
test_erase_exception_guarantee(erase_function);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// size_type erase(const key_type& k);
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer, class Compare = std::less<>>
void test_one() {
using M = std::flat_set<int, Compare, KeyContainer>;
auto make = [](std::initializer_list<int> il) {
M m;
for (int i : il) {
m.emplace(i);
}
return m;
};
M m = make({1, 2, 3, 4, 5, 6, 7, 8});
ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type);
auto n = m.erase(9);
assert(n == 0);
assert(m == make({1, 2, 3, 4, 5, 6, 7, 8}));
n = m.erase(4);
assert(n == 1);
assert(m == make({1, 2, 3, 5, 6, 7, 8}));
n = m.erase(1);
assert(n == 1);
assert(m == make({2, 3, 5, 6, 7, 8}));
n = m.erase(8);
assert(n == 1);
assert(m == make({2, 3, 5, 6, 7}));
n = m.erase(3);
assert(n == 1);
assert(m == make({2, 5, 6, 7}));
n = m.erase(4);
assert(n == 0);
assert(m == make({2, 5, 6, 7}));
n = m.erase(6);
assert(n == 1);
assert(m == make({2, 5, 7}));
n = m.erase(7);
assert(n == 1);
assert(m == make({2, 5}));
n = m.erase(2);
assert(n == 1);
assert(m == make({5}));
n = m.erase(5);
assert(n == 1);
assert(m.empty());
// was empty
n = m.erase(5);
assert(n == 0);
assert(m.empty());
}
void test() {
test_one<std::vector<int>>();
test_one<std::vector<int>, std::greater<>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto erase_function = [](auto& m, auto key_arg) {
using Map = std::decay_t<decltype(m)>;
using Key = typename Map::key_type;
const Key key{key_arg};
m.erase(key);
};
test_erase_exception_guarantee(erase_function);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,157 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// size_type erase(K&& k);
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanErase = requires(M m, Transparent<int> k) { m.erase(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanErase<TransparentSet>);
static_assert(!CanErase<const TransparentSet>);
static_assert(!CanErase<NonTransparentSet>);
static_assert(!CanErase<const NonTransparentSet>);
template <class Key, class It>
struct HeterogeneousKey {
explicit HeterogeneousKey(Key key, It it) : key_(key), it_(it) {}
operator It() && { return it_; }
auto operator<=>(Key key) const { return key_ <=> key; }
friend bool operator<(const HeterogeneousKey&, const HeterogeneousKey&) {
assert(false);
return false;
}
Key key_;
It it_;
};
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
M m = {1, 2, 3, 4};
ASSERT_SAME_TYPE(decltype(m.erase(9)), typename M::size_type);
auto n = m.erase(3); // erase(K&&) [with K=int]
assert(n == 1);
assert((m == M{1, 2, 4}));
typename M::key_type lvalue = 2;
n = m.erase(lvalue); // erase(K&&) [with K=int&]
assert(n == 1);
assert((m == M{1, 4}));
const typename M::key_type const_lvalue = 1;
n = m.erase(const_lvalue); // erase(const key_type&)
assert(n == 1);
assert((m == M{4}));
}
template <class KeyContainer>
void test_transparent_comparator() {
using M = std::flat_set<std::string, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
ASSERT_SAME_TYPE(decltype(m.erase(Transparent<std::string>{"abc"})), typename M::size_type);
auto n = m.erase(Transparent<std::string>{"epsilon"});
assert(n == 1);
M expected = {"alpha", "beta", "eta", "gamma"};
assert(m == expected);
auto n2 = m.erase(Transparent<std::string>{"aaa"});
assert(n2 == 0);
assert(m == expected);
}
{
// was empty
M m;
auto n = m.erase(Transparent<std::string>{"epsilon"});
assert(n == 0);
assert(m.empty());
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
test_transparent_comparator<std::vector<std::string>>();
test_transparent_comparator<std::deque<std::string>>();
test_transparent_comparator<MinSequenceContainer<std::string>>();
test_transparent_comparator<std::vector<std::string, min_allocator<std::string>>>();
{
// P2077's HeterogeneousKey example
using M = std::flat_set<int, std::less<>>;
M m = {1, 2, 3, 4, 5, 6, 7, 8};
auto h1 = HeterogeneousKey<int, M::iterator>(8, m.begin());
std::same_as<M::size_type> auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match
assert(n == 1);
assert((m == M{1, 2, 3, 4, 5, 6, 7}));
std::same_as<M::iterator> auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out
assert(it == m.begin());
assert((m == M{2, 3, 4, 5, 6, 7}));
}
{
using M = std::flat_set<int, std::less<>>;
M m = {1, 2, 3, 4, 5, 6, 7, 8};
auto h1 = HeterogeneousKey<int, M::const_iterator>(8, m.begin());
std::same_as<M::size_type> auto n = m.erase(h1); // lvalue is not convertible to It; erase(K&&) is the best match
assert(n == 1);
assert((m == M{1, 2, 3, 4, 5, 6, 7}));
std::same_as<M::iterator> auto it = m.erase(std::move(h1)); // rvalue is convertible to It; erase(K&&) drops out
assert(it == m.begin());
assert((m == M{2, 3, 4, 5, 6, 7}));
}
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto n = m.erase(Transparent<int>{3});
assert(n == 1);
assert(transparent_used);
}
}
void test_exception() {
auto erase_transparent = [](auto& m, auto key_arg) {
using Set = std::decay_t<decltype(m)>;
using Key = typename Set::key_type;
m.erase(Transparent<Key>{key_arg});
};
test_erase_exception_guarantee(erase_transparent);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,102 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// containers extract() &&;
#include <algorithm>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class T>
concept CanExtract = requires(T&& t) { std::forward<T>(t).extract(); };
static_assert(CanExtract<std::flat_set<int>&&>);
static_assert(!CanExtract<std::flat_set<int>&>);
static_assert(!CanExtract<std::flat_set<int> const&>);
static_assert(!CanExtract<std::flat_set<int> const&&>);
template <class KeyContainer>
void test_one() {
using M = std::flat_set<int, std::less<int>, KeyContainer>;
{
M m = M({1, 2, 3});
std::same_as<KeyContainer> auto keys = std::move(m).extract();
auto expected_keys = {1, 2, 3};
assert(std::ranges::equal(keys, expected_keys));
check_invariant(m);
LIBCPP_ASSERT(m.empty());
}
{
// was empty
M m;
assert(m.empty());
auto keys = std::move(m).extract();
assert(keys.empty());
LIBCPP_ASSERT(m.empty());
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
{
// extracted object maintains invariant if the underlying container does not clear after move
using M = std::flat_set<int, std::less<>, CopyOnlyVector<int>>;
M m = M({1, 2, 3});
std::same_as<M::container_type> auto keys = std::move(m).extract();
assert(keys.size() == 3);
check_invariant(m);
LIBCPP_ASSERT(m.empty());
}
}
void test_exception() {
{
#ifndef TEST_HAS_NO_EXCEPTIONS
using KeyContainer = ThrowOnMoveContainer<int>;
using M = std::flat_set<int, std::ranges::less, KeyContainer>;
M m;
m.emplace(1);
m.emplace(2);
try {
auto c = std::move(m).extract();
assert(false);
} catch (int) {
check_invariant(m);
// In libc++, we try to erase the key after value emplacement failure.
// and after erasure failure, we clear the flat_set
LIBCPP_ASSERT(m.size() == 0);
}
#endif
}
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// pair<iterator, bool> insert(const value_type& v);
#include <flat_set>
#include <deque>
#include <cassert>
#include <functional>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "../helpers.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using R = std::pair<typename M::iterator, bool>;
using VT = typename M::value_type;
M m;
const VT v1(2);
std::same_as<R> decltype(auto) r = m.insert(v1);
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 1);
assert(*r.first == 2);
const VT v2(1);
r = m.insert(v2);
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 2);
assert(*r.first == 1);
const VT v3(3);
r = m.insert(v3);
assert(r.second);
assert(r.first == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r.first == 3);
const VT v4(3);
r = m.insert(v4);
assert(!r.second);
assert(r.first == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r.first == 3);
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, auto key_arg) {
using value_type = typename std::decay_t<decltype(m)>::value_type;
const value_type p(key_arg);
m.insert(p);
};
test_emplace_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,92 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// void insert(initializer_list<value_type> il);
#include <flat_set>
#include <cassert>
#include <functional>
#include <deque>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using V = typename M::value_type;
{
M m = {1, 1, 1, 3, 3, 3};
m.insert({
4,
4,
4,
1,
1,
1,
2,
2,
2,
});
assert(m.size() == 4);
assert(std::distance(m.begin(), m.end()) == 4);
assert(*m.begin() == V(1));
assert(*std::next(m.begin()) == V(2));
assert(*std::next(m.begin(), 2) == V(3));
assert(*std::next(m.begin(), 3) == V(4));
}
{
// was empty
M m;
m.insert({
4,
4,
4,
1,
1,
1,
2,
2,
2,
});
M expected = {1, 2, 4};
assert(m == expected);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, const auto& newValues) {
using FlatSet = std::decay_t<decltype(m)>;
using value_type = typename FlatSet::value_type;
std::initializer_list<value_type> il = {newValues[0]};
m.insert(il);
};
test_insert_range_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator insert(const_iterator position, const value_type& v);
#include <flat_set>
#include <cassert>
#include <functional>
#include <deque>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "../helpers.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using R = typename M::iterator;
using VT = typename M::value_type;
M m;
const VT v1(2);
std::same_as<R> decltype(auto) r = m.insert(m.end(), v1);
assert(r == m.begin());
assert(m.size() == 1);
assert(*r == 2);
const VT v2(1);
r = m.insert(m.end(), v2);
assert(r == m.begin());
assert(m.size() == 2);
assert(*r == 1);
const VT v3(3);
r = m.insert(m.end(), v3);
assert(r == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r == 3);
const VT v4(3);
r = m.insert(m.end(), v4);
assert(r == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r == 3);
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, auto key_arg) {
using FlatSet = std::decay_t<decltype(m)>;
using value_type = typename FlatSet::value_type;
const value_type p(key_arg);
m.insert(m.begin(), p);
};
test_emplace_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,94 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class InputIterator>
// void insert(InputIterator first, InputIterator last);
#include <flat_set>
#include <cassert>
#include <functional>
#include <deque>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
// test constraint InputIterator
template <class M, class... Args>
concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward<Args>(args)...); };
using Set = std::flat_set<int>;
static_assert(CanInsert<Set, int*, int*>);
static_assert(CanInsert<Set, cpp17_input_iterator<int*>, cpp17_input_iterator<int*>>);
static_assert(!CanInsert<Set, int, int>);
static_assert(!CanInsert<Set, cpp20_input_iterator<int*>, cpp20_input_iterator<int*>>);
template <class KeyContainer>
void test_one() {
using M = std::flat_set<int, std::less<int>, KeyContainer>;
int ar1[] = {
2,
2,
2,
1,
1,
1,
3,
3,
3,
};
int ar2[] = {
4,
4,
4,
1,
1,
1,
0,
0,
0,
};
M m;
m.insert(cpp17_input_iterator<int*>(ar1), cpp17_input_iterator<int*>(ar1 + sizeof(ar1) / sizeof(ar1[0])));
assert(m.size() == 3);
M expected{1, 2, 3};
assert(m == expected);
m.insert(cpp17_input_iterator<int*>(ar2), cpp17_input_iterator<int*>(ar2 + sizeof(ar2) / sizeof(ar2[0])));
assert(m.size() == 5);
M expected2{0, 1, 2, 3, 4};
assert(m == expected2);
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, const auto& newValues) { m.insert(newValues.begin(), newValues.end()); };
test_insert_range_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator insert(const_iterator position, value_type&&);
#include <flat_set>
#include <cassert>
#include <deque>
#include "MinSequenceContainer.h"
#include "MoveOnly.h"
#include "min_allocator.h"
#include "../helpers.h"
#include "test_macros.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using V = Key;
using R = typename M::iterator;
M m;
std::same_as<R> decltype(auto) r = m.insert(m.end(), V(2));
assert(r == m.begin());
assert(m.size() == 1);
assert(*r == V(2));
r = m.insert(m.end(), V(1));
assert(r == m.begin());
assert(m.size() == 2);
assert(*r == V(1));
r = m.insert(m.end(), V(3));
assert(r == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r == V(3));
r = m.insert(m.end(), V(3));
assert(r == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r == V(3));
}
void test() {
test_one<std::vector<int>>();
test_one<std::vector<MoveOnly>>();
test_one<std::deque<int>>();
test_one<std::deque<MoveOnly>>();
test_one<MinSequenceContainer<int>>();
test_one<MinSequenceContainer<MoveOnly>>();
test_one<std::vector<int, min_allocator<int>>>();
test_one<std::vector<MoveOnly, min_allocator<MoveOnly>>>();
}
void test_exception() {
auto insert_func = [](auto& m, auto key_arg) {
using FlatSet = std::decay_t<decltype(m)>;
using value_type = typename FlatSet::value_type;
value_type p(key_arg);
m.insert(m.begin(), std::move(p));
};
test_emplace_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,111 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<container-compatible-range<value_type> R>
// void insert_range(R&& rg);
#include <algorithm>
#include <deque>
#include <flat_set>
#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 CanInsertRange = requires(M m, R&& r) { m.insert_range(std::forward<R>(r)); };
using Set = std::flat_set<int, double>;
static_assert(CanInsertRange<Set, std::ranges::subrange<int*>>);
static_assert(CanInsertRange<Set, std::ranges::subrange<short*>>);
static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<int, int>*>>);
static_assert(!CanInsertRange<Set, std::ranges::subrange<std::pair<short, short>*>>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using It = forward_iterator<const int*>;
M m = {10, 8, 5, 2, 1};
int ar[] = {3, 1, 4, 1, 5, 9};
std::ranges::subrange r = {It(ar), It(ar + 6)};
static_assert(std::ranges::common_range<decltype(r)>);
m.insert_range(r);
assert((m == M{1, 2, 3, 4, 5, 8, 9, 10}));
}
{
using M = std::flat_set<Key, std::greater<>, KeyContainer>;
using It = cpp20_input_iterator<const int*>;
M m = {8, 5, 3, 2};
int ar[] = {3, 1, 4, 1, 5, 9};
std::ranges::subrange r = {It(ar), sentinel_wrapper<It>(It(ar + 6))};
static_assert(!std::ranges::common_range<decltype(r)>);
m.insert_range(r);
assert((m == M{1, 2, 3, 4, 5, 8, 9}));
}
{
// The "uniquing" part uses the comparator, not operator==.
struct ModTen {
bool operator()(int a, int b) const { return (a % 10) < (b % 10); }
};
using M = std::flat_set<Key, ModTen, KeyContainer>;
M m = {21, 43, 15, 37};
int ar[] = {33, 18, 55, 18, 42};
m.insert_range(ar);
assert((m == M{21, 42, 43, 15, 37, 18}));
}
{
// was empty
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
M m;
int ar[] = {3, 1, 4, 1, 5, 9};
m.insert_range(ar);
assert((m == M{1, 3, 4, 5, 9}));
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
{
// Items are forwarded correctly from the input range.
MoveOnly a[] = {3, 1, 4, 1, 5};
std::flat_set<MoveOnly> m;
m.insert_range(a | std::views::as_rvalue);
MoveOnly expected[] = {1, 3, 4, 5};
assert(std::ranges::equal(m, expected));
}
}
void test_exception() {
auto insert_func = [](auto& m, const auto& newValues) { m.insert_range(newValues); };
test_insert_range_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// class flat_set
// pair<iterator, bool> insert(value_type&& v);
#include <flat_set>
#include <cassert>
#include <deque>
#include "MinSequenceContainer.h"
#include "MoveOnly.h"
#include "min_allocator.h"
#include "test_macros.h"
#include "../helpers.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
using R = std::pair<typename M::iterator, bool>;
using V = typename M::value_type;
M m;
std::same_as<R> decltype(auto) r = m.insert(V(2));
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 1);
assert(*r.first == V(2));
r = m.insert(V(1));
assert(r.second);
assert(r.first == m.begin());
assert(m.size() == 2);
assert(*r.first == V(1));
r = m.insert(V(3));
assert(r.second);
assert(r.first == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r.first == V(3));
r = m.insert(V(3));
assert(!r.second);
assert(r.first == std::ranges::prev(m.end()));
assert(m.size() == 3);
assert(*r.first == V(3));
}
void test() {
test_one<std::vector<int>>();
test_one<std::vector<MoveOnly>>();
test_one<std::deque<int>>();
test_one<std::deque<MoveOnly>>();
test_one<MinSequenceContainer<int>>();
test_one<MinSequenceContainer<MoveOnly>>();
test_one<std::vector<int, min_allocator<int>>>();
test_one<std::vector<MoveOnly, min_allocator<MoveOnly>>>();
}
void test_exception() {
auto insert_func = [](auto& m, auto key_arg) {
using FlatSet = std::decay_t<decltype(m)>;
using value_type = typename FlatSet::value_type;
value_type p(key_arg);
m.insert(std::move(p));
};
test_emplace_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,72 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// void insert(sorted_unique_t, initializer_list<value_type> il);
#include <flat_set>
#include <cassert>
#include <functional>
#include <deque>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
using V = Key;
{
M m = {1, 1, 1, 3, 3, 3};
m.insert(std::sorted_unique, {0, 1, 2, 4});
assert(m.size() == 5);
assert(std::distance(m.begin(), m.end()) == 5);
assert(*m.begin() == V(0));
assert(*std::next(m.begin()) == V(1));
assert(*std::next(m.begin(), 2) == V(2));
assert(*std::next(m.begin(), 3) == V(3));
assert(*std::next(m.begin(), 4) == V(4));
}
{
// empty
M m;
m.insert(std::sorted_unique, {0, 1, 2, 4});
M expected = {0, 1, 2, 4};
assert(m == expected);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, const auto& newValues) {
using FlatSet = std::decay_t<decltype(m)>;
using value_type = typename FlatSet::value_type;
std::initializer_list<value_type> il = {newValues[0]};
m.insert(std::sorted_unique, il);
};
test_insert_range_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template <class InputIterator>
// void insert(sorted_unique_t, InputIterator first, InputIterator last);
#include <flat_set>
#include <cassert>
#include <functional>
#include <deque>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
// test constraint InputIterator
template <class M, class... Args>
concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward<Args>(args)...); };
using Set = std::flat_set<int>;
static_assert(CanInsert<Set, std::sorted_unique_t, int*, int*>);
static_assert(CanInsert<Set, std::sorted_unique_t, cpp17_input_iterator<int*>, cpp17_input_iterator<int*>>);
static_assert(!CanInsert<Set, std::sorted_unique_t, int, int>);
static_assert(!CanInsert<Set, std::sorted_unique_t, cpp20_input_iterator<int*>, cpp20_input_iterator<int*>>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
int ar1[] = {1, 2, 3};
int ar2[] = {0, 2, 4};
M m;
m.insert(std::sorted_unique,
cpp17_input_iterator<int*>(ar1),
cpp17_input_iterator<int*>(ar1 + sizeof(ar1) / sizeof(ar1[0])));
assert(m.size() == 3);
M expected{1, 2, 3};
assert(m == expected);
m.insert(std::sorted_unique,
cpp17_input_iterator<int*>(ar2),
cpp17_input_iterator<int*>(ar2 + sizeof(ar2) / sizeof(ar2[0])));
assert(m.size() == 5);
M expected2{0, 1, 2, 3, 4};
assert(m == expected2);
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
auto insert_func = [](auto& m, const auto& newValues) {
m.insert(std::sorted_unique, newValues.begin(), newValues.end());
};
test_insert_range_exception_guarantee(insert_func);
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,186 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> pair<iterator, bool> insert(P&& x);
// template<class K> iterator insert(const_iterator hint, P&& x);
#include <algorithm>
#include <compare>
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <tuple>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "test_iterators.h"
#include "min_allocator.h"
// Constraints: is_constructible_v<value_type, K> is true.
template <class M, class... Args>
concept CanInsert = requires(M m, Args&&... args) { m.insert(std::forward<Args>(args)...); };
using Set = std::flat_set<int>;
using Iter = Set::const_iterator;
static_assert(CanInsert<Set, short&&>);
static_assert(CanInsert<Set, Iter, short&&>);
static_assert(!CanInsert<Set, std::string>);
static_assert(!CanInsert<Set, Iter, std::string>);
static int expensive_comparisons = 0;
static int cheap_comparisons = 0;
struct CompareCounter {
int i_ = 0;
CompareCounter(int i) : i_(i) {}
friend auto operator<=>(const CompareCounter& x, const CompareCounter& y) {
expensive_comparisons += 1;
return x.i_ <=> y.i_;
}
bool operator==(const CompareCounter&) const = default;
friend auto operator<=>(const CompareCounter& x, int y) {
cheap_comparisons += 1;
return x.i_ <=> y;
}
};
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
const int expected[] = {1, 2, 3, 4, 5};
{
// insert(P&&)
// Unlike flat_set, here we can't use key_compare to compare value_type versus P,
// so we must eagerly convert to value_type.
M m = {1, 2, 4, 5};
expensive_comparisons = 0;
cheap_comparisons = 0;
std::same_as<std::pair<typename M::iterator, bool>> auto p = m.insert(3); // conversion happens first
assert(expensive_comparisons >= 2);
assert(cheap_comparisons == 0);
assert(p == std::make_pair(m.begin() + 2, true));
assert(std::ranges::equal(m, expected));
}
{
// insert(const_iterator, P&&)
M m = {1, 2, 4, 5};
expensive_comparisons = 0;
cheap_comparisons = 0;
std::same_as<typename M::iterator> auto it = m.insert(m.begin(), 3);
assert(expensive_comparisons >= 2);
assert(cheap_comparisons == 0);
assert(it == m.begin() + 2);
assert(std::ranges::equal(m, expected));
}
{
// insert(value_type&&)
M m = {1, 2, 4, 5};
expensive_comparisons = 0;
cheap_comparisons = 0;
std::same_as<std::pair<typename M::iterator, bool>> auto p = m.insert(3); // conversion happens last
assert(expensive_comparisons >= 2);
assert(cheap_comparisons == 0);
assert(p == std::make_pair(m.begin() + 2, true));
assert(std::ranges::equal(m, expected));
}
{
// insert(const_iterator, value_type&&)
M m = {1, 2, 4, 5};
expensive_comparisons = 0;
cheap_comparisons = 0;
std::same_as<typename M::iterator> auto it = m.insert(m.begin(), 3);
assert(expensive_comparisons >= 2);
assert(cheap_comparisons == 0);
assert(it == m.begin() + 2);
assert(std::ranges::equal(m, expected));
}
{
// emplace(Args&&...)
M m = {1, 2, 4, 5};
expensive_comparisons = 0;
cheap_comparisons = 0;
std::same_as<std::pair<typename M::iterator, bool>> auto p = m.emplace(3); // conversion happens first
assert(expensive_comparisons >= 2);
assert(cheap_comparisons == 0);
assert(p == std::make_pair(m.begin() + 2, true));
assert(std::ranges::equal(m, expected));
}
{
// was empty
M m;
std::same_as<std::pair<typename M::iterator, bool>> auto p = m.insert(3);
assert(p == std::make_pair(m.begin(), true));
M expected2 = {3};
assert(std::ranges::equal(m, expected2));
}
}
void test() {
test_one<std::vector<CompareCounter>>();
test_one<std::deque<CompareCounter>>();
test_one<MinSequenceContainer<CompareCounter>>();
test_one<std::vector<CompareCounter, min_allocator<CompareCounter>>>();
{
// no ambiguity between insert(pos, P&&) and insert(first, last)
using M = std::flat_set<int>;
struct Evil {
operator M::value_type() const;
operator M::const_iterator() const;
};
std::flat_set<int> m;
ASSERT_SAME_TYPE(decltype(m.insert(Evil())), std::pair<M::iterator, bool>);
ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), Evil())), M::iterator);
ASSERT_SAME_TYPE(decltype(m.insert(m.begin(), m.end())), void);
}
}
void test_exception() {
{
auto insert_func = [](auto& m, auto key_arg) {
using FlatSet = std::decay_t<decltype(m)>;
struct T {
typename FlatSet::key_type key_;
T(typename FlatSet::key_type key) : key_(key) {}
operator typename FlatSet::value_type() const { return key_; }
};
T t(key_arg);
m.insert(t);
};
test_emplace_exception_guarantee(insert_func);
}
{
auto insert_func_iter = [](auto& m, auto key_arg) {
using FlatSet = std::decay_t<decltype(m)>;
struct T {
typename FlatSet::key_type key_;
T(typename FlatSet::key_type key) : key_(key) {}
operator typename FlatSet::value_type() const { return key_; }
};
T t(key_arg);
m.insert(m.begin(), t);
};
test_emplace_exception_guarantee(insert_func_iter);
}
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// void replace(container_type&& key_cont);
#include <algorithm>
#include <deque>
#include <concepts>
#include <flat_set>
#include <functional>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class T, class... Args>
concept CanReplace = requires(T t, Args&&... args) { t.replace(std::forward<Args>(args)...); };
using Set = std::flat_set<int, int>;
static_assert(CanReplace<Set, std::vector<int>>);
static_assert(!CanReplace<Set, const std::vector<int>&>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
{
// was empty
M m;
KeyContainer new_keys = {7, 8};
auto expected_keys = new_keys;
m.replace(std::move(new_keys));
assert(m.size() == 2);
assert(std::ranges::equal(m, expected_keys));
}
M m = M({1, 2, 3});
KeyContainer new_keys = {7, 8};
auto expected_keys = new_keys;
m.replace(std::move(new_keys));
assert(m.size() == 2);
assert(std::ranges::equal(m, expected_keys));
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
void test_exception() {
#ifndef TEST_HAS_NO_EXCEPTIONS
using KeyContainer = ThrowOnMoveContainer<int>;
using M = std::flat_set<int, std::ranges::less, KeyContainer>;
M m;
m.emplace(1);
m.emplace(2);
try {
KeyContainer new_keys{3, 4};
m.replace(std::move(new_keys));
assert(false);
} catch (int) {
check_invariant(m);
// In libc++, we clear the map
LIBCPP_ASSERT(m.size() == 0);
}
#endif
}
int main(int, char**) {
test();
test_exception();
return 0;
}

View File

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// `check_assertion.h` requires Unix headers and regex support.
// REQUIRES: has-unix-headers
// UNSUPPORTED: no-localization
// UNSUPPORTED: no-exceptions
// <flat_set>
// void swap(flat_set& y) noexcept;
// friend void swap(flat_set& x, flat_set& y) noexcept
// Test that std::terminate is called if any exception is thrown during swap
#include <flat_set>
#include <cassert>
#include <deque>
#include <functional>
#include <vector>
#include "test_macros.h"
#include "../helpers.h"
#include "check_assertion.h"
template <class F>
void test_swap_exception_guarantee([[maybe_unused]] F&& swap_function) {
{
// key swap throws
using KeyContainer = ThrowOnMoveContainer<int>;
using M = std::flat_set<int, TransparentComparator, KeyContainer>;
M m1, m2;
m1.emplace(1);
m1.emplace(2);
m2.emplace(3);
m2.emplace(4);
// swap is noexcept
EXPECT_STD_TERMINATE([&] { swap_function(m1, m2); });
}
}
int main(int, char**) {
{
auto swap_func = [](auto& m1, auto& m2) { swap(m1, m2); };
test_swap_exception_guarantee(swap_func);
}
{
auto swap_func = [](auto& m1, auto& m2) { m1.swap(m2); };
test_swap_exception_guarantee(swap_func);
}
return 0;
}

View File

@ -0,0 +1,98 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// friend void swap(flat_set& x, flat_set& y) noexcept
#include <flat_set>
#include <cassert>
#include <deque>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "MoveOnly.h"
#include "min_allocator.h"
#include "test_macros.h"
#include "../helpers.h"
// test noexcept
template <class T>
concept NoExceptAdlSwap = requires(T t1, T t2) {
{ swap(t1, t2) } noexcept;
};
static_assert(NoExceptAdlSwap<std::flat_set<int>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(NoExceptAdlSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
{
M m1;
M m2;
M m1_save = m1;
M m2_save = m2;
swap(m1, m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12};
M m1;
M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0]));
M m1_save = m1;
M m2_save = m2;
swap(m1, m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar1[] = {1, 2, 3, 4};
M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0]));
M m2;
M m1_save = m1;
M m2_save = m2;
swap(m1, m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar1[] = {1, 2, 3, 4};
int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12};
M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0]));
M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0]));
M m1_save = m1;
M m2_save = m2;
swap(m1, m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,96 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// void swap(flat_set& y) noexcept;
#include <flat_set>
#include <cassert>
#include <deque>
#include <functional>
#include <vector>
#include "MinSequenceContainer.h"
#include "MoveOnly.h"
#include "min_allocator.h"
#include "test_macros.h"
#include "../helpers.h"
// test noexcept
template <class T>
concept NoExceptMemberSwap = requires(T t1, T t2) {
{ t1.swap(t2) } noexcept;
};
static_assert(NoExceptMemberSwap<std::flat_set<int>>);
#ifndef TEST_HAS_NO_EXCEPTIONS
static_assert(NoExceptMemberSwap<std::flat_set<int, std::less<int>, ThrowOnMoveContainer<int>>>);
#endif
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<Key>, KeyContainer>;
{
M m1;
M m2;
M m1_save = m1;
M m2_save = m2;
m1.swap(m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12};
M m1;
M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0]));
M m1_save = m1;
M m2_save = m2;
m1.swap(m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar1[] = {1, 2, 3, 4};
M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0]));
M m2;
M m1_save = m1;
M m2_save = m2;
m1.swap(m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
{
int ar1[] = {1, 2, 3, 4};
int ar2[] = {5, 6, 7, 8, 9, 10, 11, 12};
M m1(ar1, ar1 + sizeof(ar1) / sizeof(ar1[0]));
M m2(ar2, ar2 + sizeof(ar2) / sizeof(ar2[0]));
M m1_save = m1;
M m2_save = m2;
m1.swap(m2);
assert(m1 == m2_save);
assert(m2 == m1_save);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// key_compare key_comp() const;
// value_compare value_comp() const;
#include <cassert>
#include <flat_set>
#include <functional>
#include <utility>
#include <vector>
#include "test_macros.h"
void test() {
{
using M = std::flat_set<int>;
using Comp = std::less<int>; // the default
M m = {};
ASSERT_SAME_TYPE(M::key_compare, Comp);
ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp);
ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp);
Comp kc = m.key_comp();
assert(kc(1, 2));
assert(!kc(2, 1));
auto vc = m.value_comp();
assert(vc(1, 2));
assert(!vc(2, 1));
}
{
using Comp = std::function<bool(int, int)>;
using M = std::flat_set<int, Comp>;
Comp comp = std::greater<int>();
M m({}, comp);
ASSERT_SAME_TYPE(M::key_compare, Comp);
ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp);
ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp);
Comp kc = m.key_comp();
assert(!kc(1, 2));
assert(kc(2, 1));
auto vc = m.value_comp();
assert(!vc(1, 2));
assert(vc(2, 1));
}
{
using Comp = std::less<>;
using M = std::flat_set<int, Comp>;
M m = {};
ASSERT_SAME_TYPE(M::key_compare, Comp);
ASSERT_SAME_TYPE(decltype(m.key_comp()), Comp);
ASSERT_SAME_TYPE(decltype(m.value_comp()), Comp);
Comp kc = m.key_comp();
assert(kc(1, 2));
assert(!kc(2, 1));
auto vc = m.value_comp();
auto a = std::make_pair(1, 2);
ASSERT_SAME_TYPE(decltype(vc(a, a)), bool);
assert(vc(1, 2));
assert(!vc(2, 1));
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// bool contains(const key_type& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
assert(!m.contains(0));
assert(m.contains(1));
assert(m.contains(2));
assert(!m.contains(3));
assert(m.contains(4));
assert(m.contains(5));
assert(!m.contains(6));
assert(!m.contains(7));
assert(std::as_const(m).contains(8));
assert(!std::as_const(m).contains(9));
m.clear();
assert(!m.contains(1));
}
{
using M = std::flat_set<Key, std::greater<int>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
assert(!m.contains(0));
assert(m.contains(1));
assert(m.contains(2));
assert(!m.contains(3));
assert(m.contains(4));
assert(m.contains(5));
assert(!m.contains(6));
assert(!m.contains(7));
assert(std::as_const(m).contains(8));
assert(!std::as_const(m).contains(9));
m.clear();
assert(!m.contains(1));
}
{
// empty
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m;
assert(!m.contains(0));
assert(!m.contains(1));
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> bool contains(const K& x) const;
#include <cassert>
#include <flat_set>
#include <string>
#include <utility>
#include <deque>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanContains = requires(M m, Transparent<int> k) { m.contains(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanContains<TransparentSet>);
static_assert(CanContains<const TransparentSet>);
static_assert(!CanContains<NonTransparentSet>);
static_assert(!CanContains<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
ASSERT_SAME_TYPE(decltype(m.contains(Transparent<std::string>{"abc"})), bool);
ASSERT_SAME_TYPE(decltype(std::as_const(m).contains(Transparent<std::string>{"b"})), bool);
assert(m.contains(Transparent<std::string>{"alpha"}) == true);
assert(m.contains(Transparent<std::string>{"beta"}) == true);
assert(m.contains(Transparent<std::string>{"epsilon"}) == true);
assert(m.contains(Transparent<std::string>{"eta"}) == true);
assert(m.contains(Transparent<std::string>{"gamma"}) == true);
assert(m.contains(Transparent<std::string>{"al"}) == false);
assert(m.contains(Transparent<std::string>{""}) == false);
assert(m.contains(Transparent<std::string>{"g"}) == false);
}
{
// empty
M m;
assert(m.contains(Transparent<std::string>{"gamma"}) == false);
assert(m.contains(Transparent<std::string>{"al"}) == false);
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto b = m.contains(Transparent<int>{3});
assert(b);
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// size_type count(const key_type& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using S = typename KeyContainer::size_type;
{
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.count(0)), S);
assert(m.count(0) == 0);
assert(m.count(1) == 1);
assert(m.count(2) == 1);
assert(m.count(3) == 0);
assert(m.count(4) == 1);
assert(m.count(5) == 1);
assert(m.count(6) == 0);
assert(m.count(7) == 0);
assert(std::as_const(m).count(8) == 1);
assert(std::as_const(m).count(9) == 0);
}
{
using M = std::flat_set<Key, std::greater<int>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.count(0)), S);
assert(m.count(0) == 0);
assert(m.count(1) == 1);
assert(m.count(2) == 1);
assert(m.count(3) == 0);
assert(m.count(4) == 1);
assert(m.count(5) == 1);
assert(m.count(6) == 0);
assert(m.count(7) == 0);
assert(std::as_const(m).count(8) == 1);
assert(std::as_const(m).count(9) == 0);
}
{
// empty
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m;
assert(m.count(0) == 0);
assert(m.count(1) == 0);
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> size_type count(const K& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanCount = requires(M m, Transparent<int> k) { m.count(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanCount<TransparentSet>);
static_assert(CanCount<const TransparentSet>);
static_assert(!CanCount<NonTransparentSet>);
static_assert(!CanCount<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
ASSERT_SAME_TYPE(decltype(m.count(Transparent<std::string>{"abc"})), typename M::size_type);
ASSERT_SAME_TYPE(decltype(std::as_const(m).count(Transparent<std::string>{"b"})), typename M::size_type);
assert(m.count(Transparent<std::string>{"alpha"}) == 1);
assert(m.count(Transparent<std::string>{"beta"}) == 1);
assert(m.count(Transparent<std::string>{"epsilon"}) == 1);
assert(m.count(Transparent<std::string>{"eta"}) == 1);
assert(m.count(Transparent<std::string>{"gamma"}) == 1);
assert(m.count(Transparent<std::string>{"al"}) == 0);
assert(m.count(Transparent<std::string>{""}) == 0);
assert(m.count(Transparent<std::string>{"g"}) == 0);
}
{
// empty
M m;
assert(m.count(Transparent<std::string>{"alpha"}) == 0);
assert(m.count(Transparent<std::string>{"beta"}) == 0);
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto n = m.count(Transparent<int>{3});
assert(n == 1);
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,88 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// pair<iterator,iterator> equal_range(const key_type& k);
// pair<const_iterator,const_iterator> equal_range(const key_type& k) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using M = std::flat_set<Key, std::less<>, KeyContainer>;
using R = std::pair<typename M::iterator, typename M::iterator>;
using CR = std::pair<typename M::const_iterator, typename M::const_iterator>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R);
ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR);
auto begin = m.begin();
assert(m.equal_range(0) == std::pair(begin, begin));
assert(m.equal_range(1) == std::pair(begin, begin + 1));
assert(m.equal_range(2) == std::pair(begin + 1, begin + 2));
assert(m.equal_range(3) == std::pair(begin + 2, begin + 2));
assert(m.equal_range(4) == std::pair(begin + 2, begin + 3));
assert(m.equal_range(5) == std::pair(begin + 3, begin + 4));
assert(m.equal_range(6) == std::pair(begin + 4, begin + 4));
assert(m.equal_range(7) == std::pair(begin + 4, begin + 4));
assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin() + 4, m.cbegin() + 5));
assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin() + 5, m.cbegin() + 5));
}
{
using M = std::flat_set<Key, std::greater<int>, KeyContainer>;
using R = std::pair<typename M::iterator, typename M::iterator>;
using CR = std::pair<typename M::const_iterator, typename M::const_iterator>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.equal_range(0)), R);
ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(0)), CR);
auto begin = m.begin();
assert(m.equal_range(0) == std::pair(begin + 5, begin + 5));
assert(m.equal_range(1) == std::pair(begin + 4, begin + 5));
assert(m.equal_range(2) == std::pair(begin + 3, begin + 4));
assert(m.equal_range(3) == std::pair(begin + 3, begin + 3));
assert(m.equal_range(4) == std::pair(begin + 2, begin + 3));
assert(m.equal_range(5) == std::pair(begin + 1, begin + 2));
assert(m.equal_range(6) == std::pair(begin + 1, begin + 1));
assert(m.equal_range(7) == std::pair(begin + 1, begin + 1));
assert(std::as_const(m).equal_range(8) == std::pair(m.cbegin(), m.cbegin() + 1));
assert(std::as_const(m).equal_range(9) == std::pair(m.cbegin(), m.cbegin()));
}
{
// empty
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m;
auto end = m.end();
assert(m.equal_range(0) == std::pair(end, end));
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,110 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> pair<iterator,iterator> equal_range(const K& x);
// template<class K> pair<const_iterator,const_iterator> equal_range(const K& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanEqualRange = requires(M m, Transparent<int> k) { m.equal_range(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanEqualRange<TransparentSet>);
static_assert(CanEqualRange<const TransparentSet>);
static_assert(!CanEqualRange<NonTransparentSet>);
static_assert(!CanEqualRange<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
using R = std::pair<typename M::iterator, typename M::iterator>;
using CR = std::pair<typename M::const_iterator, typename M::const_iterator>;
auto test_found = [](auto&& map, const std::string& expected_key) {
auto [first, last] = map.equal_range(Transparent<std::string>{expected_key});
assert(last - first == 1);
assert(*first == expected_key);
};
auto test_not_found = [](auto&& map, const std::string& expected_key, long expected_offset) {
auto [first, last] = map.equal_range(Transparent<std::string>{expected_key});
assert(first == last);
assert(first - map.begin() == expected_offset);
};
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
const auto& cm = m;
ASSERT_SAME_TYPE(decltype(m.equal_range(Transparent<std::string>{"abc"})), R);
ASSERT_SAME_TYPE(decltype(std::as_const(m).equal_range(Transparent<std::string>{"b"})), CR);
test_found(m, "alpha");
test_found(m, "beta");
test_found(m, "epsilon");
test_found(m, "eta");
test_found(m, "gamma");
test_found(cm, "alpha");
test_found(cm, "beta");
test_found(cm, "epsilon");
test_found(cm, "eta");
test_found(cm, "gamma");
test_not_found(m, "charlie", 2);
test_not_found(m, "aaa", 0);
test_not_found(m, "zzz", 5);
test_not_found(cm, "charlie", 2);
test_not_found(cm, "aaa", 0);
test_not_found(cm, "zzz", 5);
}
{
// empty
M m;
const auto& cm = m;
test_not_found(m, "aaa", 0);
test_not_found(cm, "charlie", 0);
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto p = m.equal_range(Transparent<int>{3});
assert(p.first != p.second);
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator find(const key_type& k);
// const_iterator find(const key_type& k) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, std::less<>, KeyContainer>;
{
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.find(0)), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).find(0)), typename M::const_iterator);
assert(m.find(0) == m.end());
assert(m.find(1) == m.begin());
assert(m.find(2) == m.begin() + 1);
assert(m.find(3) == m.end());
assert(m.find(4) == m.begin() + 2);
assert(m.find(5) == m.begin() + 3);
assert(m.find(6) == m.end());
assert(m.find(7) == m.end());
assert(std::as_const(m).find(8) == m.begin() + 4);
assert(std::as_const(m).find(9) == m.end());
}
{
// empty
M m;
assert(m.find(0) == m.end());
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> iterator find(const K& x);
// template<class K> const_iterator find(const K& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanFind = requires(M m, Transparent<int> k) { m.find(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanFind<TransparentSet>);
static_assert(CanFind<const TransparentSet>);
static_assert(!CanFind<NonTransparentSet>);
static_assert(!CanFind<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
const auto& cm = m;
ASSERT_SAME_TYPE(decltype(m.find(Transparent<std::string>{"abc"})), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).find(Transparent<std::string>{"b"})), typename M::const_iterator);
auto test_find = [](auto&& map, const std::string& expected_key, long expected_offset) {
auto iter = map.find(Transparent<std::string>{expected_key});
assert(iter - map.begin() == expected_offset);
};
test_find(m, "alpha", 0);
test_find(m, "beta", 1);
test_find(m, "epsilon", 2);
test_find(m, "eta", 3);
test_find(m, "gamma", 4);
test_find(m, "charlie", 5);
test_find(m, "aaa", 5);
test_find(m, "zzz", 5);
test_find(cm, "alpha", 0);
test_find(cm, "beta", 1);
test_find(cm, "epsilon", 2);
test_find(cm, "eta", 3);
test_find(cm, "gamma", 4);
test_find(cm, "charlie", 5);
test_find(cm, "aaa", 5);
test_find(cm, "zzz", 5);
}
{
// empty
M m;
auto iter = m.find(Transparent<std::string>{"a"});
assert(iter == m.end());
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto it = m.find(Transparent<int>{3});
assert(it != m.end());
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator lower_bound(const key_type& k);
// const_iterator lower_bound(const key_type& k) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator);
assert(m.lower_bound(0) == m.begin());
assert(m.lower_bound(1) == m.begin());
assert(m.lower_bound(2) == m.begin() + 1);
assert(m.lower_bound(3) == m.begin() + 2);
assert(m.lower_bound(4) == m.begin() + 2);
assert(m.lower_bound(5) == m.begin() + 3);
assert(m.lower_bound(6) == m.begin() + 4);
assert(m.lower_bound(7) == m.begin() + 4);
assert(std::as_const(m).lower_bound(8) == m.begin() + 4);
assert(std::as_const(m).lower_bound(9) == m.end());
}
{
using M = std::flat_set<Key, std::greater<int>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.lower_bound(0)), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(0)), typename M::const_iterator);
assert(m.lower_bound(0) == m.end());
assert(m.lower_bound(1) == m.begin() + 4);
assert(m.lower_bound(2) == m.begin() + 3);
assert(m.lower_bound(3) == m.begin() + 3);
assert(m.lower_bound(4) == m.begin() + 2);
assert(m.lower_bound(5) == m.begin() + 1);
assert(m.lower_bound(6) == m.begin() + 1);
assert(m.lower_bound(7) == m.begin() + 1);
assert(std::as_const(m).lower_bound(8) == m.begin());
assert(std::as_const(m).lower_bound(9) == m.begin());
}
{
// empty
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m;
assert(m.lower_bound(0) == m.end());
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,106 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> iterator lower_bound(const K& x);
// template<class K> const_iterator lower_bound(const K& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanLowerBound = requires(M m, Transparent<int> k) { m.lower_bound(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanLowerBound<TransparentSet>);
static_assert(CanLowerBound<const TransparentSet>);
static_assert(!CanLowerBound<NonTransparentSet>);
static_assert(!CanLowerBound<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
const auto& cm = m;
ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent<std::string>{"abc"})), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent<std::string>{"b"})), typename M::const_iterator);
auto test_lower_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) {
auto iter = map.lower_bound(Transparent<std::string>{expected_key});
assert(iter - map.begin() == expected_offset);
};
test_lower_bound(m, "abc", 0);
test_lower_bound(m, "alpha", 0);
test_lower_bound(m, "beta", 1);
test_lower_bound(m, "bets", 2);
test_lower_bound(m, "charlie", 2);
test_lower_bound(m, "echo", 2);
test_lower_bound(m, "epsilon", 2);
test_lower_bound(m, "eta", 3);
test_lower_bound(m, "gamma", 4);
test_lower_bound(m, "golf", 5);
test_lower_bound(m, "zzz", 5);
test_lower_bound(cm, "abc", 0);
test_lower_bound(cm, "alpha", 0);
test_lower_bound(cm, "beta", 1);
test_lower_bound(cm, "bets", 2);
test_lower_bound(cm, "charlie", 2);
test_lower_bound(cm, "echo", 2);
test_lower_bound(cm, "epsilon", 2);
test_lower_bound(cm, "eta", 3);
test_lower_bound(cm, "gamma", 4);
test_lower_bound(cm, "golf", 5);
test_lower_bound(cm, "zzz", 5);
}
{
// empty
M m;
auto iter = m.lower_bound(Transparent<std::string>{"a"});
assert(iter == m.end());
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto it = m.lower_bound(Transparent<int>{3});
assert(it != m.end());
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// iterator upper_bound(const key_type& k);
// const_iterator upper_bound(const key_type& k) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <functional>
#include <utility>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator);
assert(m.upper_bound(0) == m.begin());
assert(m.upper_bound(1) == m.begin() + 1);
assert(m.upper_bound(2) == m.begin() + 2);
assert(m.upper_bound(3) == m.begin() + 2);
assert(m.upper_bound(4) == m.begin() + 3);
assert(m.upper_bound(5) == m.begin() + 4);
assert(m.upper_bound(6) == m.begin() + 4);
assert(std::as_const(m).upper_bound(7) == m.begin() + 4);
assert(std::as_const(m).upper_bound(8) == m.end());
assert(std::as_const(m).upper_bound(9) == m.end());
}
{
using M = std::flat_set<Key, std::greater<int>, KeyContainer>;
M m = {1, 2, 4, 5, 8};
ASSERT_SAME_TYPE(decltype(m.upper_bound(0)), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).upper_bound(0)), typename M::const_iterator);
assert(m.upper_bound(0) == m.end());
assert(m.upper_bound(1) == m.end());
assert(m.upper_bound(2) == m.begin() + 4);
assert(m.upper_bound(3) == m.begin() + 3);
assert(m.upper_bound(4) == m.begin() + 3);
assert(m.upper_bound(5) == m.begin() + 2);
assert(m.upper_bound(6) == m.begin() + 1);
assert(m.upper_bound(7) == m.begin() + 1);
assert(std::as_const(m).upper_bound(8) == m.begin() + 1);
assert(std::as_const(m).upper_bound(9) == m.begin());
}
{
// empty
using M = std::flat_set<Key, std::less<>, KeyContainer>;
M m;
assert(m.upper_bound(0) == m.end());
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,106 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// template<class K> iterator upper_bound(const K& x);
// template<class K> const_iterator upper_bound(const K& x) const;
#include <cassert>
#include <deque>
#include <flat_set>
#include <string>
#include <utility>
#include "MinSequenceContainer.h"
#include "../helpers.h"
#include "test_macros.h"
#include "min_allocator.h"
// Constraints: The qualified-id Compare::is_transparent is valid and denotes a type.
template <class M>
concept CanUpperBound = requires(M m, Transparent<int> k) { m.upper_bound(k); };
using TransparentSet = std::flat_set<int, TransparentComparator>;
using NonTransparentSet = std::flat_set<int, NonTransparentComparator>;
static_assert(CanUpperBound<TransparentSet>);
static_assert(CanUpperBound<const TransparentSet>);
static_assert(!CanUpperBound<NonTransparentSet>);
static_assert(!CanUpperBound<const NonTransparentSet>);
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
using M = std::flat_set<Key, TransparentComparator, KeyContainer>;
{
M m = {"alpha", "beta", "epsilon", "eta", "gamma"};
const auto& cm = m;
ASSERT_SAME_TYPE(decltype(m.lower_bound(Transparent<std::string>{"abc"})), typename M::iterator);
ASSERT_SAME_TYPE(decltype(std::as_const(m).lower_bound(Transparent<std::string>{"b"})), typename M::const_iterator);
auto test_upper_bound = [&](auto&& map, const std::string& expected_key, long expected_offset) {
auto iter = map.upper_bound(Transparent<std::string>{expected_key});
assert(iter - map.begin() == expected_offset);
};
test_upper_bound(m, "abc", 0);
test_upper_bound(m, "alpha", 1);
test_upper_bound(m, "beta", 2);
test_upper_bound(m, "bets", 2);
test_upper_bound(m, "charlie", 2);
test_upper_bound(m, "echo", 2);
test_upper_bound(m, "epsilon", 3);
test_upper_bound(m, "eta", 4);
test_upper_bound(m, "gamma", 5);
test_upper_bound(m, "golf", 5);
test_upper_bound(m, "zzz", 5);
test_upper_bound(cm, "abc", 0);
test_upper_bound(cm, "alpha", 1);
test_upper_bound(cm, "beta", 2);
test_upper_bound(cm, "bets", 2);
test_upper_bound(cm, "charlie", 2);
test_upper_bound(cm, "echo", 2);
test_upper_bound(cm, "epsilon", 3);
test_upper_bound(cm, "eta", 4);
test_upper_bound(cm, "gamma", 5);
test_upper_bound(cm, "golf", 5);
test_upper_bound(cm, "zzz", 5);
}
{
// empty
M m;
auto iter = m.upper_bound(Transparent<std::string>{"a"});
assert(iter == m.end());
}
}
void test() {
test_one<std::vector<std::string>>();
test_one<std::deque<std::string>>();
test_one<MinSequenceContainer<std::string>>();
test_one<std::vector<std::string, min_allocator<std::string>>>();
{
bool transparent_used = false;
TransparentComparator c(transparent_used);
std::flat_set<int, TransparentComparator> m(std::sorted_unique, {1, 2, 3}, c);
assert(!transparent_used);
auto it = m.upper_bound(Transparent<int>{2});
assert(it != m.end());
assert(transparent_used);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,307 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_CONTAINERS_CONTAINER_ADAPTORS_FLAT_SET_HELPERS_H
#define TEST_STD_CONTAINERS_CONTAINER_ADAPTORS_FLAT_SET_HELPERS_H
#include <algorithm>
#include <cassert>
#include <string>
#include <vector>
#include <flat_set>
#include "test_allocator.h"
#include "test_macros.h"
template <class... Args>
void check_invariant(const std::flat_set<Args...>& m) {
assert(std::is_sorted(m.begin(), m.end(), m.key_comp()));
auto key_equal = [&](const auto& x, const auto& y) {
const auto& c = m.key_comp();
return !c(x, y) && !c(y, x);
};
assert(std::adjacent_find(m.begin(), m.end(), key_equal) == m.end());
}
struct StartsWith {
explicit StartsWith(char ch) : lower_(1, ch), upper_(1, ch + 1) {}
StartsWith(const StartsWith&) = delete;
void operator=(const StartsWith&) = delete;
struct Less {
using is_transparent = void;
bool operator()(const std::string& a, const std::string& b) const { return a < b; }
bool operator()(const StartsWith& a, const std::string& b) const { return a.upper_ <= b; }
bool operator()(const std::string& a, const StartsWith& b) const { return a < b.lower_; }
bool operator()(const StartsWith&, const StartsWith&) const {
assert(false); // should not be called
return false;
}
};
private:
std::string lower_;
std::string upper_;
};
template <class T>
struct CopyOnlyVector : std::vector<T> {
using std::vector<T>::vector;
CopyOnlyVector(const CopyOnlyVector&) = default;
CopyOnlyVector(CopyOnlyVector&& other) : CopyOnlyVector(other) {}
CopyOnlyVector(CopyOnlyVector&& other, std::vector<T>::allocator_type alloc) : CopyOnlyVector(other, alloc) {}
CopyOnlyVector& operator=(const CopyOnlyVector&) = default;
CopyOnlyVector& operator=(CopyOnlyVector& other) { return this->operator=(other); }
};
template <class T, bool ConvertibleToT = false>
struct Transparent {
T t;
operator T() const
requires ConvertibleToT
{
return t;
}
};
template <class T>
using ConvertibleTransparent = Transparent<T, true>;
template <class T>
using NonConvertibleTransparent = Transparent<T, false>;
struct TransparentComparator {
using is_transparent = void;
bool* transparent_used = nullptr;
TransparentComparator() = default;
TransparentComparator(bool& used) : transparent_used(&used) {}
template <class T, bool Convertible>
bool operator()(const T& t, const Transparent<T, Convertible>& transparent) const {
if (transparent_used != nullptr) {
*transparent_used = true;
}
return t < transparent.t;
}
template <class T, bool Convertible>
bool operator()(const Transparent<T, Convertible>& transparent, const T& t) const {
if (transparent_used != nullptr) {
*transparent_used = true;
}
return transparent.t < t;
}
template <class T>
bool operator()(const T& t1, const T& t2) const {
return t1 < t2;
}
};
struct NonTransparentComparator {
template <class T, bool Convertible>
bool operator()(const T&, const Transparent<T, Convertible>&) const;
template <class T, bool Convertible>
bool operator()(const Transparent<T, Convertible>&, const T&) const;
template <class T>
bool operator()(const T&, const T&) const;
};
struct NoDefaultCtr {
NoDefaultCtr() = delete;
};
#ifndef TEST_HAS_NO_EXCEPTIONS
template <class T>
struct EmplaceUnsafeContainer : std::vector<T> {
using std::vector<T>::vector;
template <class... Args>
auto emplace(Args&&... args) -> decltype(std::declval<std::vector<T>>().emplace(std::forward<Args>(args)...)) {
if (this->size() > 1) {
auto it1 = this->begin();
auto it2 = it1 + 1;
// messing up the container
std::iter_swap(it1, it2);
}
throw 42;
}
template <class... Args>
auto insert(Args&&... args) -> decltype(std::declval<std::vector<T>>().insert(std::forward<Args>(args)...)) {
if (this->size() > 1) {
auto it1 = this->begin();
auto it2 = it1 + 1;
// messing up the container
std::iter_swap(it1, it2);
}
throw 42;
}
template <class... Args>
auto insert_range(Args&&... args)
-> decltype(std::declval<std::vector<T>>().insert_range(std::forward<Args>(args)...)) {
if (this->size() > 1) {
auto it1 = this->begin();
auto it2 = it1 + 1;
// messing up the container
std::iter_swap(it1, it2);
}
throw 42;
}
};
template <class T>
struct ThrowOnEraseContainer : std::vector<T> {
using std::vector<T>::vector;
template <class... Args>
auto erase(Args&&... args) -> decltype(std::declval<std::vector<T>>().erase(std::forward<Args>(args)...)) {
throw 42;
}
};
template <class T>
struct ThrowOnMoveContainer : std::vector<T> {
using std::vector<T>::vector;
ThrowOnMoveContainer(ThrowOnMoveContainer&&) { throw 42; }
ThrowOnMoveContainer& operator=(ThrowOnMoveContainer&&) { throw 42; }
};
#endif
template <class F>
void test_emplace_exception_guarantee([[maybe_unused]] F&& emplace_function) {
#ifndef TEST_HAS_NO_EXCEPTIONS
using C = TransparentComparator;
{
// Throw on emplace the key, and underlying has strong exception guarantee
using KeyContainer = std::vector<int, test_allocator<int>>;
using M = std::flat_set<int, C, KeyContainer>;
LIBCPP_STATIC_ASSERT(std::__container_traits<KeyContainer>::__emplacement_has_strong_exception_safety_guarantee);
test_allocator_statistics stats;
KeyContainer a({1, 2, 3, 4}, test_allocator<int>{&stats});
[[maybe_unused]] auto expected_keys = a;
M m(std::sorted_unique, std::move(a));
stats.throw_after = 1;
try {
emplace_function(m, 0);
assert(false);
} catch (const std::bad_alloc&) {
check_invariant(m);
// In libc++, the flat_set is unchanged
LIBCPP_ASSERT(m.size() == 4);
LIBCPP_ASSERT(std::ranges::equal(m, expected_keys));
}
}
{
// Throw on emplace the key, and underlying has no strong exception guarantee
using KeyContainer = EmplaceUnsafeContainer<int>;
using M = std::flat_set<int, C, KeyContainer>;
LIBCPP_STATIC_ASSERT(!std::__container_traits<KeyContainer>::__emplacement_has_strong_exception_safety_guarantee);
KeyContainer a = {1, 2, 3, 4};
M m(std::sorted_unique, std::move(a));
try {
emplace_function(m, 0);
assert(false);
} catch (int) {
check_invariant(m);
// In libc++, the flat_set is cleared
LIBCPP_ASSERT(m.size() == 0);
}
}
#endif
}
template <class F>
void test_insert_range_exception_guarantee([[maybe_unused]] F&& insert_function) {
#ifndef TEST_HAS_NO_EXCEPTIONS
using KeyContainer = EmplaceUnsafeContainer<int>;
using M = std::flat_set<int, std::ranges::less, KeyContainer>;
test_allocator_statistics stats;
KeyContainer a{1, 2, 3, 4};
M m(std::sorted_unique, std::move(a));
std::vector<int> newValues = {0, 1, 5, 6, 7, 8};
stats.throw_after = 1;
try {
insert_function(m, newValues);
assert(false);
} catch (int) {
check_invariant(m);
// In libc++, we clear if anything goes wrong when inserting a range
LIBCPP_ASSERT(m.size() == 0);
}
#endif
}
template <class F>
void test_erase_exception_guarantee([[maybe_unused]] F&& erase_function) {
#ifndef TEST_HAS_NO_EXCEPTIONS
{
// key erase throws
using KeyContainer = ThrowOnEraseContainer<int>;
using M = std::flat_set<int, TransparentComparator, KeyContainer>;
KeyContainer a{1, 2, 3, 4};
M m(std::sorted_unique, std::move(a));
try {
erase_function(m, 3);
assert(false);
} catch (int) {
check_invariant(m);
// In libc++, we clear if anything goes wrong when erasing
LIBCPP_ASSERT(m.size() == 0);
}
}
#endif
}
class Moveable {
int int_;
double double_;
public:
Moveable() : int_(0), double_(0) {}
Moveable(int i, double d) : int_(i), double_(d) {}
Moveable(Moveable&& x) : int_(x.int_), double_(x.double_) {
x.int_ = -1;
x.double_ = -1;
}
Moveable& operator=(Moveable&& x) {
int_ = x.int_;
x.int_ = -1;
double_ = x.double_;
x.double_ = -1;
return *this;
}
Moveable(const Moveable&) = delete;
Moveable& operator=(const Moveable&) = delete;
bool operator==(const Moveable& x) const { return int_ == x.int_ && double_ == x.double_; }
bool operator<(const Moveable& x) const { return int_ < x.int_ || (int_ == x.int_ && double_ < x.double_); }
int get() const { return int_; }
bool moved() const { return int_ == -1; }
};
#endif // TEST_STD_CONTAINERS_CONTAINER_ADAPTORS_FLAT_SET_HELPERS_H

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// Check that std::flat_set and its iterators can be instantiated with an incomplete
// type.
#include <flat_set>
#include <vector>
struct A {
using Set = std::flat_set<A>;
int data;
Set m;
Set::iterator it;
Set::const_iterator cit;
};
// Implement the operator< required in order to instantiate flat_set<A>
bool operator<(A const& L, A const& R) { return L.data < R.data; }
void test() { A a; }
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,110 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// <flat_set>
// friend bool operator==(const flat_set& x, const flat_set& y);
// friend synth-three-way-result<value_type>
// operator<=>(const flat_set& x, const flat_set& y);
#include <algorithm>
#include <cassert>
#include <deque>
#include <compare>
#include <flat_set>
#include <functional>
#include <limits>
#include <vector>
#include "MinSequenceContainer.h"
#include "test_macros.h"
#include "min_allocator.h"
#include "test_allocator.h"
#include "test_comparisons.h"
#include "test_container_comparisons.h"
template <class KeyContainer>
void test_one() {
using Key = typename KeyContainer::value_type;
{
using C = std::flat_set<Key>;
C s1 = {1};
C s2 = {2};
ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering);
AssertComparisonsReturnBool<C>();
assert(testComparisons(s1, s2, false, true));
s2 = {1};
assert(testComparisons(s1, s2, true, false));
s2 = {1, 2};
assert(testComparisons(s1, s2, false, true));
s1 = {0, 1, 2};
assert(testComparisons(s1, s2, false, true));
s2 = {0, 1, 3};
assert(testComparisons(s1, s2, false, true));
}
{
// Comparisons use value_type's native operators, not the comparator
using C = std::flat_set<Key, std::greater<Key>>;
C s1 = {1};
C s2 = {2};
ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::strong_ordering);
AssertComparisonsReturnBool<C>();
assert(testComparisons(s1, s2, false, true));
s2 = {1};
assert(testComparisons(s1, s2, true, false));
s2 = {1, 2};
assert(testComparisons(s1, s2, false, true));
s1 = {0, 1, 2};
assert(testComparisons(s1, s2, false, false));
s2 = {0, 1, 3};
assert(testComparisons(s1, s2, false, true));
}
}
void test() {
test_one<std::vector<int>>();
test_one<std::deque<int>>();
test_one<MinSequenceContainer<int>>();
test_one<std::vector<int, min_allocator<int>>>();
{
using C = std::flat_set<double>;
C s1 = {1};
C s2 = C(std::sorted_unique, {std::numeric_limits<double>::quiet_NaN()});
ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering);
AssertComparisonsReturnBool<C>();
assert(testComparisonsComplete(s1, s2, false, false, false));
}
{
// Comparisons use value_type's native operators, not the comparator
struct StrongComp {
bool operator()(double a, double b) const { return std::strong_order(a, b) < 0; }
};
using C = std::flat_set<double, StrongComp>;
C s1 = {1};
C s2 = {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()};
ASSERT_SAME_TYPE(decltype(s1 <=> s2), std::partial_ordering);
AssertComparisonsReturnBool<C>();
assert(testComparisonsComplete(s1, s2, false, false, false));
s1 = {1, std::numeric_limits<double>::quiet_NaN(), 1};
s2 = {std::numeric_limits<double>::quiet_NaN(), 1};
assert(std::lexicographical_compare_three_way(s1.begin(), s1.end(), s2.begin(), s2.end(), std::strong_order) ==
std::strong_ordering::equal);
assert(s1 != s2);
assert((s1 <=> s2) == std::partial_ordering::unordered);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,94 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// using key_type = Key;
// using value_type = Key;
// using key_compare = Compare;
// using value_compare = Compare;
// using reference = value_type&;
// using const_reference = const value_type&;
// using size_type = typename KeyContainer::size_type;
// using difference_type = typename KeyContainer::difference_type;
// using iterator = implementation-defined; // see [container.requirements]
// using const_iterator = implementation-defined; // see [container.requirements]
// using reverse_iterator = std::reverse_iterator<iterator>;
// using const_reverse_iterator = std::reverse_iterator<const_iterator>;
// using container_type = KeyContainer;
#include <concepts>
#include <deque>
#include <flat_set>
#include <functional>
#include <ranges>
#include <string>
#include <vector>
#include "min_allocator.h"
void test() {
{
using M = std::flat_set<int>;
static_assert(std::is_same_v<typename M::key_type, int>);
static_assert(std::is_same_v<typename M::value_type, int>);
static_assert(std::is_same_v<typename M::key_compare, std::less<int>>);
static_assert(std::is_same_v<typename M::value_compare, std::less<int>>);
static_assert(std::is_same_v<typename M::reference, int&>);
static_assert(std::is_same_v<typename M::const_reference, const int&>);
static_assert(std::is_same_v<typename M::size_type, size_t>);
static_assert(std::is_same_v<typename M::difference_type, ptrdiff_t>);
static_assert(requires { typename M::iterator; });
static_assert(requires { typename M::const_iterator; });
static_assert(std::is_same_v<typename M::reverse_iterator, std::reverse_iterator<typename M::iterator>>);
static_assert(
std::is_same_v<typename M::const_reverse_iterator, std::reverse_iterator<typename M::const_iterator>>);
static_assert(std::is_same_v<typename M::container_type, std::vector<int>>);
static_assert(requires { typename M::value_compare; });
}
{
struct A {};
struct Compare {
bool operator()(const std::string&, const std::string&) const;
};
using M = std::flat_set<std::string, Compare, std::deque<std::string>>;
static_assert(std::is_same_v<typename M::key_type, std::string>);
static_assert(std::is_same_v<typename M::value_type, std::string>);
static_assert(std::is_same_v<typename M::key_compare, Compare>);
static_assert(std::is_same_v<typename M::value_compare, Compare>);
static_assert(std::is_same_v<typename M::reference, std::string&>);
static_assert(std::is_same_v<typename M::const_reference, const std::string&>);
static_assert(std::is_same_v<typename M::size_type, size_t>);
static_assert(std::is_same_v<typename M::difference_type, ptrdiff_t>);
static_assert(requires { typename M::iterator; });
static_assert(requires { typename M::const_iterator; });
static_assert(std::is_same_v<typename M::reverse_iterator, std::reverse_iterator<typename M::iterator>>);
static_assert(
std::is_same_v<typename M::const_reverse_iterator, std::reverse_iterator<typename M::const_iterator>>);
static_assert(std::is_same_v<typename M::container_type, std::deque<std::string>>);
}
{
using C = std::flat_set<short, std::greater<long>, std::deque<short, min_allocator<short>>>;
static_assert(std::is_same_v<C::key_type, short>);
static_assert(std::is_same_v<C::value_type, short>);
static_assert(std::is_same_v<C::key_compare, std::greater<long>>);
static_assert(std::is_same_v<C::value_compare, std::greater<long>>);
static_assert(std::is_same_v<C::reference, short&>);
static_assert(std::is_same_v<C::const_reference, const short&>);
static_assert(std::random_access_iterator<C::iterator>);
static_assert(std::random_access_iterator<C::const_iterator>);
static_assert(std::random_access_iterator<C::reverse_iterator>);
static_assert(std::random_access_iterator<C::const_reverse_iterator>);
static_assert(std::is_same_v<C::reverse_iterator, std::reverse_iterator<C::iterator>>);
static_assert(std::is_same_v<C::const_reverse_iterator, std::reverse_iterator<C::const_iterator>>);
// size_type is invariably size_t
static_assert(std::is_same_v<C::size_type, std::size_t>);
static_assert(std::is_same_v<C::difference_type, std::ptrdiff_t>);
static_assert(std::is_same_v<C::container_type, std::deque<short, min_allocator<short>>>);
}
}

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// WARNING: This test was generated by generate_feature_test_macro_components.py
// and should not be edited manually.
//
// clang-format off
// <flat_set>
// Test the feature test macros defined by <flat_set>
/* Constant Value
__cpp_lib_flat_set 202207L [C++23]
*/
#include <flat_set>
#include "test_macros.h"
#if TEST_STD_VER < 14
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined before c++23"
# endif
#elif TEST_STD_VER == 14
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined before c++23"
# endif
#elif TEST_STD_VER == 17
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined before c++23"
# endif
#elif TEST_STD_VER == 20
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined before c++23"
# endif
#elif TEST_STD_VER == 23
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should be defined in c++23"
# endif
# if __cpp_lib_flat_set != 202207L
# error "__cpp_lib_flat_set should have the value 202207L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!"
# endif
# endif
#elif TEST_STD_VER > 23
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should be defined in c++26"
# endif
# if __cpp_lib_flat_set != 202207L
# error "__cpp_lib_flat_set should have the value 202207L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_flat_set
# error "__cpp_lib_flat_set should not be defined because it is unimplemented in libc++!"
# endif
# endif
#endif // TEST_STD_VER > 23

View File

@ -164,7 +164,6 @@ module_c_headers = [h for h in all_headers if h.has_cxx20_module() and h.is_cstd
# modules will fail to build if a header is added but this list is not updated.
headers_not_available = list(map(Header, [
"debugging",
"flat_set",
"generator",
"hazard_pointer",
"inplace_vector",
@ -261,6 +260,7 @@ mandatory_inclusions = {
"deque": ["compare", "initializer_list"],
"filesystem": ["compare"],
"flat_map": ["compare", "initializer_list"],
"flat_set": ["compare", "initializer_list"],
"forward_list": ["compare", "initializer_list"],
"ios": ["iosfwd"],
"iostream": ["ios", "istream", "ostream", "streambuf"],

View File

@ -92,6 +92,9 @@ ExtraHeader["ranges"] = "v1/__fwd/subrange.h$"
# same definition.
ExtraHeader["functional"] = "v1/__compare/compare_three_way.h$"
# <flat_set> reuses some functionality defined inside <flat_map>
ExtraHeader["flat_set"] = "v1/__flat_map/sorted_unique.h$"
# Some C compatibility headers define std::size_t, which is in <__cstddef/size_t.h>
for header in ("cstdio", "cstdlib", "cstring", "ctime", "cuchar", "cwchar"):
ExtraHeader[header] = "v1/__cstddef/size_t.h$"