Skip to content

Commit 303ad72

Browse files
committed
review comments
1 parent 94747e5 commit 303ad72

File tree

7 files changed

+118
-62
lines changed

7 files changed

+118
-62
lines changed

libcxx/include/__flat_map/key_value_iterator.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <__iterator/product_iterator.h>
1919
#include <__memory/addressof.h>
2020
#include <__type_traits/conditional.h>
21+
#include <__utility/forward.h>
2122
#include <__utility/move.h>
2223
#include <__utility/pair.h>
2324

@@ -175,17 +176,22 @@ template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const
175176
struct __product_iterator_traits<__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, _Const>> {
176177
static constexpr size_t __size = 2;
177178

178-
template <size_t _Nth>
179-
_LIBCPP_HIDE_FROM_ABI static auto
180-
__get_iterator_element(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, _Const> __it)
179+
template <size_t _Nth, class _Iter>
180+
_LIBCPP_HIDE_FROM_ABI static decltype(auto) __get_iterator_element(_Iter&& __it)
181181
requires(_Nth <= 1)
182182
{
183183
if constexpr (_Nth == 0) {
184-
return __it.__key_iter_;
184+
return std::forward<_Iter>(__it).__key_iter_;
185185
} else {
186-
return __it.__mapped_iter_;
186+
return std::forward<_Iter>(__it).__mapped_iter_;
187187
}
188188
}
189+
190+
template <class _KeyIter, class _MappedIter>
191+
_LIBCPP_HIDE_FROM_ABI static auto __make_product_iterator(_KeyIter&& __key_iter, _MappedIter&& __mapped_iter) {
192+
return __key_value_iterator<_Owner, _KeyContainer, _MappedContainer, _Const>(
193+
std::forward<_KeyIter>(__key_iter), std::forward<_MappedIter>(__mapped_iter));
194+
}
189195
};
190196

191197
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__flat_map/utils.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,6 @@ struct __flat_map_utils {
8080
return typename _Map::iterator(std::move(__key_it), std::move(__mapped_it));
8181
}
8282

83-
// TODO: We could optimize this, see
84-
// https://github.com/llvm/llvm-project/issues/108624
8583
template <class _Map, class _InputIterator, class _Sentinel>
8684
_LIBCPP_HIDE_FROM_ABI static typename _Map::size_type
8785
__append(_Map& __map, _InputIterator __first, _Sentinel __last) {

libcxx/include/__iterator/product_iterator.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
// The number of underlying iterators inside the product iterator.
2222
//
2323
// - template <size_t _N>
24-
// static auto Traits::__get_iterator_element(It __it)
24+
// static decltype(auto) Traits::__get_iterator_element(It&& __it)
2525
// Returns the _Nth iterator element of the given product iterator.
2626

2727
#include <__config>
@@ -42,8 +42,11 @@ struct __product_iterator_traits;
4242
{
4343
static constexpr size_t __size = ...;
4444
45-
template <size_t _N>
46-
static auto __get_iterator_element(_Iterator);
45+
template <size_t _N, class _Iter>
46+
static decltype(auto) __get_iterator_element(_Iter&&);
47+
48+
template <class... _Iters>
49+
static _Iterator __make_product_iterator(_Iters&&...);
4750
};
4851
*/
4952

libcxx/include/__ranges/zip_view.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -473,15 +473,20 @@ inline constexpr auto zip = __zip::__fn{};
473473
} // namespace views
474474
} // namespace ranges
475475

