[libc++] Replace stable_sort with sort in flat_map (#121431)

Fixes #120788
This commit is contained in:
Hui
2025-01-13 14:09:29 +00:00
committed by GitHub
parent 2a551ab300
commit 162397f98d
5 changed files with 5 additions and 202 deletions

View File

@@ -17,7 +17,7 @@
#include <__algorithm/ranges_inplace_merge.h>
#include <__algorithm/ranges_lower_bound.h>
#include <__algorithm/ranges_partition_point.h>
#include <__algorithm/ranges_stable_sort.h>
#include <__algorithm/ranges_sort.h>
#include <__algorithm/ranges_unique.h>
#include <__algorithm/ranges_upper_bound.h>
#include <__algorithm/remove_if.h>
@@ -853,9 +853,7 @@ private:
// is no invariant state to preserve
_LIBCPP_HIDE_FROM_ABI void __sort_and_unique() {
auto __zv = ranges::views::zip(__containers_.keys, __containers_.values);
// To be consistent with std::map's behaviour, we use stable_sort instead of sort.
// As a result, if there are duplicated keys, the first value in the original order will be taken.
ranges::stable_sort(__zv, __compare_, [](const auto& __p) -> decltype(auto) { return std::get<0>(__p); });
ranges::sort(__zv, __compare_, [](const auto& __p) -> decltype(auto) { return std::get<0>(__p); });
auto __dup_start = ranges::unique(__zv, __key_equiv(__compare_)).begin();
auto __dist = ranges::distance(__zv.begin(), __dup_start);
__containers_.keys.erase(__containers_.keys.begin() + __dist, __containers_.keys.end());
@@ -886,7 +884,7 @@ private:
return __compare_(std::get<0>(__p1), std::get<0>(__p2));
};
if constexpr (!_WasSorted) {
ranges::stable_sort(__zv.begin() + __append_start_offset, __end, __compare_key);
ranges::sort(__zv.begin() + __append_start_offset, __end, __compare_key);
} else {
_LIBCPP_ASSERT_SEMANTIC_REQUIREMENT(
__is_sorted_and_unique(__containers_.keys | ranges::views::drop(__append_start_offset)),

View File

@@ -760,6 +760,8 @@ module std [system] {
module ranges_sort {
header "__algorithm/ranges_sort.h"
export std.functional.ranges_operations
export std.algorithm.sort
export std.algorithm.make_projected
}
module ranges_stable_partition {
header "__algorithm/ranges_stable_partition.h"

View File

@@ -1,68 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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_map>
// flat_map(key_container_type key_cont, mapped_container_type mapped_cont);
//
// libc++ uses stable_sort to ensure that flat_map's behavior matches map's,
// in terms of which duplicate items are kept.
// This tests a conforming extension.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <flat_map>
#include <random>
#include <map>
#include <vector>
#include "test_macros.h"
struct Mod256 {
bool operator()(int x, int y) const { return (x % 256) < (y % 256); }
};
int main(int, char**) {
std::mt19937 randomness;
std::vector<uint16_t> values;
std::vector<std::pair<uint16_t, uint16_t>> pairs;
for (int i = 0; i < 200; ++i) {
uint16_t r = randomness();
values.push_back(r);
pairs.emplace_back(r, r);
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs.begin(), pairs.end());
std::flat_map<uint16_t, uint16_t, Mod256> fm(values, values);
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs.begin(), pairs.end());
std::flat_map<uint16_t, uint16_t, Mod256> fm(values, values, Mod256());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs.begin(), pairs.end());
std::flat_map<uint16_t, uint16_t, Mod256> fm(values, values, std::allocator<int>());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs.begin(), pairs.end());
std::flat_map<uint16_t, uint16_t, Mod256> fm(values, values, Mod256(), std::allocator<int>());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
return 0;
}

View File

@@ -1,66 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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_map>
// template<class InputIterator>
// flat_map(InputIterator first, InputIterator last, const key_compare& comp = key_compare())
//
// libc++ uses stable_sort to ensure that flat_map's behavior matches map's,
// in terms of which duplicate items are kept.
// This tests a conforming extension.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <flat_map>
#include <random>
#include <map>
#include <vector>
#include "test_macros.h"
struct Mod256 {
bool operator()(int x, int y) const { return (x % 256) < (y % 256); }
};
int main(int, char**) {
std::mt19937 randomness;
std::pair<uint16_t, uint16_t> pairs[200];
for (auto& pair : pairs) {
pair = {uint16_t(randomness()), uint16_t(randomness())};
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs, pairs + 200);
std::flat_map<uint16_t, uint16_t, Mod256> fm(pairs, pairs + 200);
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs, pairs + 200, std::allocator<int>());
std::flat_map<uint16_t, uint16_t, Mod256> fm(pairs, pairs + 200, std::allocator<int>());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs, pairs + 200, Mod256());
std::flat_map<uint16_t, uint16_t, Mod256> fm(pairs, pairs + 200, Mod256());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::map<uint16_t, uint16_t, Mod256> m(pairs, pairs + 200, Mod256(), std::allocator<int>());
std::flat_map<uint16_t, uint16_t, Mod256> fm(pairs, pairs + 200, Mod256(), std::allocator<int>());
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
return 0;
}

View File

@@ -1,63 +0,0 @@
//===----------------------------------------------------------------------===//
//
// 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_map>
// template<container-compatible-range<value_type> R>
// void insert_range(R&& rg);
//
// libc++ uses stable_sort to ensure that flat_map's behavior matches map's,
// in terms of which duplicate items are kept.
// This tests a conforming extension.
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <flat_map>
#include <random>
#include <ranges>
#include <map>
#include <vector>
#include <utility>
#include "test_macros.h"
struct Mod256 {
bool operator()(int x, int y) const { return (x % 256) < (y % 256); }
};
int main(int, char**) {
{
std::mt19937 randomness;
std::pair<uint16_t, uint16_t> pairs[400];
for (int i = 0; i < 400; ++i) {
uint16_t r = randomness();
pairs[i] = {r, r};
}
std::map<uint16_t, uint16_t, Mod256> m(pairs, pairs + 200);
std::flat_map<uint16_t, uint16_t, Mod256> fm(std::sorted_unique, m.begin(), m.end());
assert(std::ranges::equal(fm, m));
fm.insert_range(std::views::counted(pairs + 200, 200));
m.insert(pairs + 200, pairs + 400);
assert(fm.size() == m.size());
LIBCPP_ASSERT(std::ranges::equal(fm, m));
}
{
std::vector<std::pair<int, int>> v{{1, 2}, {1, 3}};
std::flat_map<int, int> m;
m.insert_range(v);
assert(m.size() == 1);
LIBCPP_ASSERT(m[1] == 2);
}
return 0;
}