Skip to content

[libc++] Implement std::flat_multiset #128363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Apr 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_flat_map`` ``202207L``
---------------------------------------------------------- -----------------
``__cpp_lib_flat_set`` *unimplemented*
``__cpp_lib_flat_set`` ``202207L``
---------------------------------------------------------- -----------------
``__cpp_lib_format_ranges`` ``202207L``
---------------------------------------------------------- -----------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/ReleaseNotes/21.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ 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>`__)
- P0472R3: Put std::monostate in <utility> (`Github <https://github.com/llvm/llvm-project/issues/127874>`__)
- P1222R4: A Standard ``flat_set`` (`Github <https://github.com/llvm/llvm-project/issues/105193>`__)

Improvements and New Features
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx23Papers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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)","|In progress|","",""
"`P1222R4 <https://wg21.link/P1222R4>`__","A Standard ``flat_set``","2022-07 (Virtual)","|Complete|","21",""
"`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)","","",""
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,10 @@ set(files
__flat_map/sorted_equivalent.h
__flat_map/sorted_unique.h
__flat_map/utils.h
__flat_set/flat_multiset.h
__flat_set/flat_set.h
__flat_set/ra_iterator.h
__flat_set/utils.h
__format/buffer.h
__format/concepts.h
__format/container_adaptor.h
Expand Down
792 changes: 792 additions & 0 deletions libcxx/include/__flat_set/flat_multiset.h

Large diffs are not rendered by default.

41 changes: 6 additions & 35 deletions libcxx/include/__flat_set/flat_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <__cstddef/ptrdiff_t.h>
#include <__flat_map/sorted_unique.h>
#include <__flat_set/ra_iterator.h>
#include <__flat_set/utils.h>
#include <__functional/invoke.h>
#include <__functional/is_transparent.h>
#include <__functional/operations.h>
Expand Down Expand Up @@ -82,6 +83,8 @@ class flat_set {
template <class, class, class>
friend class flat_set;

friend __flat_set_utils;

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");

Expand Down Expand Up @@ -619,31 +622,11 @@ class flat_set {
__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)...);
__flat_set_utils::__append(*this, std::forward<_Args>(__args)...);
if (size() != __old_size) {
if constexpr (!_WasSorted) {
ranges::sort(__keys_.begin() + __old_size, __keys_.end(), __compare_);
Expand Down Expand Up @@ -680,23 +663,11 @@ class flat_set {
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);
return pair<iterator, bool>(__flat_set_utils::__emplace_exact_pos(*this, __it, std::forward<_Kp>(__key)), true);
} else {
return pair<iterator, bool>(std::move(__it), false);
}
Expand All @@ -717,7 +688,7 @@ class flat_set {
_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));
return __flat_set_utils::__emplace_exact_pos(*this, __hint, std::forward<_Kp>(__key));
} else {
// we already have an equal key
return __hint;
Expand Down
78 changes: 78 additions & 0 deletions libcxx/include/__flat_set/utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// -*- 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_UTILS_H
#define _LIBCPP___FLAT_SET_UTILS_H

#include <__config>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__type_traits/container_traits.h>
#include <__type_traits/decay.h>
#include <__utility/exception_guard.h>
#include <__utility/forward.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

#if _LIBCPP_STD_VER >= 23

_LIBCPP_BEGIN_NAMESPACE_STD

// These utilities are defined in a class instead of a namespace so that this class can be befriended more easily.
struct __flat_set_utils {
// Emplace a key into a flat_{multi}set, at the exact position that
// __it point to, assuming that the key is not already present in the set.
// When an exception is thrown during the emplacement, the function will clear the set if the container does not
// have strong exception safety guarantee on emplacement.
template <class _Set, class _Iter, class _KeyArg>
_LIBCPP_HIDE_FROM_ABI static auto __emplace_exact_pos(_Set& __set, _Iter&& __iter, _KeyArg&& __key) {
using _KeyContainer = typename decay_t<_Set>::container_type;
auto __on_failure = std::__make_exception_guard([&]() noexcept {
if constexpr (!__container_traits<_KeyContainer>::__emplacement_has_strong_exception_safety_guarantee) {
__set.clear() /* noexcept */;
}
});
auto __key_it = __set.__keys_.emplace(__iter.__base(), std::forward<_KeyArg>(__key));
__on_failure.__complete();
return typename decay_t<_Set>::iterator(std::move(__key_it));
}

template <class _Set, class _InputIterator>
_LIBCPP_HIDE_FROM_ABI static void __append(_Set& __set, _InputIterator __first, _InputIterator __last) {
__set.__keys_.insert(__set.__keys_.end(), std::move(__first), std::move(__last));
}

template <class _Set, class _Range>
_LIBCPP_HIDE_FROM_ABI static void __append(_Set& __set, _Range&& __rng) {
if constexpr (requires { __set.__keys_.insert_range(__set.__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.
__set.__keys_.insert_range(__set.__keys_.end(), std::forward<_Range>(__rng));
} else if constexpr (ranges::common_range<_Range>) {
__set.__keys_.insert(__set.__keys_.end(), ranges::begin(__rng), ranges::end(__rng));
} else {
for (auto&& __x : __rng) {
__set.__keys_.insert(__set.__keys_.end(), std::forward<decltype(__x)>(__x));
}
}
}
};
_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER >= 23

_LIBCPP_POP_MACROS

#endif // #define _LIBCPP___FLAT_SET_UTILS_H
17 changes: 17 additions & 0 deletions libcxx/include/flat_set
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ namespace std {
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);

// [flat.multiset], class template flat_multiset
template<class Key, class Compare = less<Key>, class KeyContainer = vector<Key>>
class flat_multiset;

struct sorted_equivalent_t { explicit sorted_equivalent_t() = default; };
inline constexpr sorted_equivalent_t sorted_equivalent{};

template<class Key, class Compare, class KeyContainer, class Allocator>
struct uses_allocator<flat_multiset<Key, Compare, KeyContainer>, Allocator>;

// [flat.multiset.erasure], erasure for flat_multiset
template<class Key, class Compare, class KeyContainer, class Predicate>
typename flat_multiset<Key, Compare, KeyContainer>::size_type
erase_if(flat_multiset<Key, Compare, KeyContainer>& c, Predicate pred);
}
*/

Expand All @@ -40,7 +55,9 @@ namespace std {
# include <__config>

# if _LIBCPP_STD_VER >= 23
# include <__flat_map/sorted_equivalent.h>
# include <__flat_map/sorted_unique.h>
# include <__flat_set/flat_multiset.h>
# include <__flat_set/flat_set.h>
# endif

Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -1304,13 +1304,16 @@ module std [system] {
module flat_set {
module flat_set {
header "__flat_set/flat_set.h"
header "__flat_set/flat_multiset.h"
export std.vector.vector
export std.vector.fwd
}
module ra_iterator { header "__flat_set/ra_iterator.h" }
module utils { header "__flat_set/utils.h" }

header "flat_set"
export std.flat_map.sorted_unique
export std.flat_map.sorted_equivalent
export *
}

Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_containers_ranges 202202L
# define __cpp_lib_expected 202211L
# define __cpp_lib_flat_map 202207L
// # define __cpp_lib_flat_set 202207L
# define __cpp_lib_flat_set 202207L
# define __cpp_lib_format_ranges 202207L
// # define __cpp_lib_formatters 202302L
# define __cpp_lib_forward_like 202207L
Expand Down
4 changes: 1 addition & 3 deletions libcxx/modules/std/flat_set.inc
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@ 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;

using std::sorted_equivalent;
using std::sorted_equivalent_t;
#endif
#endif // _LIBCPP_STD_VER >= 23
} // namespace std
Loading