476-
template <class _Iter>
477-
requires _Iter::__is_zip_view_iterator::value
478-
struct __product_iterator_traits<_Iter> {
479-
static constexpr size_t __size = tuple_size<decltype(std::declval<_Iter>().__current_)>::value;
476+
template <class _Iterator>
477+
requires _Iterator::__is_zip_view_iterator
478+
struct __product_iterator_traits<_Iterator> {
479+
static constexpr size_t __size = tuple_size<decltype(std::declval<_Iterator>().__current_)>::value;
480480

481-
template <size_t _Nth>
481+
template <size_t _Nth, class _Iter>
482482
requires(_Nth < __size)
483-
_LIBCPP_HIDE_FROM_ABI static constexpr auto __get_iterator_element(_Iter __it) {
484-
return std::get<_Nth>(__it.__current_);
483+
_LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_iterator_element(_Iter&& __it) {
484+
return std::get<_Nth>(std::forward<_Iter>(__it).__current_);
485+
}
486+
487+
template <class... _Iters>
488+
_LIBCPP_HIDE_FROM_ABI static constexpr _Iterator __make_product_iterator(_Iters&&... __iters) {
489+
return _Iterator(std::tuple(std::forward<_Iters>(__iters)...));
485490
}
486491
};
487492

libcxx/test/benchmarks/containers/associative/associative_container_benchmarks.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ void associative_container_benchmarks(std::string container) {
6666

6767
static constexpr bool is_ordered_container = requires(Container c, Key k) { c.lower_bound(k); };
6868

69+
static constexpr bool is_map_like = requires { typename Container::mapped_type; };
70+
6971
// These benchmarks are structured to perform the operation being benchmarked
7072
// a small number of times at each iteration, in order to offset the cost of
7173
// PauseTiming() and ResumeTiming().
@@ -321,6 +323,47 @@ void associative_container_benchmarks(std::string container) {
321323
}
322324
});
323325

326+
if constexpr (is_map_like) {
327+
bench("insert(iterator, iterator) (product_iterator from same type)", [=](auto& st) {
328+
const std::size_t size = st.range(0);
329+
std::vector<Value> in = make_value_types(generate_unique_keys(size + (size / 10)));
330+
std::sort(in.begin(), in.end(), [&](const auto& x, const auto& y) { return get_key(x) < get_key(y); });
331+
Container source(in.begin(), in.end());
332+
333+
Container c;
334+
335+
for ([[maybe_unused]] auto _ : st) {
336+
c.insert(source.begin(), source.end());
337+
benchmark::DoNotOptimize(c);
338+
benchmark::ClobberMemory();
339+
340+
st.PauseTiming();
341+
c = Container();
342+
st.ResumeTiming();
343+
}
344+
});
345+
346+
bench("insert(iterator, iterator) (product_iterator from zip_view)", [=](auto& st) {
347+
const std::size_t size = st.range(0);
348+
std::vector<Key> keys = generate_unique_keys(size + (size / 10));
349+
std::sort(keys.begin(), keys.end());
350+
std::vector<typename Container::mapped_type> mapped(keys.size());
351+
352+
auto source = std::views::zip(keys, mapped);
353+
354+
Container c;
355+
356+
for ([[maybe_unused]] auto _ : st) {
357+
c.insert(source.begin(), source.end());
358+
benchmark::DoNotOptimize(c);
359+
benchmark::ClobberMemory();
360+
361+
st.PauseTiming();
362+
c = Container();
363+
st.ResumeTiming();
364+
}
365+
});
366+
}
324367
/////////////////////////
325368
// Erasure
326369
/////////////////////////

libcxx/test/benchmarks/containers/associative/flat_map.bench.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,54 +27,9 @@ struct support::adapt_operations<std::flat_map<K, V>> {
2727
static auto get_iterator(InsertionResult const& result) { return result.first; }
2828
};
2929

30-
void product_iterator_benchmark_flat_map(benchmark::State& state) {
31-
const std::size_t size = state.range(0);
32-
33-
using M = std::flat_map<int, int>;
34-
35-
const M source =
36-
std::views::iota(0, static_cast<int>(size)) | std::views::transform([](int i) { return std::pair(i, i); }) |
37-
std::ranges::to<std::flat_map<int, int>>();
38-
39-
for (auto _ : state) {
40-
M m;
41-
m.insert(std::sorted_unique, source.begin(), source.end());
42-
benchmark::DoNotOptimize(m);
43-
benchmark::ClobberMemory();
44-
}
45-
}
46-
47-
void product_iterator_benchmark_zip_view(benchmark::State& state) {
48-
const std::size_t size = state.range(0);
49-
50-
using M = std::flat_map<int, int>;
51-
52-
const std::vector<int> keys = std::views::iota(0, static_cast<int>(size)) | std::ranges::to<std::vector<int>>();
53-
const std::vector<int> values = keys;
54-
55-
auto source = std::views::zip(keys, values);
56-
for (auto _ : state) {
57-
M m;
58-
m.insert(std::sorted_unique, source.begin(), source.end());
59-
benchmark::DoNotOptimize(m);
60-
benchmark::ClobberMemory();
61-
}
62-
}
63-
6430
int main(int argc, char** argv) {
6531
support::associative_container_benchmarks<std::flat_map<int, int>>("std::flat_map<int, int>");
6632

67-
benchmark::RegisterBenchmark("flat_map::insert_product_iterator_flat_map", product_iterator_benchmark_flat_map)
68-
->Arg(32)
69-
->Arg(1024)
70-
->Arg(8192)
71-
->Arg(65536);
72-
benchmark::RegisterBenchmark("flat_map::insert_product_iterator_zip", product_iterator_benchmark_zip_view)
73-
->Arg(32)
74-
->Arg(1024)
75-
->Arg(8192)
76-
->Arg(65536);
77-
7833
benchmark::Initialize(&argc, argv);
7934
benchmark::RunSpecifiedBenchmarks();
8035
benchmark::Shutdown();
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
#include <ranges>
12+
#include <type_traits>
13+
14+
#include "test_macros.h"
15+
#include "test_iterators.h"
16+
17+
constexpr bool test() {
18+
{
19+
// Test that the __get_iterator_element can handle a non-copyable iterator
20+
int Date[] = {1, 2, 3, 4};
21+
cpp20_input_iterator<int*> iter(Date);
22+
sentinel_wrapper<cpp20_input_iterator<int*>> sent{cpp20_input_iterator<int*>(Date + 4)};
23+
std::ranges::subrange r1(std::move(iter), std::move(sent));
24+
auto v = std::views::zip(std::move(r1), std::views::iota(0, 4));
25+
auto it = v.begin();
26+
27+
using Iter = decltype(it);
28+
29+
static_assert(!std::is_copy_constructible_v<Iter>);
30+
31+
static_assert(std::__product_iterator_traits<Iter>::__size == 2);
32+
std::same_as<cpp20_input_iterator<int*>&> decltype(auto) it1 =
33+
std::__product_iterator_traits<Iter>::__get_iterator_element<0>(it);
34+
35+
assert(*it1 == 1);
36+
}
37+
38+
return true;
39+
}
40+
41+
int main(int, char**) {
42+
test();
43+
static_assert(test());
44+
45+
return 0;
46+
}

0 commit comments

Comments
 (0)