Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmultimedia_ranges_p.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QMULTIMEDIA_RANGES_P_H
5#define QMULTIMEDIA_RANGES_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qtconfigmacros.h>
19
20#ifdef __cpp_lib_ranges
21# include <ranges> // IWYU pragma: export
22#endif
23
24#include <algorithm>
25#include <functional>
26#include <utility>
27
28QT_BEGIN_NAMESPACE
29
31
32#ifdef __cpp_lib_ranges
33
35
36using std::ranges::all_of;
37using std::ranges::any_of;
38using std::ranges::copy;
39using std::ranges::equal;
40using std::ranges::equal_range;
41using std::ranges::fill;
42using std::ranges::find;
43using std::ranges::find_if;
44using std::ranges::for_each;
45using std::ranges::lower_bound;
46using std::ranges::max;
47using std::ranges::max_element;
48using std::ranges::min;
49using std::ranges::min_element;
50using std::ranges::none_of;
51using std::ranges::sort;
52using std::ranges::stable_sort;
53using std::ranges::transform;
54using std::ranges::upper_bound;
55
56#else
57
58template <typename R>
59using range_iterator_t = decltype(std::begin(std::declval<R &>()));
60
61template <typename It>
62using iter_value_t = typename std::iterator_traits<It>::value_type;
63
64template <typename R>
66
67// Caveat: best effort, not a 1-to-1 mapping to c++20 style ranges
68
69inline constexpr auto all_of = [](auto &&range, auto predicate) {
70 return std::all_of(std::begin(range), std::end(range), std::move(predicate));
71};
72
73inline constexpr auto any_of = [](auto &&range, auto predicate) {
74 return std::any_of(std::begin(range), std::end(range), std::move(predicate));
75};
76
77inline constexpr auto none_of = [](auto &&range, auto predicate) {
78 return std::none_of(std::begin(range), std::end(range), std::move(predicate));
79};
80
81inline constexpr auto for_each = [](auto &&range, auto func) {
82 return std::for_each(std::begin(range), std::end(range), std::move(func));
83};
84
85inline constexpr auto copy = [](auto &&in, auto out) {
86 return std::copy(std::begin(in), std::end(in), std::move(out));
87};
88
89inline constexpr auto fill = [](auto &&range, const auto &value) {
90 return std::fill(std::begin(range), std::end(range), value);
91};
92
93inline constexpr auto find = [](auto &&range, const auto &value) {
94 return std::find(std::begin(range), std::end(range), value);
95};
96
97inline constexpr auto find_if = [](auto &&range, auto predicate) {
98 return std::find_if(std::begin(range), std::end(range), std::move(predicate));
99};
100
101template <typename Iterator>
103{
104 Iterator m_begin;
105 Iterator m_end;
106 constexpr Iterator begin() const { return m_begin; }
107 constexpr Iterator end() const { return m_end; }
108};
109
110namespace impl {
111
113{
114 template <typename Range, typename T, typename Comp = std::less<>>
115 auto operator()(Range &&range, const T &value, Comp comp = {}) const
116 {
117 return std::lower_bound(std::begin(range), std::end(range), value, std::move(comp));
118 }
119};
120
122{
123 template <typename Range, typename T, typename Comp = std::less<>>
124 auto operator()(Range &&range, const T &value, Comp comp = {}) const
125 {
126 return std::upper_bound(std::begin(range), std::end(range), value, std::move(comp));
127 }
128};
129
131{
132 template <typename Range, typename T, typename Comp = std::less<>>
133 auto operator()(Range &&range, const T &value, Comp comp = {}) const
134 {
135 auto [b, e] = std::equal_range(std::begin(range), std::end(range), value, std::move(comp));
136 return subrange<decltype(b)>{ b, e };
137 }
138};
139
140struct max_fn
141{
142 template <typename Range, typename Comp = std::less<>>
143 auto operator()(Range &&range, Comp comp) const
144 {
145 auto it = std::max_element(std::begin(range), std::end(range), std::move(comp));
146 return *it;
147 }
148
149 template <typename Range>
150 auto operator()(Range &&range) const
151 {
152 auto it = std::max_element(std::begin(range), std::end(range));
153 return *it;
154 }
155};
156
158{
159 template <typename Range, typename Comp = std::less<>>
160 auto operator()(Range &&range, Comp comp) const
161 {
162 return std::max_element(std::begin(range), std::end(range), std::move(comp));
163 }
164
165 template <typename Range>
166 auto operator()(Range &&range) const
167 {
168 return std::max_element(std::begin(range), std::end(range));
169 }
170};
171
172struct min_fn
173{
174 template <typename Range, typename Comp = std::less<>>
175 auto operator()(Range &&range, Comp comp) const
176 {
177 auto it = std::min_element(std::begin(range), std::end(range), std::move(comp));
178 return *it;
179 }
180
181 template <typename Range>
182 auto operator()(Range &&range) const
183 {
184 auto it = std::min_element(std::begin(range), std::end(range));
185 return *it;
186 }
187};
188
190{
191 template <typename Range, typename Comp = std::less<>>
192 auto operator()(Range &&range, Comp comp) const
193 {
194 return std::min_element(std::begin(range), std::end(range), std::move(comp));
195 }
196
197 template <typename Range>
198 auto operator()(Range &&range) const
199 {
200 return std::min_element(std::begin(range), std::end(range));
201 }
202};
203
205{
206 template <typename Range, typename Comp = std::less<>>
207 void operator()(Range &&range, Comp comp) const
208 {
209 std::sort(std::begin(range), std::end(range), std::move(comp));
210 }
211
212 template <typename Range>
213 void operator()(Range &&range) const
214 {
215 std::sort(std::begin(range), std::end(range));
216 }
217};
218
220{
221 template <typename Range, typename Comp = std::less<>>
222 void operator()(Range &&range, Comp comp) const
223 {
224 std::stable_sort(std::begin(range), std::end(range), std::move(comp));
225 }
226
227 template <typename Range>
228 void operator()(Range &&range) const
229 {
230 std::stable_sort(std::begin(range), std::end(range));
231 }
232};
233
235{
236 template <typename Range1, typename Range2, typename Pred = std::equal_to<>>
237 bool operator()(Range1 &&lhs, Range2 &&rhs, Pred pred = {}) const
238 {
239 return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs),
240 std::move(pred));
241 }
242};
243
244} // namespace impl
245
246inline constexpr auto equal = impl::equal_fn{};
247inline constexpr auto lower_bound = impl::lower_bound_fn{};
248inline constexpr auto upper_bound = impl::upper_bound_fn{};
249inline constexpr auto equal_range = impl::equal_range_fn{};
250inline constexpr auto sort = impl::sort_fn{};
251inline constexpr auto stable_sort = impl::stable_sort_fn{};
252inline constexpr auto max = impl::max_fn{};
253inline constexpr auto max_element = impl::max_element_fn{};
254inline constexpr auto min = impl::min_fn{};
255inline constexpr auto min_element = impl::min_element_fn{};
256inline constexpr auto transform = [](auto &&range, auto output, auto op) {
257 return std::transform(std::begin(range), std::end(range), std::move(output),
258 [op = std::move(op)](const auto &x) {
259 return std::invoke(op, x);
260 });
261};
262
263#endif
264
265#if __cpp_lib_ranges_contains >= 202207L
266using std::ranges::contains;
267#else
268
269inline constexpr auto contains = [](auto &&range, const auto &value) {
270 return std::find(std::begin(range), std::end(range), value) != std::end(range);
271};
272
273#endif
274
275#if __cpp_lib_ranges_to_container >= 202202L
276using std::ranges::to;
277#else
278
279namespace impl {
280
281template <typename Container>
283{
284};
285
286template <typename Container, typename Range>
287Container operator|(Range &&range, to_adaptor<Container>)
288{
289 return Container(std::begin(range), std::end(range));
290}
291
292template <template <class...> class Container>
296
297template <template <class...> class Container, class Range>
299{
300 return Container<ranges::range_value_t<Range>>(std::begin(range), std::end(range));
301}
302
303} // namespace impl
304
305template <typename Container, typename Range>
306Container to(Range &&range)
307{
308 return Container(std::begin(range), std::end(range));
309}
310
311template <typename Container>
312impl::to_adaptor<Container> to()
313{
314 return {};
315}
316
317template <template <class...> class Container>
318auto to()
319{
320 return impl::to_adaptor_template_template<Container>{};
321}
322#endif
323
324} // namespace QtMultimediaPrivate::ranges
325
327
328#ifdef __cpp_lib_ranges
329using std::views::filter;
330using std::views::keys;
331using std::views::transform;
332using std::views::values;
333#else
334
335namespace impl {
336
337template <typename Range>
339{
340 using BaseIt = decltype(std::begin(std::declval<Range &>()));
341
342 class iterator
343 {
344 BaseIt m_it;
345
346 public:
347 using iterator_category = std::input_iterator_tag;
348 using value_type =
349 std::remove_cv_t<std::remove_reference_t<decltype((*std::declval<BaseIt>()).first)>>;
350 using difference_type = std::ptrdiff_t;
351 using pointer = const value_type *;
352 using reference = decltype((*std::declval<BaseIt>()).first);
353
354 constexpr explicit iterator(BaseIt it) : m_it(std::move(it)) { }
355 constexpr reference operator*() const { return (*m_it).first; }
356 constexpr iterator &operator++() { ++m_it; return *this; }
357 constexpr bool operator==(const iterator &o) const { return m_it == o.m_it; }
358 constexpr bool operator!=(const iterator &o) const { return m_it != o.m_it; }
359 };
360
361 Range &m_range;
362
363public:
364 constexpr explicit KeysView(Range &range) : m_range(range) { }
365 constexpr iterator begin() const { return iterator{ std::begin(m_range) }; }
366 constexpr iterator end() const { return iterator{ std::end(m_range) }; }
367};
368
369template <typename Range>
371{
372 using BaseIt = decltype(std::begin(std::declval<Range &>()));
373
374 class iterator
375 {
376 BaseIt m_it;
377
378 public:
379 using iterator_category = std::input_iterator_tag;
380 using value_type =
381 std::remove_cv_t<std::remove_reference_t<decltype((*std::declval<BaseIt>()).second)>>;
382 using difference_type = std::ptrdiff_t;
383 using pointer = const value_type *;
384 using reference = decltype((*std::declval<BaseIt>()).second);
385
386 constexpr explicit iterator(BaseIt it) : m_it(std::move(it)) { }
387 constexpr reference operator*() const { return (*m_it).second; }
388 constexpr iterator &operator++() { ++m_it; return *this; }
389 constexpr bool operator==(const iterator &o) const { return m_it == o.m_it; }
390 constexpr bool operator!=(const iterator &o) const { return m_it != o.m_it; }
391 };
392
393 Range &m_range;
394
395public:
396 constexpr explicit ValuesView(Range &range) : m_range(range) { }
397 constexpr iterator begin() const { return iterator{ std::begin(m_range) }; }
398 constexpr iterator end() const { return iterator{ std::end(m_range) }; }
399};
400
401struct keys_tag { };
402struct values_tag { };
403
404template <typename Range>
405constexpr KeysView<const Range> operator|(const Range &range, keys_tag) { return KeysView<const Range>{ range }; }
406
407template <typename Range>
408constexpr ValuesView<const Range> operator|(const Range &range, values_tag) { return ValuesView<const Range>{ range }; }
409
410template <typename Container, typename Predicate>
412{
413 using BaseIt = decltype(std::begin(std::declval<Container &>()));
414
415 class iterator
416 {
417 BaseIt m_it;
418 BaseIt m_end;
419 Predicate m_pred;
420
421 constexpr void advance()
422 {
423 while (m_it != m_end && !m_pred(*m_it))
424 ++m_it;
425 }
426
427 public:
428 using iterator_category = std::input_iterator_tag;
429 using value_type = std::remove_cv_t<std::remove_reference_t<decltype(*std::declval<BaseIt>())>>;
430 using difference_type = std::ptrdiff_t;
431 using pointer = const value_type *;
432 using reference = decltype(*std::declval<BaseIt>());
433
434 constexpr iterator(BaseIt it, BaseIt end, Predicate pred)
435 : m_it(std::move(it)), m_end(std::move(end)), m_pred(std::move(pred))
436 {
437 advance();
438 }
439
440 constexpr auto operator*() const -> decltype(*m_it) { return *m_it; }
441
442 constexpr iterator &operator++()
443 {
444 ++m_it;
445 advance();
446 return *this;
447 }
448
449 constexpr bool operator==(const iterator &other) const { return m_it == other.m_it; }
450 constexpr bool operator!=(const iterator &other) const { return m_it != other.m_it; }
451 };
452
453 Container &m_container;
454 Predicate m_pred;
455
456public:
457 constexpr FilterView(Container &container, Predicate pred)
458 : m_container(container), m_pred(std::move(pred))
459 {
460 }
461
462 constexpr iterator begin() const
463 {
464 return iterator{
465 std::begin(m_container),
466 std::end(m_container),
467 m_pred,
468 };
469 }
470
471 constexpr iterator end() const
472 {
473 return iterator{
474 std::end(m_container),
475 std::end(m_container),
476 m_pred,
477 };
478 }
479};
480
481template <typename Predicate>
483{
484 Predicate pred;
485};
486
487// operator| is in impl so ADL finds it via the FilterAdaptor type
488// Takes const Container& to allow binding both lvalues and rvalues (chained FilterViews).
489// The resulting FilterView stores a const ref, valid for the lifetime of the full expression.
490template <typename Container, typename Predicate>
491constexpr auto operator|(const Container &container, FilterAdaptor<Predicate> adaptor)
492{
493 return FilterView<const Container, Predicate>(container, std::move(adaptor.pred));
494}
495
496template <typename Range, typename Transform>
498{
499 using BaseIt = decltype(std::begin(std::declval<Range &>()));
500
501 class iterator
502 {
503 BaseIt m_it;
504 Transform m_transform;
505
506 public:
507 using value_type = std::remove_cv_t<std::remove_reference_t<
508 decltype(std::invoke(std::declval<Transform>(), *std::declval<BaseIt>()))>>;
509 using reference = value_type;
510 using pointer = void;
511 using difference_type = std::ptrdiff_t;
512 using iterator_category = std::input_iterator_tag;
513
514 constexpr iterator(BaseIt it, Transform transform)
515 : m_it(std::move(it)), m_transform(std::move(transform))
516 {
517 }
518
519 constexpr value_type operator*() const { return std::invoke(m_transform, *m_it); }
520 constexpr iterator &operator++() { ++m_it; return *this; }
521 constexpr bool operator==(const iterator &other) const { return m_it == other.m_it; }
522 constexpr bool operator!=(const iterator &other) const { return m_it != other.m_it; }
523 };
524
525 Range &m_range;
526 Transform m_transform;
527
528public:
529 constexpr TransformView(Range &range, Transform transform)
530 : m_range(range), m_transform(std::move(transform))
531 {
532 }
533
534 constexpr iterator begin() const { return iterator{ std::begin(m_range), m_transform }; }
535 constexpr iterator end() const { return iterator{ std::end(m_range), m_transform }; }
536};
537
538template <typename Transform>
540{
541 Transform transform;
542};
543
544template <typename Container, typename Transform>
545constexpr auto operator|(const Container &container, TransformAdaptor<Transform> adaptor)
546{
547 return TransformView<const Container, Transform>(container, std::move(adaptor.transform));
548}
549
550} // namespace impl
551
552template <typename Container, typename Predicate>
553constexpr auto filter(const Container &container, Predicate pred)
554{
555 return impl::FilterView<const Container, Predicate>(container, std::move(pred));
556}
557
558template <typename Predicate>
559constexpr auto filter(Predicate pred)
560{
561 return impl::FilterAdaptor<Predicate>{ std::move(pred) };
562}
563
564template <typename Container, typename Transform>
565constexpr auto transform(const Container &container, Transform t)
566{
567 return impl::TransformView<const Container, Transform>(container, std::move(t));
568}
569
570template <typename Transform>
571constexpr auto transform(Transform t)
572{
573 return impl::TransformAdaptor<Transform>{ std::move(t) };
574}
575
576inline constexpr impl::keys_tag keys{};
577inline constexpr impl::values_tag values{};
578
579#endif
580
581} // namespace QtMultimediaPrivate::views
582
583QT_END_NAMESPACE
584
585#endif // QMULTIMEDIA_RANGES_P_H
constexpr FilterView(Container &container, Predicate pred)
constexpr TransformView(Range &range, Transform transform)
Container operator|(Range &&range, to_adaptor< Container >)
auto operator|(Range &&range, to_adaptor_template_template< Container >)
typename std::iterator_traits< It >::value_type iter_value_t
impl::to_adaptor< Container > to()
decltype(std::begin(std::declval< R & >())) range_iterator_t
Container to(Range &&range)
constexpr KeysView< const Range > operator|(const Range &range, keys_tag)
constexpr auto operator|(const Container &container, TransformAdaptor< Transform > adaptor)
constexpr ValuesView< const Range > operator|(const Range &range, values_tag)
constexpr auto operator|(const Container &container, FilterAdaptor< Predicate > adaptor)
constexpr impl::values_tag values
constexpr impl::keys_tag keys
constexpr auto filter(Predicate pred)
constexpr auto transform(Transform t)
constexpr auto filter(const Container &container, Predicate pred)
constexpr auto transform(const Container &container, Transform t)
bool operator()(Range1 &&lhs, Range2 &&rhs, Pred pred={}) const
auto operator()(Range &&range, const T &value, Comp comp={}) const
auto operator()(Range &&range, const T &value, Comp comp={}) const
auto operator()(Range &&range, Comp comp) const
auto operator()(Range &&range, Comp comp) const
auto operator()(Range &&range, Comp comp) const
auto operator()(Range &&range, Comp comp) const
void operator()(Range &&range, Comp comp) const
void operator()(Range &&range, Comp comp) const
auto operator()(Range &&range, const T &value, Comp comp={}) const