On Wed, May 27, 2026 at 3:06 PM Patrick Palka <[email protected]> wrote:

> Ever since r16-1742 ranges::inplace_merge is now correctly C++20 iterator
> aware which allows us to idiomatically implement this helper with the
> correct optimal complexity N + M log M instead of N log N.
>
> libstdc++-v3/ChangeLog:
>
>         * include/std/flat_map (_Flat_map_impl::_M_insert): New bool
>         parameter __is_sorted default to false.  Reimplement using
>         views::zip and ranges::inplace_merge.
>         (_Flat_map_impl::insert): In the __sorted_t overload, pass
>         __is_sorted=true to _M_insert.
> ---
>  libstdc++-v3/include/std/flat_map | 32 +++++++++----------------------
>  1 file changed, 9 insertions(+), 23 deletions(-)
>
This one LGTM.

>
> diff --git a/libstdc++-v3/include/std/flat_map
> b/libstdc++-v3/include/std/flat_map
> index 18f06e6bdaf8..a51c6625d54a 100644
> --- a/libstdc++-v3/include/std/flat_map
> +++ b/libstdc++-v3/include/std/flat_map
> @@ -602,13 +602,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>        template<typename _Iter, typename _Sent>
>         _GLIBCXX26_CONSTEXPR
>         void
> -       _M_insert(_Iter __first, _Sent __last)
> +       _M_insert(_Iter __first, _Sent __last, bool __is_sorted = false)
>         {
> -         // FIXME: This implementation fails its complexity requirements.
> -         // We can't idiomatically implement an efficient version (as in
> the
> -         // disabled code) until ranges::inplace_merge is fixed to
> dispatch
> -         // on iterator concept instead of iterator category.
> -#if 0
>           auto __guard = _M_make_clear_guard();
>           auto __n = size();
>           for (; __first != __last; ++__first)
> @@ -618,22 +613,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>               _M_cont.values.emplace_back(std::move(__value.second));
>             }
>           auto __zv = views::zip(_M_cont.keys, _M_cont.values);
> -         ranges::sort(__zv.begin() + __n, __zv.end(), value_comp());
> -         ranges::inplace_merge(__zv.begin(), __zv.begin() + __n,
> __zv.end(), value_comp());
> +         if (__is_sorted)
> +           _GLIBCXX_DEBUG_ASSERT(ranges::is_sorted(__zv.begin() + __n,
> __zv.end(),
> +                                                   value_comp()));
> +         else
> +           ranges::sort(__zv.begin() + __n, __zv.end(), value_comp());
> +         ranges::inplace_merge(__zv.begin(), __zv.begin() + __n,
> __zv.end(),
> +                               value_comp());
>           if constexpr (!_Multi)
>             _M_unique();
> -         __guard._M_cont = nullptr;
> -#else
> -         auto __guard = _M_make_clear_guard();
> -         for (; __first != __last; ++__first)
> -           {
> -             value_type __value = *__first;
> -             _M_cont.keys.emplace_back(std::move(__value.first));
> -             _M_cont.values.emplace_back(std::move(__value.second));
> -           }
> -         _M_sort_uniq();
>           __guard._M_disable();
> -#endif
>         }
>
>      public:
> @@ -647,10 +636,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         _GLIBCXX26_CONSTEXPR
>         void
>         insert(__sorted_t, _InputIterator __first, _InputIterator __last)
> -       {
> -         // FIXME: This implementation fails its complexity requirements;
> see above.
> -         insert(std::move(__first), std::move(__last));
> -       }
> +       { _M_insert(std::move(__first), std::move(__last), true); }
>
>        template<__detail::__container_compatible_range<value_type> _Rg>
>         _GLIBCXX26_CONSTEXPR
> --
> 2.54.0.rc1.54.g60f07c4f5c
>
>

Reply via email to