Skip to content

Commit 0387c2f

Browse files
bashtanovStephanDollberg
authored andcommitted
chunked_hash_{map,set}: from-range utility functions for set and hetero
Implement from-range table creation tables for 1) chunked_hash_set 2) chunked_hash_{map,set} with custom hash and eq callables Drop const and volatile specifiers when guessing map type from a range of pairs: these may come from std::map or alike, with const keys. Constrain templates to accept only appropriate range types.
1 parent e48604e commit 0387c2f

2 files changed

Lines changed: 79 additions & 25 deletions

File tree

include/seastar/core/chunked_hash_map.hh

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -91,27 +91,6 @@ using chunked_hash_map = ankerl::unordered_dense::segmented_map<
9191
ankerl::unordered_dense::bucket_type::standard,
9292
chunked_vector<ankerl::unordered_dense::bucket_type::standard>>;
9393

94-
namespace internal {
95-
template<typename Range>
96-
struct chunked_hash_map_from_range_impl {
97-
using value_t = std::ranges::range_value_t<std::decay_t<Range>>;
98-
using first_t = typename value_t::first_type;
99-
using second_t = typename value_t::second_type;
100-
using ret_t = chunked_hash_map<first_t, second_t>;
101-
};
102-
} // namespace internal
103-
104-
// reserves if range size is known
105-
template<typename Range>
106-
typename internal::chunked_hash_map_from_range_impl<Range>::ret_t
107-
chunked_hash_map_from_range(Range&& range) {
108-
size_t size = 0;
109-
if constexpr (std::ranges::sized_range<Range>) {
110-
size = std::ranges::size(range);
111-
}
112-
return {std::ranges::begin(range), std::ranges::end(range), size};
113-
};
114-
11594
/**
11695
* @brief A set counterpart of chunked_hash_map (uses a chunked vector as the
11796
* underlying storage).
@@ -131,6 +110,44 @@ using chunked_hash_set = ankerl::unordered_dense::segmented_set<
131110
ankerl::unordered_dense::bucket_type::standard,
132111
chunked_vector<ankerl::unordered_dense::bucket_type::standard>>;
133112

113+
namespace internal {
114+
template<typename Range>
115+
struct chunked_hash_map_from_range_impl {
116+
using value_t = std::ranges::range_value_t<std::decay_t<Range>>;
117+
using first_t = typename value_t::first_type;
118+
using second_t = typename value_t::second_type;
119+
using ret_t = chunked_hash_map<std::remove_cv_t<first_t>, second_t>;
120+
};
121+
} // namespace internal
122+
123+
// reserves if range size is known
124+
template<typename TargetTable, typename Range>
125+
requires std::ranges::input_range<Range>
126+
&& std::convertible_to<std::ranges::range_reference_t<Range>, typename TargetTable::value_type>
127+
TargetTable chunked_table_from_range(Range&& range) {
128+
size_t size = 0;
129+
if constexpr (std::ranges::sized_range<Range>) {
130+
size = std::ranges::size(range);
131+
}
132+
return {std::ranges::begin(range), std::ranges::end(range), size};
133+
}
134+
135+
// reserves if range size is known
136+
template<std::ranges::input_range Range>
137+
auto chunked_hash_map_from_range(Range&& range) {
138+
return chunked_table_from_range<
139+
typename internal::chunked_hash_map_from_range_impl<Range>::ret_t>(
140+
std::forward<Range>(range));
141+
}
142+
143+
// reserves if range size is known
144+
template<std::ranges::input_range Range>
145+
auto chunked_hash_set_from_range(Range&& range) {
146+
return chunked_table_from_range<
147+
chunked_hash_set<std::ranges::range_value_t<std::decay_t<Range>>>>(
148+
std::forward<Range>(range));
149+
}
150+
134151
/// Returns a lower bound on the memory currently being held by `m`.
135152
template<
136153
typename K,

tests/unit/chunked_hash_map_test.cc

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Copyright 2024 Redpanda Data, Inc.
2020
*/
2121

