{"id":2226153,"url":"http://patchwork.ozlabs.org/api/patches/2226153/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.3@forge-stage.sourceware.org/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.3@forge-stage.sourceware.org>","list_archive_url":null,"date":"2026-04-22T10:14:44","name":"[v1,3/3] libstdc++: Implement C++23 <flat_set> (P1222R4)","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"8ff5a1ba74565a00bc36dc5bf3edbd252784d8db","submitter":{"id":93215,"url":"http://patchwork.ozlabs.org/api/people/93215/?format=json","name":"ppalka via Sourceware Forge","email":"forge-bot+ppalka@forge-stage.sourceware.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.3@forge-stage.sourceware.org/mbox/","series":[{"id":500959,"url":"http://patchwork.ozlabs.org/api/series/500959/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=500959","date":"2026-04-22T10:14:41","name":"libstdc++: Implement C++23 <flat_map> and <flat_set>","version":1,"mbox":"http://patchwork.ozlabs.org/series/500959/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2226153/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2226153/checks/","tags":{},"related":[],"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org","sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org","server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g0w9w62zGz1y2d\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 20:16:36 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id F10F84B9DB64\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 10:16:34 +0000 (GMT)","from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id B04A54BA9011\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:15:59 +0000 (GMT)","from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id 7B26840556\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:15:59 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org F10F84B9DB64","OpenDKIM Filter v2.11.0 sourceware.org B04A54BA9011"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org B04A54BA9011","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org B04A54BA9011","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776852959; cv=none;\n b=NxlN1dIWp5zHE3JjGEKFa7KKYEObpyoz3mwWmOIS1fEudOvxIkCGyIfv015m8uLAdj/UnyC6AcQnNXoVnWVb9MiWTCsJMrz7VXBLVKYBsyioDlHEp0hPjRImNtt+XvRKzRpJ2FAt3MQyD9WrJ4JCwxAU6EVUP3K7z31KcTODCxk=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776852959; c=relaxed/simple;\n bh=42QprnOOXOuZzMtU33J/UeuqrS9cclTaJfQ3KOfzQ2o=;\n h=From:Date:Subject:To:Message-ID;\n b=WeqRbSR5DZIzferXNdafzf9bxsC0EFpjdGF69inXPhO+Wr0AINKi/f4tRWo+20SwaznLLZsZtbVJd/SRSgczIDee3fongRkwrKC08cvQYBC4ZeR7QYk3uIn1xS2wR/+GqcgYHmY8VDVlrjlDYNVBdNSMOmK0+h2Tieixz0cVJ9Y=","ARC-Authentication-Results":"i=1; server2.sourceware.org","From":"ppalka via Sourceware Forge\n <forge-bot+ppalka@forge-stage.sourceware.org>","Date":"Wed, 22 Apr 2026 10:14:44 +0000","Subject":"[PATCH v1 3/3] libstdc++: Implement C++23 <flat_set> (P1222R4)","To":"gcc-patches mailing list <gcc-patches@gcc.gnu.org>","Message-ID":"\n <bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.3@forge-stage.sourceware.org>","X-Mailer":"batrachomyomachia","X-Requested-Reviewer":"redi","X-Pull-Request-Organization":"gcc","X-Pull-Request-Repository":"gcc-TEST","X-Pull-Request":"https://forge.sourceware.org/gcc/gcc-TEST/pulls/9","References":"\n <bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.0@forge-stage.sourceware.org>","In-Reply-To":"\n <bmm.hhuay3vzv6.gcc.gcc-TEST.ppalka.9.1.0@forge-stage.sourceware.org>","X-Patch-URL":"\n https://forge.sourceware.org/gcc/gcc-TEST/commit/b564cb690469527d0825f7303ac8275ed19206d0","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Reply-To":"gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n ppalka@gcc.gnu.org","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"From: Patrick Palka <ppalka@redhat.com>\n\nThis implements the C++23 container adaptors std::flat_set and\nstd::flat_multiset from P1222R4.  The implementation is essentially\nan simpler and pared down version of std::flat_map.\n\nlibstdc++-v3/ChangeLog:\n\n\t* include/Makefile.am: Add new header <flat_set>.\n\t* include/Makefile.in: Regenerate.\n\t* include/bits/version.def (__cpp_flat_set): Define.\n\t* include/bits/version.h: Regenerate\n\t* include/std/flat_set: New file.\n\t* testsuite/23_containers/flat_multiset/1.cc: New test.\n\t* testsuite/23_containers/flat_set/1.cc: New test.\n---\n libstdc++-v3/include/Makefile.am              |    1 +\n libstdc++-v3/include/Makefile.in              |    1 +\n libstdc++-v3/include/bits/version.def         |    8 +\n libstdc++-v3/include/bits/version.h           |   10 +\n libstdc++-v3/include/precompiled/stdc++.h     |    1 +\n libstdc++-v3/include/std/flat_set             | 1040 +++++++++++++++++\n libstdc++-v3/src/c++23/std.cc.in              |   10 +\n .../23_containers/flat_multiset/1.cc          |  131 +++\n .../testsuite/23_containers/flat_set/1.cc     |  146 +++\n 9 files changed, 1348 insertions(+)\n create mode 100644 libstdc++-v3/include/std/flat_set\n create mode 100644 libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/flat_set/1.cc","diff":"diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am\nindex b606bcd49359..3e1e42e79737 100644\n--- a/libstdc++-v3/include/Makefile.am\n+++ b/libstdc++-v3/include/Makefile.am\n@@ -71,6 +71,7 @@ std_headers = \\\n \t${std_srcdir}/execution \\\n \t${std_srcdir}/filesystem \\\n \t${std_srcdir}/flat_map \\\n+\t${std_srcdir}/flat_set \\\n \t${std_srcdir}/format \\\n \t${std_srcdir}/forward_list \\\n \t${std_srcdir}/fstream \\\ndiff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in\nindex d277f87905b9..4c461afb7513 100644\n--- a/libstdc++-v3/include/Makefile.in\n+++ b/libstdc++-v3/include/Makefile.in\n@@ -427,6 +427,7 @@ std_freestanding = \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/execution \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/filesystem \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/flat_map \\\n+@GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/flat_set \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/format \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/forward_list \\\n @GLIBCXX_HOSTED_TRUE@\t${std_srcdir}/fstream \\\ndiff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def\nindex 171ee2780e8d..3b31cff51943 100644\n--- a/libstdc++-v3/include/bits/version.def\n+++ b/libstdc++-v3/include/bits/version.def\n@@ -1671,6 +1671,14 @@ ftms = {\n   };\n };\n \n+ftms = {\n+  name = flat_set;\n+  values = {\n+    v = 202207;\n+    cxxmin = 23;\n+  };\n+};\n+\n ftms = {\n   name = formatters;\n   values = {\ndiff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h\nindex 5e1858855eb6..ef27ae5e4fae 100644\n--- a/libstdc++-v3/include/bits/version.h\n+++ b/libstdc++-v3/include/bits/version.h\n@@ -1845,6 +1845,16 @@\n #endif /* !defined(__cpp_lib_flat_map) && defined(__glibcxx_want_flat_map) */\n #undef __glibcxx_want_flat_map\n \n+#if !defined(__cpp_lib_flat_set)\n+# if (__cplusplus >= 202100L)\n+#  define __glibcxx_flat_set 202207L\n+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_flat_set)\n+#   define __cpp_lib_flat_set 202207L\n+#  endif\n+# endif\n+#endif /* !defined(__cpp_lib_flat_set) && defined(__glibcxx_want_flat_set) */\n+#undef __glibcxx_want_flat_set\n+\n #if !defined(__cpp_lib_formatters)\n # if (__cplusplus >= 202100L) && _GLIBCXX_HOSTED\n #  define __glibcxx_formatters 202302L\ndiff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h\nindex 67ee00d073bb..3312a7a4dd4d 100644\n--- a/libstdc++-v3/include/precompiled/stdc++.h\n+++ b/libstdc++-v3/include/precompiled/stdc++.h\n@@ -226,6 +226,7 @@\n #if __cplusplus > 202002L\n #include <expected>\n #include <flat_map>\n+#include <flat_set>\n #include <generator>\n #include <print>\n #include <spanstream>\ndiff --git a/libstdc++-v3/include/std/flat_set b/libstdc++-v3/include/std/flat_set\nnew file mode 100644\nindex 000000000000..60205b64c933\n--- /dev/null\n+++ b/libstdc++-v3/include/std/flat_set\n@@ -0,0 +1,1040 @@\n+// <flat_set> -*- C++ -*-\n+\n+// Copyright The GNU Toolchain Authors.\n+//\n+// This file is part of the GNU ISO C++ Library.  This library is free\n+// software; you can redistribute it and/or modify it under the\n+// terms of the GNU General Public License as published by the\n+// Free Software Foundation; either version 3, or (at your option)\n+// any later version.\n+\n+// This library is distributed in the hope that it will be useful,\n+// but WITHOUT ANY WARRANTY; without even the implied warranty of\n+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+// GNU General Public License for more details.\n+\n+// Under Section 7 of GPL version 3, you are granted additional\n+// permissions described in the GCC Runtime Library Exception, version\n+// 3.1, as published by the Free Software Foundation.\n+\n+// You should have received a copy of the GNU General Public License and\n+// a copy of the GCC Runtime Library Exception along with this program;\n+// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see\n+// <http://www.gnu.org/licenses/>.\n+\n+/** @file include/flat_set\n+ *  This is a Standard C++ Library header.\n+ */\n+\n+#ifndef _GLIBCXX_FLAT_SET\n+#define _GLIBCXX_FLAT_SET 1\n+\n+#ifdef _GLIBCXX_SYSHDR\n+#pragma GCC system_header\n+#endif\n+\n+#define __glibcxx_want_flat_set\n+#include <bits/version.h>\n+\n+#ifdef __cpp_lib_flat_set // >= C++23\n+\n+#include <compare>\n+#include <initializer_list>\n+\n+#include <exception>\n+#include <functional> // not_fn\n+#include <optional>\n+#include <type_traits>\n+#include <vector>\n+#include <bits/functexcept.h>\n+#include <bits/stl_algo.h>\n+#include <bits/stl_function.h>  // less\n+#include <bits/stl_pair.h>\n+#include <bits/uses_allocator_args.h> // make_obj_using_allocator\n+#ifdef _GLIBCXX_DEBUG\n+# include <bits/ranges_algo.h> // ranges::is_sorted\n+#endif\n+\n+namespace std _GLIBCXX_VISIBILITY(default)\n+{\n+_GLIBCXX_BEGIN_NAMESPACE_VERSION\n+\n+  template<typename _Key, typename _Compare,\n+\t   typename _KeyContainer>\n+    class flat_set;\n+\n+  template<typename _Key, typename _Compare,\n+\t   typename _KeyContainer>\n+    class flat_multiset;\n+\n+  template<typename _Key, typename _Compare, typename _KeyContainer, bool _Multi>\n+    class _Flat_set_impl\n+    {\n+      static_assert(is_same_v<_Key, typename _KeyContainer::value_type>);\n+      static_assert(is_nothrow_swappable_v<_KeyContainer>);\n+\n+      using _Derived = __conditional_t<_Multi,\n+\t\t\t\t       flat_multiset<_Key, _Compare, _KeyContainer>,\n+\t\t\t\t       flat_set<_Key, _Compare, _KeyContainer>>;\n+      using __sorted_t = __conditional_t<_Multi, sorted_equivalent_t, sorted_unique_t>;\n+\n+    public:\n+      using key_type                = _Key;\n+      using value_type              = _Key;\n+      using key_compare             = _Compare;\n+      using value_compare           = _Compare;\n+      using reference               = value_type&;\n+      using const_reference         = const value_type&;\n+      using size_type               = typename _KeyContainer::size_type;\n+      using difference_type         = typename _KeyContainer::difference_type;\n+      using iterator                = typename _KeyContainer::const_iterator;\n+      using const_iterator          = typename _KeyContainer::const_iterator;\n+      using reverse_iterator        = std::reverse_iterator<iterator>;\n+      using const_reverse_iterator  = std::reverse_iterator<const_iterator>;\n+      using container_type          = _KeyContainer;\n+\n+    private:\n+      using __emplace_result_t = __conditional_t<_Multi, iterator, pair<iterator, bool>>;\n+\n+      struct _ClearGuard\n+      {\n+\tcontainer_type* _M_cont;\n+\n+\t_ClearGuard(container_type& __cont)\n+\t: _M_cont(std::__addressof(__cont))\n+\t{ }\n+\n+\t~_ClearGuard()\n+\t{\n+\t  if (_M_cont)\n+\t    _M_cont->clear();\n+\t}\n+\n+\tvoid\n+\t_M_disable()\n+\t{ _M_cont = nullptr; }\n+      };\n+\n+      _ClearGuard\n+      _M_make_clear_guard()\n+      { return _ClearGuard{this->_M_cont}; }\n+\n+    public:\n+      // constructors\n+      _Flat_set_impl() : _Flat_set_impl(key_compare()) { }\n+\n+      explicit\n+      _Flat_set_impl(const key_compare& __comp)\n+      : _M_cont(), _M_comp(__comp)\n+      { }\n+\n+      _Flat_set_impl(container_type __cont, const key_compare& __comp = key_compare())\n+      : _M_cont(std::move(__cont)), _M_comp(__comp)\n+      { _M_sort_uniq(); }\n+\n+      _Flat_set_impl(__sorted_t,\n+\t\t     container_type __cont, const key_compare& __comp = key_compare())\n+      : _M_cont(std::move(__cont)), _M_comp(__comp)\n+      { _GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(_M_cont, _M_comp)); }\n+\n+      template<__has_input_iter_cat _InputIterator>\n+\t_Flat_set_impl(_InputIterator __first, _InputIterator __last,\n+\t\t       const key_compare& __comp = key_compare())\n+\t: _M_cont(), _M_comp(__comp)\n+\t{ insert(__first, __last); }\n+\n+      template<__has_input_iter_cat _InputIterator>\n+\t_Flat_set_impl(__sorted_t __s,\n+\t\t       _InputIterator __first, _InputIterator __last,\n+\t\t       const key_compare& __comp = key_compare())\n+\t: _M_cont(), _M_comp(__comp)\n+\t{ insert(__s, __first, __last); }\n+\n+      template<__detail::__container_compatible_range<value_type> _Rg>\n+\t_Flat_set_impl(from_range_t __fr, _Rg&& __rg)\n+\t: _Flat_set_impl(__fr, std::forward<_Rg>(__rg), key_compare())\n+\t{ }\n+\n+      template<__detail::__container_compatible_range<value_type> _Rg>\n+\t_Flat_set_impl(from_range_t, _Rg&& __rg, const key_compare& __comp)\n+\t: _Flat_set_impl(__comp)\n+\t{ insert_range(std::forward<_Rg>(__rg)); }\n+\n+      _Flat_set_impl(initializer_list<value_type> __il,\n+\t\t     const key_compare& __comp = key_compare())\n+      : _Flat_set_impl(__il.begin(), __il.end(), __comp)\n+      { }\n+\n+      _Flat_set_impl(__sorted_t __s,\n+\t\t     initializer_list<value_type> __il,\n+\t\t     const key_compare& __comp = key_compare())\n+      : _Flat_set_impl(__s, __il.begin(), __il.end(), __comp)\n+      { }\n+\n+      // constructors with allocators\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\texplicit\n+\t_Flat_set_impl(const _Alloc& __a)\n+\t: _Flat_set_impl(key_compare(), __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(const key_compare& __comp, const _Alloc& __a)\n+\t: _M_cont(std::make_obj_using_allocator<container_type>(__a)),\n+\t  _M_comp(__comp)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(const container_type& __cont, const _Alloc& __a)\n+\t: _Flat_set_impl(__cont, key_compare(), __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(const container_type& __cont, const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _M_cont(std::make_obj_using_allocator<container_type>(__a, __cont)),\n+\t  _M_comp(__comp)\n+\t{ _M_sort_uniq(); }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t __s, const container_type& __cont, const _Alloc& __a)\n+\t: _Flat_set_impl(__s, __cont, key_compare(), __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t, const container_type& __cont, const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _M_cont(std::make_obj_using_allocator<container_type>(__a, __cont)),\n+\t  _M_comp(__comp)\n+\t{ _GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(_M_cont, _M_comp)); }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(const _Derived& __x, const _Alloc& __a)\n+\t: _M_cont(std::make_obj_using_allocator<container_type>(__a, __x._M_cont)),\n+\t  _M_comp(__x._M_comp)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(_Derived&& __x, const _Alloc& __a)\n+\t: _M_cont(std::make_obj_using_allocator<container_type>(__a, std::move(__x._M_cont))),\n+\t  _M_comp(__x._M_comp)\n+\t{ }\n+\n+      template<__has_input_iter_cat _InputIterator, __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(_InputIterator __first, _InputIterator __last,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(std::move(__first), std::move(__last), key_compare(), __a)\n+\t{ }\n+\n+      template<__has_input_iter_cat _InputIterator, __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(_InputIterator __first, _InputIterator __last,\n+\t\t       const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__comp, __a)\n+\t{ insert(__first, __last); }\n+\n+      template<__has_input_iter_cat _InputIterator, __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t __s,\n+\t\t       _InputIterator __first, _InputIterator __last,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__s, std::move(__first), std::move(__last), key_compare(), __a)\n+\t{ }\n+\n+      template<__has_input_iter_cat _InputIterator, __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t __s,\n+\t\t       _InputIterator __first, _InputIterator __last,\n+\t\t       const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__comp, __a)\n+\t{ insert(__s, __first, __last); }\n+\n+      template<__detail::__container_compatible_range<value_type> _Rg,\n+\t       __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(from_range_t __fr, _Rg&& __rg,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__fr, std::forward<_Rg>(__rg), key_compare(), __a)\n+\t{ }\n+\n+      template<__detail::__container_compatible_range<value_type> _Rg,\n+\t       __allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(from_range_t, _Rg&& __rg,\n+\t\t       const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__comp, __a)\n+\t{ insert_range(std::forward<_Rg>(__rg)); }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(initializer_list<value_type> __il,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__il, key_compare(), __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(initializer_list<value_type> __il,\n+\t\t       const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__il.begin(), __il.end(), __comp, __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t __s,\n+\t\t       initializer_list<value_type> __il,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__s, __il.begin(), __il.end(), key_compare(), __a)\n+\t{ }\n+\n+      template<__allocator_for<container_type> _Alloc>\n+\t_Flat_set_impl(__sorted_t __s,\n+\t\t       initializer_list<value_type> __il,\n+\t\t       const key_compare& __comp,\n+\t\t       const _Alloc& __a)\n+\t: _Flat_set_impl(__s, __il.begin(), __il.end(), __comp, __a)\n+\t{ }\n+\n+      _Derived&\n+      operator=(initializer_list<value_type> __il)\n+      {\n+\tauto __guard = _M_make_clear_guard();\n+\t_M_cont = __il;\n+\t_M_sort_uniq();\n+\t__guard._M_disable();\n+\treturn static_cast<_Derived&>(*this);\n+      }\n+\n+      // iterators\n+      const_iterator\n+      begin() const noexcept\n+      { return _M_cont.begin(); }\n+\n+      const_iterator\n+      end() const noexcept\n+      { return _M_cont.end(); }\n+\n+      const_reverse_iterator\n+      rbegin() const noexcept\n+      { return const_reverse_iterator(end()); }\n+\n+      const_reverse_iterator\n+      rend() const noexcept\n+      { return const_reverse_iterator(begin()); }\n+\n+      const_iterator\n+      cbegin() const noexcept\n+      { return begin(); }\n+\n+      const_iterator\n+      cend() const noexcept\n+      { return end(); }\n+\n+      const_reverse_iterator\n+      crbegin() const noexcept\n+      { return rbegin(); }\n+\n+      const_reverse_iterator\n+      crend() const noexcept\n+      { return rend(); }\n+\n+      // capacity\n+      [[nodiscard]] bool\n+      empty() const noexcept\n+      { return _M_cont.empty(); }\n+\n+      size_type\n+      size() const noexcept\n+      { return _M_cont.size(); }\n+\n+      size_type\n+      max_size() const noexcept\n+      { return _M_cont.max_size(); }\n+\n+      // modifiers\n+      template<typename... _Args>\n+\tpair<iterator, bool>\n+\t_M_try_emplace(optional<const_iterator> __hint, _Args&&... __args)\n+\t{\n+\t  // TODO: Simplify and audit the hint handling.\n+\t  value_type __k(std::forward<_Args>(__args)...);\n+\t  typename container_type::iterator __it;\n+\t  int __r = -1, __s = -1;\n+\t  if (__hint.has_value()\n+\t      && (__hint == cbegin()\n+\t\t  || (__r = !_M_comp(__k, (*__hint)[-1]))) // k >= hint[-1]\n+\t      && (__hint == cend()\n+\t\t  || (__s = !_M_comp((*__hint)[0], __k)))) // k <= hint[0]\n+\t    {\n+\t      __it = _M_cont.begin() + (*__hint - begin());\n+\t      if constexpr (!_Multi)\n+\t\tif (__r == 1 && !_M_comp(__it[-1], __k)) // k == hint[-1]\n+\t\t  return {__it - 1, false};\n+\t    }\n+\t  else\n+\t    {\n+\t      auto __first = _M_cont.begin();\n+\t      auto __last = _M_cont.end();\n+\t      if (__r == 1) // k >= hint[-1]\n+\t\t__first += *__hint - _M_cont.begin();\n+\t      else if (__r == 0) // k < __hint[-1]\n+\t\t__last = __first + (*__hint - _M_cont.begin());\n+\t      if constexpr (_Multi)\n+\t\t{\n+\t\t  if (__s == 0) // hint[0] < k\n+\t\t    // Insert before the leftmost equivalent key.\n+\t\t    __it = std::lower_bound(__first, __last, __k, _M_comp);\n+\t\t  else\n+\t\t    // Insert after the rightmost equivalent key.\n+\t\t    __it = std::upper_bound(std::make_reverse_iterator(__last),\n+\t\t\t\t\t    std::make_reverse_iterator(__first),\n+\t\t\t\t\t    __k, std::not_fn(_M_comp)).base();\n+\t\t}\n+\t      else\n+\t\t__it = std::lower_bound(__first, __last, __k, _M_comp);\n+\t    }\n+\n+\t  if constexpr (!_Multi)\n+\t    if (__it != _M_cont.end() && !_M_comp(__k, __it[0]))\n+\t      return {__it, false};\n+\n+\t  auto __guard = _M_make_clear_guard();\n+\t  __it = _M_cont.insert(__it, std::move(__k));\n+\t  __guard._M_disable();\n+\t  return {__it, true};\n+\t}\n+\n+      template<typename... _Args>\n+\trequires is_constructible_v<value_type, _Args...>\n+\t__emplace_result_t\n+\templace(_Args&&... __args)\n+\t{\n+\t  auto __r = _M_try_emplace(nullopt, std::forward<_Args>(__args)...);\n+\t  if constexpr (_Multi)\n+\t    return __r.first;\n+\t  else\n+\t    return __r;\n+\t}\n+\n+      template<typename... _Args>\n+\titerator\n+\templace_hint(const_iterator __position, _Args&&... __args)\n+\t{ return _M_try_emplace(__position, std::forward<_Args>(__args)...).first; }\n+\n+      __emplace_result_t\n+      insert(const value_type& __x)\n+      { return emplace(__x); }\n+\n+      __emplace_result_t\n+      insert(value_type&& __x)\n+      { return emplace(std::move(__x)); }\n+\n+      iterator\n+      insert(const_iterator __position, const value_type& __x)\n+      { return emplace_hint(__position, __x); }\n+\n+      iterator\n+      insert(const_iterator __position, value_type&& __x)\n+      { return emplace_hint(__position, std::move(__x)); }\n+\n+      template<typename _Arg>\n+\trequires is_constructible_v<value_type, _Arg>\n+\t__emplace_result_t\n+\tinsert(_Arg&& __x)\n+\t{ return emplace(std::forward<_Arg>(__x)); }\n+\n+      template<typename _Arg>\n+\trequires is_constructible_v<value_type, _Arg>\n+\titerator\n+\tinsert(const_iterator __position, _Arg&& __x)\n+\t{ return emplace_hint(__position, std::forward<_Arg>(__x)); }\n+\n+      template<__has_input_iter_cat _InputIterator>\n+\tvoid\n+\tinsert(_InputIterator __first, _InputIterator __last)\n+\t{\n+\t  auto __guard = _M_make_clear_guard();\n+\t  auto __it = _M_cont.insert(_M_cont.end(), __first, __last);\n+\t  std::sort(__it, _M_cont.end(), _M_comp);\n+\t  std::inplace_merge(_M_cont.begin(), __it, _M_cont.end(), _M_comp);\n+\t  if constexpr (!_Multi)\n+\t    _M_unique();\n+\t  __guard._M_disable();\n+\t}\n+\n+      template<__has_input_iter_cat _InputIterator>\n+\tvoid\n+\tinsert(__sorted_t, _InputIterator __first, _InputIterator __last)\n+\t{\n+\t  auto __guard = _M_make_clear_guard();\n+\t  auto __it = _M_cont.insert(_M_cont.end(), __first, __last);\n+\t  std::inplace_merge(_M_cont.begin(), __it, _M_cont.end(), _M_comp);\n+\t  if constexpr (!_Multi)\n+\t    _M_unique();\n+\t  __guard._M_disable();\n+\t}\n+\n+      template<__detail::__container_compatible_range<value_type> _Rg>\n+\tvoid\n+\tinsert_range(_Rg&& __rg)\n+\t{ insert(ranges::begin(__rg), ranges::end(__rg)); }\n+\n+      void\n+      insert(initializer_list<value_type> __il)\n+      { insert(__il.begin(), __il.end()); }\n+\n+      void\n+      insert(__sorted_t __s, initializer_list<value_type> __il)\n+      { insert(__s, __il.begin(), __il.end()); }\n+\n+      container_type\n+      extract() &&\n+      {\n+\tauto __guard = _M_make_clear_guard();\n+\treturn std::move(_M_cont);\n+      }\n+\n+      void\n+      replace(container_type&& __cont)\n+      {\n+\t_GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(__cont, _M_comp));\n+\tauto __guard = _M_make_clear_guard();\n+\t_M_cont = std::move(__cont);\n+\t__guard._M_disable();\n+      }\n+\n+      iterator\n+      erase(const_iterator __position)\n+      { return _M_cont.erase(__position); }\n+\n+      size_type\n+      erase(const key_type& __x)\n+      { return erase<const key_type&>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<remove_cvref_t<_Key2>, _Key>\n+\t  || (__transparent_comparator<_Compare>\n+\t      && !is_convertible_v<_Key2, iterator>\n+\t      && !is_convertible_v<_Key2, const_iterator>)\n+\tsize_type\n+\terase(_Key2&& __x)\n+\t{\n+\t  auto [__first, __last] = equal_range(std::forward<_Key2>(__x));\n+\t  auto __n = __last - __first;\n+\t  erase(__first, __last);\n+\t  return __n;\n+\t}\n+\n+      iterator\n+      erase(const_iterator __first, const_iterator __last)\n+      { return _M_cont.erase(__first, __last); }\n+\n+      void\n+      swap(_Derived& __x) noexcept\n+      {\n+\tusing std::swap;\n+\tswap(_M_cont, __x._M_cont);\n+\tswap(_M_comp, __x._M_comp);\n+      }\n+\n+      void\n+      clear() noexcept\n+      { _M_cont.clear(); }\n+\n+      // observers\n+      [[nodiscard]]\n+      key_compare\n+      key_comp() const\n+      { return _M_comp; }\n+\n+      [[nodiscard]]\n+      value_compare\n+      value_comp() const\n+      { return _M_comp; }\n+\n+      // map operations\n+      [[nodiscard]]\n+      iterator\n+      find(const key_type& __x)\n+      { return find<key_type>(__x); }\n+\n+      [[nodiscard]]\n+      const_iterator\n+      find(const key_type& __x) const\n+      { return find<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\titerator\n+\tfind(const _Key2& __x)\n+\t{\n+\t  auto __it = lower_bound(__x);\n+\t  if (__it != end() && !_M_comp(__x, *__it))\n+\t    return __it;\n+\t  else\n+\t    return end();\n+\t}\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tconst_iterator\n+\tfind(const _Key2& __x) const\n+\t{\n+\t  auto __it = lower_bound(__x);\n+\t  if (__it != cend() && !_M_comp(__x, *__it))\n+\t    return __it;\n+\t  else\n+\t    return cend();\n+\t}\n+\n+      [[nodiscard]]\n+      size_type\n+      count(const key_type& __x) const\n+      { return count<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tsize_type\n+\tcount(const _Key2& __x) const\n+\t{\n+\t  if constexpr (!_Multi)\n+\t    return contains<_Key2>(__x);\n+\t  else\n+\t    {\n+\t      auto [__first, __last] = equal_range(__x);\n+\t      return __last - __first;\n+\t    }\n+\t}\n+\n+      [[nodiscard]]\n+      bool\n+      contains(const key_type& __x) const\n+      { return contains<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tbool\n+\tcontains(const _Key2& __x) const\n+\t{ return find(__x) != cend(); }\n+\n+      [[nodiscard]]\n+      iterator\n+      lower_bound(const key_type& __x)\n+      { return lower_bound<key_type>(__x); }\n+\n+      [[nodiscard]]\n+      const_iterator\n+      lower_bound(const key_type& __x) const\n+      { return lower_bound<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\titerator\n+\tlower_bound(const _Key2& __x)\n+\t{ return std::lower_bound(begin(), end(), __x, _M_comp); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tconst_iterator\n+\tlower_bound(const _Key2& __x) const\n+\t{ return std::lower_bound(begin(), end(), __x, _M_comp); }\n+\n+      [[nodiscard]]\n+      iterator\n+      upper_bound(const key_type& __x)\n+      { return upper_bound<key_type>(__x); }\n+\n+      [[nodiscard]]\n+      const_iterator\n+      upper_bound(const key_type& __x) const\n+      { return upper_bound<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\titerator\n+\tupper_bound(const _Key2& __x)\n+\t{ return std::upper_bound(begin(), end(), __x, _M_comp); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tconst_iterator\n+\tupper_bound(const _Key2& __x) const\n+\t{ return std::upper_bound(begin(), end(), __x, _M_comp); }\n+\n+      [[nodiscard]]\n+      pair<iterator, iterator>\n+      equal_range(const key_type& __x)\n+      { return equal_range<key_type>(__x); }\n+\n+      [[nodiscard]]\n+      pair<const_iterator, const_iterator>\n+      equal_range(const key_type& __x) const\n+      { return equal_range<key_type>(__x); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tpair<iterator, iterator>\n+\tequal_range(const _Key2& __x)\n+\t{ return std::equal_range(begin(), end(), __x, _M_comp); }\n+\n+      template<typename _Key2>\n+\trequires same_as<_Key2, _Key> || __transparent_comparator<_Compare>\n+\t[[nodiscard]]\n+\tpair<const_iterator, const_iterator>\n+\tequal_range(const _Key2& __x) const\n+\t{ return std::equal_range(begin(), end(), __x, _M_comp); }\n+\n+      [[nodiscard]]\n+      friend bool\n+      operator==(const _Derived& __x, const _Derived& __y)\n+      { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }\n+\n+      template<typename _Up = value_type>\n+\t[[nodiscard]]\n+\tfriend __detail::__synth3way_t<_Up>\n+\toperator<=>(const _Derived& __x, const _Derived& __y)\n+\t{\n+\t  return std::lexicographical_compare_three_way(__x.begin(), __x.end(),\n+\t\t\t\t\t\t\t__y.begin(), __y.end(),\n+\t\t\t\t\t\t\t__detail::__synth3way);\n+\t}\n+\n+      friend void\n+      swap(_Derived& __x, _Derived& __y) noexcept\n+      { return __x.swap(__y); }\n+\n+      template<typename _Predicate>\n+\tfriend size_type\n+\terase_if(_Derived& __c, _Predicate __pred)\n+\t{\n+\t  auto __guard = __like_t<_Derived&, _Flat_set_impl>(__c)._M_make_clear_guard();\n+\t  auto __first = __c._M_cont.begin();\n+\t  auto __last = __c._M_cont.end();\n+\t  __first = std::remove_if(__first, __last, __pred);\n+\t  auto __n = __last - __first;\n+\t  __c.erase(__first, __last);\n+\t  __guard._M_disable();\n+\t  return __n;\n+\t}\n+\n+    private:\n+      container_type _M_cont;\n+      [[no_unique_address]] _Compare _M_comp;\n+\n+      void\n+      _M_sort_uniq()\n+      {\n+\tstd::sort(_M_cont.begin(), _M_cont.end(), _M_comp);\n+\tif constexpr (!_Multi)\n+\t  _M_unique();\n+      }\n+\n+      void\n+      _M_unique() requires (!_Multi)\n+      {\n+\tstruct __key_equiv\n+\t{\n+\t  __key_equiv(key_compare __c) : _M_comp(__c) { }\n+\n+\t  bool\n+\t  operator()(const_reference __x, const_reference __y) const\n+\t  { return !_M_comp(__x, __y) && !_M_comp(__y, __x); }\n+\n+\t  [[no_unique_address]] key_compare _M_comp;\n+\t};\n+\n+\tauto __first = _M_cont.begin();\n+\tauto __last = _M_cont.end();\n+\t__first = std::unique(__first, __last, __key_equiv(_M_comp));\n+\t_M_cont.erase(__first, __last);\n+      }\n+    };\n+\n+  /* Class template flat_set - container adaptor\n+   *\n+   * @ingroup\n+   */\n+  template<typename _Key, typename _Compare = less<_Key>,\n+\t   typename _KeyContainer = vector<_Key>>\n+    class flat_set\n+    : private _Flat_set_impl<_Key, _Compare, _KeyContainer, false>\n+    {\n+      using _Impl = _Flat_set_impl<_Key, _Compare, _KeyContainer, false>;\n+      friend _Impl;\n+\n+    public:\n+      // types\n+      using typename _Impl::key_type;\n+      using typename _Impl::value_type;\n+      using typename _Impl::key_compare;\n+      using typename _Impl::reference;\n+      using typename _Impl::const_reference;\n+      using typename _Impl::size_type;\n+      using typename _Impl::difference_type;\n+      using typename _Impl::iterator;\n+      using typename _Impl::const_iterator;\n+      using typename _Impl::reverse_iterator;\n+      using typename _Impl::const_reverse_iterator;\n+      using typename _Impl::container_type;\n+      using typename _Impl::value_compare;\n+\n+      // constructors\n+      using _Impl::_Impl;\n+\n+      // iterators\n+      using _Impl::begin;\n+      using _Impl::end;\n+      using _Impl::rbegin;\n+      using _Impl::rend;\n+\n+      using _Impl::cbegin;\n+      using _Impl::cend;\n+      using _Impl::crbegin;\n+      using _Impl::crend;\n+\n+      // capacity\n+      using _Impl::empty;\n+      using _Impl::size;\n+      using _Impl::max_size;\n+\n+      // modifiers\n+      using _Impl::emplace;\n+      using _Impl::emplace_hint;\n+      using _Impl::insert;\n+      // using _Impl::insert_range;\n+      using _Impl::extract;\n+      using _Impl::replace;\n+      using _Impl::erase;\n+      using _Impl::swap;\n+      using _Impl::clear;\n+\n+      // observers\n+      using _Impl::key_comp;\n+      using _Impl::value_comp;\n+\n+      // map operations\n+      using _Impl::find;\n+      using _Impl::count;\n+      using _Impl::contains;\n+      using _Impl::lower_bound;\n+      using _Impl::upper_bound;\n+      using _Impl::equal_range;\n+    };\n+\n+  template<typename _KeyContainer,\n+\t   __not_allocator_like _Compare = less<typename _KeyContainer::value_type>>\n+    flat_set(_KeyContainer, _Compare = _Compare())\n+    -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __allocator_for<_KeyContainer> _Alloc>\n+    flat_set(_KeyContainer, _Alloc)\n+    -> flat_set<typename _KeyContainer::value_type,\n+\t\tless<typename _KeyContainer::value_type>, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __not_allocator_like _Compare,\n+\t   __allocator_for<_KeyContainer> _Alloc>\n+    flat_set(_KeyContainer, _Compare, _Alloc)\n+    -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer,\n+\t   __not_allocator_like _Compare = less<typename _KeyContainer::value_type>>\n+    flat_set(sorted_unique_t, _KeyContainer, _Compare = _Compare())\n+    -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __allocator_for<_KeyContainer> _Alloc>\n+    flat_set(sorted_unique_t, _KeyContainer, _Alloc)\n+    -> flat_set<typename _KeyContainer::value_type,\n+\t\tless<typename _KeyContainer::value_type>, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __not_allocator_like _Compare,\n+\t   __allocator_for<_KeyContainer> _Alloc>\n+    flat_set(sorted_unique_t, _KeyContainer, _Compare, _Alloc)\n+    -> flat_set<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<__has_input_iter_cat _InputIterator,\n+\t   __not_allocator_like _Compare = less<__iter_key_t<_InputIterator>>>\n+    flat_set(_InputIterator, _InputIterator, _Compare = _Compare())\n+    -> flat_set<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>, _Compare>;\n+\n+  template<__has_input_iter_cat _InputIterator,\n+\t   __not_allocator_like _Compare = less<__iter_key_t<_InputIterator>>>\n+    flat_set(sorted_unique_t, _InputIterator, _InputIterator, _Compare = _Compare())\n+    -> flat_set<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>, _Compare>;\n+\n+  template<ranges::input_range _Rg,\n+\t   __not_allocator_like _Compare = less<ranges::range_value_t<_Rg>>,\n+\t   __allocator_like _Alloc = allocator<ranges::range_value_t<_Rg>>>\n+    flat_set(from_range_t, _Rg&&, _Compare = _Compare(), _Alloc = _Alloc())\n+    -> flat_set<ranges::range_value_t<_Rg>, _Compare,\n+\t\tvector<ranges::range_value_t<_Rg>,\n+\t\t       __alloc_rebind<_Alloc, ranges::range_value_t<_Rg>>>>;\n+\n+  template<ranges::input_range _Rg, __allocator_like _Alloc>\n+    flat_set(from_range_t, _Rg&&, _Alloc)\n+    -> flat_set<ranges::range_value_t<_Rg>, less<ranges::range_value_t<_Rg>>,\n+\t\tvector<ranges::range_value_t<_Rg>,\n+\t\t       __alloc_rebind<_Alloc, ranges::range_value_t<_Rg>>>>;\n+\n+  template<typename _Key, __not_allocator_like _Compare = less<_Key>>\n+    flat_set(initializer_list<_Key>, _Compare = _Compare())\n+    -> flat_set<_Key, _Compare>;\n+\n+  template<typename _Key, __not_allocator_like _Compare = less<_Key>>\n+    flat_set(sorted_unique_t, initializer_list<_Key>, _Compare = _Compare())\n+    -> flat_set<_Key, _Compare>;\n+\n+  template<typename _Key, typename _Compare,\n+\t   typename _KeyContainer, typename _Alloc>\n+    struct uses_allocator<flat_set<_Key, _Compare, _KeyContainer>, _Alloc>\n+    : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>>\n+    { };\n+\n+  /* Class template flat_multiset - container adaptor\n+   *\n+   * @ingroup\n+   */\n+  template<typename _Key, typename _Compare = less<_Key>,\n+\t   typename _KeyContainer = vector<_Key>>\n+    class flat_multiset\n+    : private _Flat_set_impl<_Key, _Compare, _KeyContainer, true>\n+    {\n+      using _Impl = _Flat_set_impl<_Key, _Compare, _KeyContainer, true>;\n+      friend _Impl;\n+\n+    public:\n+      // types\n+      using typename _Impl::key_type;\n+      using typename _Impl::value_type;\n+      using typename _Impl::key_compare;\n+      using typename _Impl::reference;\n+      using typename _Impl::const_reference;\n+      using typename _Impl::size_type;\n+      using typename _Impl::difference_type;\n+      using typename _Impl::iterator;\n+      using typename _Impl::const_iterator;\n+      using typename _Impl::reverse_iterator;\n+      using typename _Impl::const_reverse_iterator;\n+      using typename _Impl::container_type;\n+      using typename _Impl::value_compare;\n+\n+      // constructors\n+      using _Impl::_Impl;\n+\n+      // iterators\n+      using _Impl::begin;\n+      using _Impl::end;\n+      using _Impl::rbegin;\n+      using _Impl::rend;\n+\n+      using _Impl::cbegin;\n+      using _Impl::cend;\n+      using _Impl::crbegin;\n+      using _Impl::crend;\n+\n+      // capacity\n+      using _Impl::empty;\n+      using _Impl::size;\n+      using _Impl::max_size;\n+\n+      // modifiers\n+      using _Impl::emplace;\n+      using _Impl::emplace_hint;\n+      using _Impl::insert;\n+      // using _Impl::insert_range;\n+      using _Impl::extract;\n+      using _Impl::replace;\n+      using _Impl::erase;\n+      using _Impl::swap;\n+      using _Impl::clear;\n+\n+      // observers\n+      using _Impl::key_comp;\n+      using _Impl::value_comp;\n+\n+      // map operations\n+      using _Impl::find;\n+      using _Impl::count;\n+      using _Impl::contains;\n+      using _Impl::lower_bound;\n+      using _Impl::upper_bound;\n+      using _Impl::equal_range;\n+    };\n+\n+  template<typename _KeyContainer,\n+\t   __not_allocator_like _Compare = less<typename _KeyContainer::value_type>>\n+    flat_multiset(_KeyContainer, _Compare = _Compare())\n+    -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __allocator_for<_KeyContainer> _Alloc>\n+    flat_multiset(_KeyContainer, _Alloc)\n+    -> flat_multiset<typename _KeyContainer::value_type,\n+\t\t     less<typename _KeyContainer::value_type>, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __not_allocator_like _Compare,\n+\t   __allocator_for<_KeyContainer> _Alloc>\n+    flat_multiset(_KeyContainer, _Compare, _Alloc)\n+    -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer,\n+\t   __not_allocator_like _Compare = less<typename _KeyContainer::value_type>>\n+    flat_multiset(sorted_equivalent_t, _KeyContainer, _Compare = _Compare())\n+    -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __allocator_for<_KeyContainer> _Alloc>\n+    flat_multiset(sorted_equivalent_t, _KeyContainer, _Alloc)\n+    -> flat_multiset<typename _KeyContainer::value_type,\n+\t\t     less<typename _KeyContainer::value_type>, _KeyContainer>;\n+\n+  template<typename _KeyContainer, __not_allocator_like _Compare,\n+\t   __allocator_for<_KeyContainer> _Alloc>\n+    flat_multiset(sorted_equivalent_t, _KeyContainer, _Compare, _Alloc)\n+    -> flat_multiset<typename _KeyContainer::value_type, _Compare, _KeyContainer>;\n+\n+  template<__has_input_iter_cat _InputIterator,\n+\t   __not_allocator_like _Compare = less<__iter_key_t<_InputIterator>>>\n+    flat_multiset(_InputIterator, _InputIterator, _Compare = _Compare())\n+    -> flat_multiset<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>, _Compare>;\n+\n+  template<__has_input_iter_cat _InputIterator,\n+\t   __not_allocator_like _Compare = less<__iter_key_t<_InputIterator>>>\n+    flat_multiset(sorted_equivalent_t, _InputIterator, _InputIterator, _Compare = _Compare())\n+    -> flat_multiset<__iter_key_t<_InputIterator>, __iter_val_t<_InputIterator>, _Compare>;\n+\n+  template<ranges::input_range _Rg,\n+\t   __not_allocator_like _Compare = less<ranges::range_value_t<_Rg>>,\n+\t   __allocator_like _Alloc = allocator<ranges::range_value_t<_Rg>>>\n+    flat_multiset(from_range_t, _Rg&&, _Compare = _Compare(), _Alloc = _Alloc())\n+    -> flat_multiset<ranges::range_value_t<_Rg>, _Compare,\n+\t\t     vector<ranges::range_value_t<_Rg>,\n+\t\t\t    __alloc_rebind<_Alloc, ranges::range_value_t<_Rg>>>>;\n+\n+  template<ranges::input_range _Rg, __allocator_like _Alloc>\n+    flat_multiset(from_range_t, _Rg&&, _Alloc)\n+    -> flat_multiset<ranges::range_value_t<_Rg>, less<ranges::range_value_t<_Rg>>,\n+\t\t     vector<ranges::range_value_t<_Rg>,\n+\t\t\t    __alloc_rebind<_Alloc, ranges::range_value_t<_Rg>>>>;\n+\n+  template<typename _Key, __not_allocator_like _Compare = less<_Key>>\n+    flat_multiset(initializer_list<_Key>, _Compare = _Compare())\n+    -> flat_multiset<_Key, _Compare>;\n+\n+  template<typename _Key, __not_allocator_like _Compare = less<_Key>>\n+    flat_multiset(sorted_equivalent_t, initializer_list<_Key>, _Compare = _Compare())\n+    -> flat_multiset<_Key, _Compare>;\n+\n+  template<typename _Key, typename _Compare,\n+\t   typename _KeyContainer, typename _Alloc>\n+    struct uses_allocator<flat_multiset<_Key, _Compare, _KeyContainer>, _Alloc>\n+    : bool_constant<uses_allocator_v<_KeyContainer, _Alloc>>\n+    { };\n+\n+_GLIBCXX_END_NAMESPACE_VERSION\n+} // namespace std\n+#endif // __cpp_lib_flat_set\n+#endif // _GLIBCXX_FLAT_SET\ndiff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in\nindex 0225badeaacc..abec89908ab5 100644\n--- a/libstdc++-v3/src/c++23/std.cc.in\n+++ b/libstdc++-v3/src/c++23/std.cc.in\n@@ -1275,6 +1275,16 @@ export namespace std\n #endif\n \n // <flat_set>\n+#if __cpp_lib_flat_set\n+export namespace std\n+{\n+  using std::flat_set;\n+  using std::sorted_equivalent;\n+  using std::sorted_equivalent_t;\n+  using std::sorted_unique;\n+  using std::sorted_unique_t;\n+}\n+#endif\n \n // <format>\n export namespace std\ndiff --git a/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc\nnew file mode 100644\nindex 000000000000..c05cda33b05d\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/flat_multiset/1.cc\n@@ -0,0 +1,131 @@\n+// { dg-do run { target c++23 } }\n+\n+#include <flat_set>\n+#include <deque>\n+#include <vector>\n+#include <testsuite_allocator.h>\n+#include <testsuite_hooks.h>\n+\n+template<template<class> class Sequence>\n+void\n+test01()\n+{\n+  std::flat_multiset<int, std::less<int>, Sequence<int>> m;\n+  static_assert( std::ranges::random_access_range<decltype(m)> );\n+\n+  m.insert(1);\n+  m.insert(2);\n+  m.insert(3);\n+  m.insert(1);\n+  m.insert(2);\n+  m.insert(3);\n+  m.insert(0);\n+  VERIFY( m.size() == 7 );\n+  VERIFY( std::ranges::equal(m, (int[]){0, 1, 1, 2, 2, 3, 3}) );\n+\n+  m.clear();\n+  m.insert(m.begin(), 0);\n+  m.insert(m.begin(), 1);\n+  m.insert(m.begin(), 2);\n+  m.insert(m.begin(), 3);\n+  m.insert(m.begin(), 1);\n+  m.insert(m.begin(), 2);\n+  m.insert(m.begin(), 3);\n+  m.insert(m.begin(), 0);\n+  VERIFY( std::ranges::equal(m, (int[]){0, 0, 1, 1, 2, 2, 3, 3}) );\n+\n+  m.clear();\n+  m = {10,10};\n+  VERIFY( m.size() == 2 );\n+  m.insert({11,12,11});\n+  VERIFY( m.size() == 5 );\n+}\n+\n+void\n+test02()\n+{\n+  std::flat_multiset<int, std::greater<int>> m;\n+  static_assert( std::ranges::random_access_range<decltype(m)> );\n+\n+  auto r = m.insert(1);\n+  VERIFY( *r == 1 );\n+  r = m.insert(2);\n+  VERIFY( *r == 2 );\n+  r = m.insert(3);\n+  VERIFY( *r == 3 );\n+  r = m.insert(1);\n+  VERIFY( *r == 1 );\n+  r = m.insert(2);\n+  VERIFY( *r == 2 );\n+  r = m.insert(3);\n+  VERIFY( *r == 3 );\n+  VERIFY( m.size() == 6 );\n+  VERIFY( std::ranges::equal(m, (int[]){3, 3, 2, 2, 1, 1}) );\n+\n+  VERIFY( m.contains(3) && !m.contains(7) );\n+  VERIFY( m.count(3) == 2 );\n+}\n+\n+void\n+test03()\n+{\n+  std::flat_set<int> m;\n+  m = {1, 3, 5};\n+  m.insert({7, 9});\n+\n+  auto it = m.find(0);\n+  VERIFY( it == m.end() );\n+  it = m.find(9);\n+  VERIFY( it == m.end()-1 );\n+\n+  const auto n = m;\n+  VERIFY( m == m );\n+  VERIFY( m == n );\n+\n+  m.erase(m.begin());\n+  m.erase(5);\n+  m.erase(m.end()-2, m.end());\n+  VERIFY( std::ranges::equal(m, (int[]){3}) );\n+  VERIFY( m != n );\n+  VERIFY( n < m );\n+\n+  m = n;\n+  erase_if(m, [](const auto& k) { return k < 5 || k > 5; });\n+  VERIFY( std::ranges::equal(m, (int[]){5}) );\n+}\n+\n+void\n+test04()\n+{\n+  using vector = std::vector<int, __gnu_test::uneq_allocator<int>>;\n+  vector v = {1, 2, 3};\n+  __gnu_test::uneq_allocator<int> alloc(42);\n+\n+  using flat_multiset = std::flat_multiset<int, std::less<int>, vector>;\n+  flat_multiset m1(alloc);\n+  VERIFY( std::move(m1).extract().get_allocator().get_personality() == 42 );\n+\n+  flat_multiset m2(v, alloc);\n+  VERIFY( std::move(m2).extract().get_allocator().get_personality() == 42 );\n+\n+  flat_multiset m2(std::sorted_equivalent_t{}, v, alloc);\n+  VERIFY( std::move(m2).extract().get_allocator().get_personality() == 42 );\n+\n+  alloc = __gnu_test::uneq_allocator<int>(43);\n+  flat_multiset m4(m2, alloc);\n+  VERIFY( std::move(m4).extract().get_allocator().get_personality() == 43 );\n+\n+  alloc = __gnu_test::uneq_allocator<int>(44);\n+  flat_multiset m5(std::move(m4), alloc);\n+  VERIFY( std::move(m5).extract().get_allocator().get_personality() == 44 );\n+}\n+\n+int\n+main()\n+{\n+  test01<std::vector>();\n+  test01<std::deque>();\n+  test02();\n+  test03();\n+  test04();\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/flat_set/1.cc b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc\nnew file mode 100644\nindex 000000000000..13c71f4c1df0\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/flat_set/1.cc\n@@ -0,0 +1,146 @@\n+// { dg-do run { target c++23 } }\n+\n+#include <flat_set>\n+\n+#if __cpp_lib_flat_set != 202207L\n+# error \"Feature-test macro __cpp_lib_flat_set has wrong value in <flat_set>\"\n+#endif\n+\n+#include <deque>\n+#include <vector>\n+#include <testsuite_allocator.h>\n+#include <testsuite_hooks.h>\n+\n+template<template<class> class Sequence>\n+void\n+test01()\n+{\n+  std::flat_set<int, std::less<int>, Sequence<int>> m;\n+  static_assert( std::ranges::random_access_range<decltype(m)> );\n+\n+  m.insert(1);\n+  m.insert(2);\n+  m.insert(3);\n+  m.insert(1);\n+  m.insert(2);\n+  m.insert(3);\n+  m.insert(0);\n+  VERIFY( m.size() == 4 );\n+  VERIFY( std::ranges::equal(m, (int[]){0, 1, 2, 3}) );\n+\n+  for (int i = 0; i < 4; i++)\n+    {\n+      m.clear();\n+      m.insert(m.end(), (i + 0) % 4);\n+      m.insert(m.end(), (i + 1) % 4);\n+      m.insert(m.end(), (i + 2) % 4);\n+      m.insert(m.end(), (i + 3) % 4);\n+      m.insert(m.begin() + i, 1);\n+      m.insert(m.begin() + i, 2);\n+      m.insert(m.begin() + i, 3);\n+      m.insert(m.begin() + i, 0);\n+      VERIFY( std::ranges::equal(m, (int[]){0, 1, 2, 3}) );\n+    }\n+\n+  m.clear();\n+  m = {10,10};\n+  VERIFY( m.size() == 1 );\n+  m.insert({11, 12, 11});\n+  VERIFY( m.size() == 3 );\n+  VERIFY( m.end()[-1] == 12 );\n+\n+  auto m_copy = m;\n+  VERIFY( m_copy == m );\n+  m_copy.operator=({12, 11, 10});\n+  VERIFY( m_copy == m );\n+}\n+\n+void\n+test02()\n+{\n+  std::flat_set<int, std::greater<int>> m;\n+  static_assert( std::ranges::random_access_range<decltype(m)> );\n+\n+  auto r = m.insert(1);\n+  VERIFY( *r.first == 1 && r.second );\n+  r = m.insert(2);\n+  VERIFY( *r.first == 2 && r.second );\n+  r = m.insert(3);\n+  VERIFY( *r.first == 3 && r.second );\n+  r = m.insert(1);\n+  VERIFY( *r.first == 1 && !r.second );\n+  r = m.insert(2);\n+  VERIFY( *r.first == 2 && !r.second );\n+  r = m.insert(3);\n+  VERIFY( *r.first == 3 && !r.second );\n+  m.insert(0);\n+  VERIFY( m.size() == 4 );\n+  VERIFY( std::ranges::equal(m, (int[]){3, 2, 1, 0}) );\n+\n+  VERIFY( m.contains(3) && !m.contains(7) );\n+  VERIFY( m.count(3) == 1 );\n+}\n+\n+void\n+test03()\n+{\n+  std::flat_set<int> m;\n+  m = {1, 3, 5};\n+  m.insert({7, 9});\n+\n+  auto it = m.find(0);\n+  VERIFY( it == m.end() );\n+  it = m.find(9);\n+  VERIFY( it == m.end()-1 );\n+\n+  const auto n = m;\n+  VERIFY( m == m );\n+  VERIFY( m == n );\n+\n+  m.erase(m.begin());\n+  m.erase(5);\n+  m.erase(m.end()-2, m.end());\n+  VERIFY( std::ranges::equal(m, (int[]){3}) );\n+  VERIFY( m != n );\n+  VERIFY( n < m );\n+\n+  m = n;\n+  erase_if(m, [](const auto& k) { return k < 5 || k > 5; });\n+  VERIFY( std::ranges::equal(m, (int[]){5}) );\n+}\n+\n+void\n+test04()\n+{\n+  using vector = std::vector<int, __gnu_test::uneq_allocator<int>>;\n+  vector v = {1, 2, 3};\n+  __gnu_test::uneq_allocator<int> alloc(42);\n+\n+  using flat_set = std::flat_set<int, std::less<int>, vector>;\n+  flat_set m1(alloc);\n+  VERIFY( std::move(m1).extract().get_allocator().get_personality() == 42 );\n+\n+  flat_set m2(v, alloc);\n+  VERIFY( std::move(m2).extract().get_allocator().get_personality() == 42 );\n+\n+  flat_set m3(std::sorted_unique_t{}, v, alloc);\n+  VERIFY( std::move(m3).extract().get_allocator().get_personality() == 42 );\n+\n+  alloc = __gnu_test::uneq_allocator<int>(43);\n+  flat_set m4(m3, alloc);\n+  VERIFY( std::move(m4).extract().get_allocator().get_personality() == 43 );\n+\n+  alloc = __gnu_test::uneq_allocator<int>(44);\n+  flat_set m5(std::move(m4), alloc);\n+  VERIFY( std::move(m5).extract().get_allocator().get_personality() == 44 );\n+}\n+\n+int\n+main()\n+{\n+  test01<std::vector>();\n+  test01<std::deque>();\n+  test02();\n+  test03();\n+  test04();\n+}\n","prefixes":["v1","3/3"]}