On 17/03/2025 09:21, Tomasz Kamiński wrote:
This is another piece of P1206R7, adding new members to std::set
and std::multiset.
PR libstdc++/111055
libstdc++-v3/ChangeLog:
* include/bits/stl_multiset.h: (inser_range)
(multiset(from_range_t, _Rg&&, const _Compare&, const _Alloc&))
(multiset(from_range_t, _Rg&&, const _Alloc&)): Define.
* include/bits/stl_set.h: (set(from_range_t, _Rg&&, const _Alloc&))
(set(from_range_t, _Rg&&, const _Compare&, const _Alloc&),
insert_range):
Define.
* testsuite/23_containers/multiset/cons/from_range.cc: New test.
* testsuite/23_containers/multiset/modifiers/insert/insert_range.cc:
New test.
* testsuite/23_containers/set/cons/from_range.cc: New test.
* testsuite/23_containers/set/modifiers/insert/insert_range.cc: New
test.
---
Added missing includes, replaced spaces with tabs.
Tested on x86_64-linux without PCH. OK for trunk?
libstdc++-v3/include/bits/stl_multiset.h | 52 ++++++++
libstdc++-v3/include/bits/stl_set.h | 55 ++++++++
.../23_containers/multiset/cons/from_range.cc | 118 ++++++++++++++++++
.../multiset/modifiers/insert/insert_range.cc | 76 +++++++++++
.../23_containers/set/cons/from_range.cc | 117 +++++++++++++++++
.../set/modifiers/insert/insert_range.cc | 79 ++++++++++++
6 files changed, 497 insertions(+)
create mode 100644
libstdc++-v3/testsuite/23_containers/multiset/cons/from_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/multiset/modifiers/insert/insert_range.cc
create mode 100644 libstdc++-v3/testsuite/23_containers/set/cons/from_range.cc
create mode 100644
libstdc++-v3/testsuite/23_containers/set/modifiers/insert/insert_range.cc
diff --git a/libstdc++-v3/include/bits/stl_multiset.h
b/libstdc++-v3/include/bits/stl_multiset.h
index 57caf6e8cc4..1d40ae01de3 100644
--- a/libstdc++-v3/include/bits/stl_multiset.h
+++ b/libstdc++-v3/include/bits/stl_multiset.h
@@ -60,6 +60,9 @@
#if __cplusplus >= 201103L
#include <initializer_list>
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+# include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -271,6 +274,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
: _M_t(_Key_alloc_type(__a))
{ _M_t._M_insert_range_equal(__first, __last); }
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Builds a %set from a range.
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ multiset(from_range_t, _Rg&& __rg,
+ const _Compare& __comp,
+ const _Alloc& __a = _Alloc())
+ : _M_t(__comp, _Key_alloc_type(__a))
+ { insert_range(std::forward<_Rg>(__rg)); }
+
+ /// Allocator-extended range constructor.
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ multiset(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())
+ : _M_t(_Key_alloc_type(__a))
+ { insert_range(std::forward<_Rg>(__rg)); }
+#endif
+
/**
* The dtor only erases the elements, and note that if the elements
* themselves are pointers, the pointed-to memory is not touched in any
@@ -566,6 +588,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ this->insert(__l.begin(), __l.end()); }
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Inserts a range of elements.
+ * @since C++23
+ * @param __rg An input range of elements that can be converted to
+ * the list's value type.
Looks like a copy/paste, this comment should adapted to the current context.
+ */
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ void
+ insert_range(_Rg&& __rg)
+ {
+ auto __first = ranges::begin(__rg);
+ const auto __last = ranges::end(__rg);
+ for (; __first != __last; ++__first)
+ _M_t._M_emplace_equal(*__first);
+ }
+#endif
+
+
#ifdef __glibcxx_node_extract // >= C++17
/// Extract a node.
node_type
@@ -955,6 +996,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
multiset(initializer_list<_Key>, _Allocator)
-> multiset<_Key, less<_Key>, _Allocator>;
+#if __glibcxx_ranges_to_container // C++ >= 23
+ template<ranges::input_range _Rg,
+ __not_allocator_like _Compare = less<ranges::range_value_t<_Rg>>,
+ __allocator_like _Alloc = std::allocator<ranges::range_value_t<_Rg>>>
+ multiset(from_range_t, _Rg&&, _Compare = _Compare(), _Alloc = _Alloc())
+ -> multiset<ranges::range_value_t<_Rg>, _Compare, _Alloc>;
+
+ template<ranges::input_range _Rg, __allocator_like _Alloc>
+ multiset(from_range_t, _Rg&&, _Alloc)
+ -> multiset<ranges::range_value_t<_Rg>, less<ranges::range_value_t<_Rg>>,
_Alloc>;
+#endif
#endif // deduction guides
/**
diff --git a/libstdc++-v3/include/bits/stl_set.h
b/libstdc++-v3/include/bits/stl_set.h
index f32323db368..2f9b2bbfb5f 100644
--- a/libstdc++-v3/include/bits/stl_set.h
+++ b/libstdc++-v3/include/bits/stl_set.h
@@ -60,6 +60,9 @@
#if __cplusplus >= 201103L
#include <initializer_list>
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+# include <bits/ranges_base.h> // ranges::begin, ranges::distance etc.
+#endif
namespace std _GLIBCXX_VISIBILITY(default)
{
@@ -275,6 +278,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
: _M_t(_Key_alloc_type(__a))
{ _M_t._M_insert_range_unique(__first, __last); }
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Builds a %set from a range.
+ * @since C++23
+ */
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ set(from_range_t, _Rg&& __rg,
+ const _Compare& __comp,
+ const _Alloc& __a = _Alloc())
+ : _M_t(__comp, _Key_alloc_type(__a))
+ { insert_range(std::forward<_Rg>(__rg)); }
+
+ /// Allocator-extended range constructor.
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ set(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())
+ : _M_t(_Key_alloc_type(__a))
+ { insert_range(std::forward<_Rg>(__rg)); }
+#endif
+
/**
* The dtor only erases the elements, and note that if the elements
* themselves are pointers, the pointed-to memory is not touched in any
@@ -581,6 +603,28 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ this->insert(__l.begin(), __l.end()); }
#endif
+#if __glibcxx_ranges_to_container // C++ >= 23
+ /**
+ * @brief Inserts a range of elements.
+ * @since C++23
+ * @param __rg An input range of elements that can be converted to
+ * the list's value type.
+ */
+ template<__detail::__container_compatible_range<_Key> _Rg>
+ void
+ insert_range(_Rg&& __rg)
+ {
+ auto __first = ranges::begin(__rg);
+ const auto __last = ranges::end(__rg);
+ using _Rv = __remove_cvref_t<ranges::range_value_t<_Rg>>;
+ for (; __first != __last; ++__first)
+ if constexpr (is_same_v<_Rv, _Key>)
+ _M_t._M_insert_unique(*__first);
+ else
+ _M_t._M_emplace_unique(*__first);
I hope it's not a too naive question but why not always call
_M_emplace_unique ?