22+
#include <seastar/core/sstring.hh>
2223
#define BOOST_TEST_MODULE chunked_hash_map
2324

2425
#include <seastar/core/chunked_hash_map.hh>
@@ -28,11 +29,15 @@
2829
#include <array>
2930
#include <list>
3031
#include <string>
32+
#include <string_view>
3133
#include <utility>
3234
#include <vector>
3335

3436
using seastar::chunked_hash_map;
37+
using seastar::chunked_hash_set;
3538
using seastar::chunked_hash_map_from_range;
39+
using seastar::chunked_hash_set_from_range;
40+
using seastar::chunked_table_from_range;
3641

3742
struct foo_with_std_hash {
3843
int a;
@@ -82,14 +87,14 @@ BOOST_AUTO_TEST_CASE(test_move_assignment) {
8287
other_map = std::move(map);
8388
}
8489

85-
BOOST_AUTO_TEST_CASE(from_range_vector) {
90+
BOOST_AUTO_TEST_CASE(map_from_range_vector) {
8691
std::vector<std::pair<int, int>> input{{1, 10}, {2, 20}, {3, 30}};
8792
auto map = chunked_hash_map_from_range(input);
8893
chunked_hash_map<int, int> expected{{1, 10}, {2, 20}, {3, 30}};
8994
BOOST_REQUIRE(map == expected);
9095
}
9196

92-
BOOST_AUTO_TEST_CASE(from_range_list) {
97+
BOOST_AUTO_TEST_CASE(map_from_range_list) {
9398
std::list<std::pair<std::string, int>> input{
9499
{"one", 1}, {"two", 2}, {"three", 3}};
95100
auto map = chunked_hash_map_from_range(input);
@@ -98,9 +103,41 @@ BOOST_AUTO_TEST_CASE(from_range_list) {
98103
BOOST_REQUIRE(map == expected);
99104
}
100105

101-
BOOST_AUTO_TEST_CASE(from_range_array) {
102-
std::array<std::pair<int, std::string>, 2> input{{{1, "one"}, {2, "two"}}};
106+
BOOST_AUTO_TEST_CASE(map_from_range_list_hetero) {
107+
using hetero_map_t = chunked_hash_map<
108+
std::string,
109+
int,
110+
ankerl::unordered_dense::hash<std::string_view>,
111+
std::equal_to<std::string_view>>;
112+
std::list<std::pair<seastar::sstring, int>> input{
113+
{"one", 1}, {"two", 2}, {"three", 3}};
114+
auto map = chunked_table_from_range<hetero_map_t>(input);
115+
hetero_map_t expected{
116+
{"one", 1}, {"two", 2}, {"three", 3}};
117+
BOOST_REQUIRE(map == expected);
118+
}
119+
120+
BOOST_AUTO_TEST_CASE(map_from_range_array) {
121+
std::array<std::pair<const int, std::string>, 2> input{{{1, "one"}, {2, "two"}}};
103122
auto map = chunked_hash_map_from_range(input);
104123
chunked_hash_map<int, std::string> expected{{1, "one"}, {2, "two"}};
105124
BOOST_REQUIRE(map == expected);
106125
}
126+
127+
BOOST_AUTO_TEST_CASE(set_from_range_vector) {
128+
std::vector<std::string> input{"foo", "bar", "baz"};
129+
auto set = chunked_hash_set_from_range(input);
130+
chunked_hash_set<std::string> expected{"foo", "bar", "baz"};
131+
BOOST_REQUIRE(set == expected);
132+
}
133+
134+
BOOST_AUTO_TEST_CASE(set_from_range_vector_hetero) {
135+
using hetero_set_t = chunked_hash_set<
136+
std::string,
137+
ankerl::unordered_dense::hash<std::string_view>,
138+
std::equal_to<std::string_view>>;
139+
std::vector<seastar::sstring> input{"foo", "bar", "baz"};
140+
auto set = chunked_table_from_range<hetero_set_t>(input);
141+
hetero_set_t expected{"foo", "bar", "baz"};
142+
BOOST_REQUIRE(set == expected);
143+
}

0 commit comments

Comments
 (0)