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#include <QtMultimedia/private/qiteratorfacade_p.h>
21
22#ifdef __cpp_lib_ranges
23# include <ranges> // IWYU pragma: export
24#endif
25
26#include <algorithm>
27#include <functional>
28#include <type_traits>
29#include <utility>
30
31QT_BEGIN_NAMESPACE
32
34
35// note: libstdc++ 11 has incomplete support for ranges (missing owning_view, P2415)
36#if defined(__cpp_lib_ranges) && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 12)
37
39
40using std::ranges::subrange;
41
42using std::ranges::all_of;
43using std::ranges::any_of;
44using std::ranges::copy;
45using std::ranges::equal;
46using std::ranges::equal_range;
47using std::ranges::fill;
48using std::ranges::find;
49using std::ranges::find_if;
50using std::ranges::for_each;
51using std::ranges::lower_bound;
52using std::ranges::max;
53using std::ranges::max_element;
54using std::ranges::min;
55using std::ranges::min_element;
56using std::ranges::none_of;
57using std::ranges::sort;
58using std::ranges::stable_sort;
59using std::ranges::transform;
60using std::ranges::upper_bound;
61
62#else
63
64template <typename R>
65using range_iterator_t = decltype(std::begin(std::declval<R &>()));
66
67template <typename It>
68using iter_value_t = typename std::iterator_traits<It>::value_type;
69
70template <typename R>
72
73// Caveat: best effort, not a 1-to-1 mapping to c++20 style ranges
74
75inline constexpr auto all_of = [](auto &&range, auto predicate) {
76 return std::all_of(std::begin(range), std::end(range), std::move(predicate));
77};
78
79inline constexpr auto any_of = [](auto &&range, auto predicate) {
80 return std::any_of(std::begin(range), std::end(range), std::move(predicate));
81};
82
83inline constexpr auto none_of = [](auto &&range, auto predicate) {
84 return std::none_of(std::begin(range), std::end(range), std::move(predicate));
85};
86
87inline constexpr auto for_each = [](auto &&range, auto func) {
88 return std::for_each(std::begin(range), std::end(range), std::move(func));
89};
90
91inline constexpr auto copy = [](auto &&in, auto out) {
92 return std::copy(std::begin(in), std::end(in), std::move(out));
93};
94
95inline constexpr auto fill = [](auto &&range, const auto &value) {
96 return std::fill(std::begin(range), std::end(range), value);
97};
98
99inline constexpr auto find = [](auto &&range, const auto &value) {
100 return std::find(std::begin(range), std::end(range), value);
101};
102
103inline constexpr auto find_if = [](auto &&range, auto predicate) {
104 return std::find_if(std::begin(range), std::end(range), std::move(predicate));
105};
106
107template <typename Iterator>
109{
110 Iterator m_begin;
111 Iterator m_end;
112 constexpr Iterator begin() const { return m_begin; }
113 constexpr Iterator end() const { return m_end; }
114};
115
116namespace impl {
117
119{
120 template <typename Range, typename T, typename Comp = std::less<>>
121 auto operator()(Range &&range, const T &value, Comp comp = {}) const
122 {
123 return std::lower_bound(std::begin(range), std::end(range), value, std::move(comp));
124 }
125};
126
128{
129 template <typename Range, typename T, typename Comp = std::less<>>
130 auto operator()(Range &&range, const T &value, Comp comp = {}) const
131 {
132 return std::upper_bound(std::begin(range), std::end(range), value, std::move(comp));
133 }
134};
135
137{
138 template <typename Range, typename T, typename Comp = std::less<>>
139 auto operator()(Range &&range, const T &value, Comp comp = {}) const
140 {
141 auto [b, e] = std::equal_range(std::begin(range), std::end(range), value, std::move(comp));
142 return subrange<decltype(b)>{ b, e };
143 }
144};
145
146struct max_fn
147{
148 template <typename Range, typename Comp = std::less<>>
149 auto operator()(Range &&range, Comp comp) const
150 {
151 auto it = std::max_element(std::begin(range), std::end(range), std::move(comp));
152 return *it;
153 }
154
155 template <typename Range>
156 auto operator()(Range &&range) const
157 {
158 auto it = std::max_element(std::begin(range), std::end(range));
159 return *it;
160 }
161};
162
164{
165 template <typename Range, typename Comp = std::less<>>
166 auto operator()(Range &&range, Comp comp) const
167 {
168 return std::max_element(std::begin(range), std::end(range), std::move(comp));
169 }
170
171 template <typename Range>
172 auto operator()(Range &&range) const
173 {
174 return std::max_element(std::begin(range), std::end(range));
175 }
176};
177
178struct min_fn
179{
180 template <typename Range, typename Comp = std::less<>>
181 auto operator()(Range &&range, Comp comp) const
182 {
183 auto it = std::min_element(std::begin(range), std::end(range), std::move(comp));
184 return *it;
185 }
186
187 template <typename Range>
188 auto operator()(Range &&range) const
189 {
190 auto it = std::min_element(std::begin(range), std::end(range));
191 return *it;
192 }
193};
194
196{
197 template <typename Range, typename Comp = std::less<>>
198 auto operator()(Range &&range, Comp comp) const
199 {
200 return std::min_element(std::begin(range), std::end(range), std::move(comp));
201 }
202
203 template <typename Range>
204 auto operator()(Range &&range) const
205 {
206 return std::min_element(std::begin(range), std::end(range));
207 }
208};
209
211{
212 template <typename Range, typename Comp = std::less<>>
213 void operator()(Range &&range, Comp comp) const
214 {
215 std::sort(std::begin(range), std::end(range), std::move(comp));
216 }
217
218 template <typename Range>
219 void operator()(Range &&range) const
220 {
221 std::sort(std::begin(range), std::end(range));
222 }
223};
224
226{
227 template <typename Range, typename Comp = std::less<>>
228 void operator()(Range &&range, Comp comp) const
229 {
230 std::stable_sort(std::begin(range), std::end(range), std::move(comp));
231 }
232
233 template <typename Range>
234 void operator()(Range &&range) const
235 {
236 std::stable_sort(std::begin(range), std::end(range));
237 }
238};
239
241{
242 template <typename Range1, typename Range2, typename Pred = std::equal_to<>>
243 bool operator()(Range1 &&lhs, Range2 &&rhs, Pred pred = {}) const
244 {
245 return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs),
246 std::move(pred));
247 }
248};
249
250} // namespace impl
251
252inline constexpr auto equal = impl::equal_fn{};
253inline constexpr auto lower_bound = impl::lower_bound_fn{};
254inline constexpr auto upper_bound = impl::upper_bound_fn{};
255inline constexpr auto equal_range = impl::equal_range_fn{};
256inline constexpr auto sort = impl::sort_fn{};
257inline constexpr auto stable_sort = impl::stable_sort_fn{};
258inline constexpr auto max = impl::max_fn{};
259inline constexpr auto max_element = impl::max_element_fn{};
260inline constexpr auto min = impl::min_fn{};
261inline constexpr auto min_element = impl::min_element_fn{};
262inline constexpr auto transform = [](auto &&range, auto output, auto op) {
263 return std::transform(std::begin(range), std::end(range), std::move(output),
264 [op = std::move(op)](const auto &x) {
265 return std::invoke(op, x);
266 });
267};
268
269#endif
270
271#if __cpp_lib_ranges_contains >= 202207L
272using std::ranges::contains;
273#else
274
275inline constexpr auto contains = [](auto &&range, const auto &value) {
276 return std::find(std::begin(range), std::end(range), value) != std::end(range);
277};
278
279#endif
280
281#if __cpp_lib_ranges_to_container >= 202202L
282using std::ranges::to;
283#else
284
285namespace impl {
286
287template <typename Container>
289{
290};
291
292template <typename Container, typename Range>
293Container operator|(Range &&range, to_adaptor<Container>)
294{
295 return Container(std::begin(range), std::end(range));
296}
297
298template <template <class...> class Container>
302
303template <template <class...> class Container, class Range>
305{
306 return Container<ranges::range_value_t<Range>>(std::begin(range), std::end(range));
307}
308
309} // namespace impl
310
311template <typename Container, typename Range>
312Container to(Range &&range)
313{
314 return Container(std::begin(range), std::end(range));
315}
316
317template <typename Container>
318impl::to_adaptor<Container> to()
319{
320 return {};
321}
322
323template <template <class...> class Container>
324auto to()
325{
326 return impl::to_adaptor_template_template<Container>{};
327}
328#endif
329
330} // namespace QtMultimediaPrivate::ranges
331
333
334// note: libstdc++ 11 has incomplete support for ranges (missing owning_view, P2415)
335#if defined(__cpp_lib_ranges) && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 12)
336using std::views::filter;
337using std::views::keys;
338using std::views::transform;
339using std::views::values;
340#else
341
342namespace impl {
343
344template <typename Range>
346{
347 using BaseIt = decltype(std::begin(std::declval<Range &>()));
348 using KeyReference = decltype((*std::declval<BaseIt>()).first);
350
351 class iterator
352 : public IteratorFacade<iterator, KeyValue, std::input_iterator_tag, KeyReference>
353 {
354 BaseIt m_it;
355
356 public:
357 constexpr explicit iterator(BaseIt it) : m_it(std::move(it)) { }
358
359 using reference = KeyReference;
360 constexpr reference dereference() const { return (*m_it).first; }
361 constexpr void increment() { ++m_it; }
362 constexpr bool equals(const iterator &o) const { return m_it == o.m_it; }
363 };
364
365 Range &m_range;
366
367public:
368 constexpr explicit KeysView(Range &range) : m_range(range) { }
369 constexpr iterator begin() const { return iterator{ std::begin(m_range) }; }
370 constexpr iterator end() const { return iterator{ std::end(m_range) }; }
371};
372
373template <typename Range>
375{
376 using BaseIt = decltype(std::begin(std::declval<Range &>()));
377 using ValueReference = decltype((*std::declval<BaseIt>()).second);
379
380 class iterator
381 : public IteratorFacade<iterator, MappedValue, std::input_iterator_tag, ValueReference>
382 {
383 BaseIt m_it;
384
385 public:
386 constexpr explicit iterator(BaseIt it) : m_it(std::move(it)) { }
387
388 using reference = ValueReference;
389 constexpr reference dereference() const { return (*m_it).second; }
390 constexpr void increment() { ++m_it; }
391 constexpr bool equals(const iterator &o) const { return m_it == o.m_it; }
392 };
393
394 Range &m_range;
395
396public:
397 constexpr explicit ValuesView(Range &range) : m_range(range) { }
398 constexpr iterator begin() const { return iterator{ std::begin(m_range) }; }
399 constexpr iterator end() const { return iterator{ std::end(m_range) }; }
400};
401
402struct keys_tag { };
403struct values_tag { };
404
405template <typename Range>
406constexpr KeysView<const Range> operator|(const Range &range, keys_tag) { return KeysView<const Range>{ range }; }
407
408template <typename Range>
409constexpr ValuesView<const Range> operator|(const Range &range, values_tag) { return ValuesView<const Range>{ range }; }
410
411template <typename Container, typename Predicate>
413{
414 using BaseIt = decltype(std::begin(std::declval<Container &>()));
415 using ElementReference = decltype(*std::declval<BaseIt>());
417
418 class iterator
419 : public IteratorFacade<iterator, ElementValue, std::input_iterator_tag, ElementReference>
420 {
421 BaseIt m_it;
422 BaseIt m_end;
423 Predicate m_pred;
424
425 constexpr void advance()
426 {
427 while (m_it != m_end && !m_pred(*m_it))
428 ++m_it;
429 }
430
431 public:
432 using reference = ElementReference;
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 reference dereference() const { return *m_it; }
441 constexpr void increment()
442 {
443 ++m_it;
444 advance();
445 }
446 constexpr bool equals(const iterator &o) const { return m_it == o.m_it; };
447 };
448
449 Container &m_container;
450 Predicate m_pred;
451
452public:
453 constexpr FilterView(Container &container, Predicate pred)
454 : m_container(container), m_pred(std::move(pred))
455 {
456 }
457
458 constexpr iterator begin() const
459 {
460 return iterator{
461 std::begin(m_container),
462 std::end(m_container),
463 m_pred,
464 };
465 }
466
467 constexpr iterator end() const
468 {
469 return iterator{
470 std::end(m_container),
471 std::end(m_container),
472 m_pred,
473 };
474 }
475};
476
477template <typename Predicate>
479{
480 Predicate pred;
481};
482
483// operator| is in impl so ADL finds it via the FilterAdaptor type
484// Takes const Container& to allow binding both lvalues and rvalues (chained FilterViews).
485// The resulting FilterView stores a const ref, valid for the lifetime of the full expression.
486template <typename Container, typename Predicate>
487constexpr auto operator|(const Container &container, FilterAdaptor<Predicate> adaptor)
488{
489 return FilterView<const Container, Predicate>(container, std::move(adaptor.pred));
490}
491
492template <typename Range, typename Transform>
494{
495 using BaseIt = decltype(std::begin(std::declval<Range &>()));
497 decltype(std::invoke(std::declval<Transform>(), *std::declval<BaseIt>()))>>;
498
499 class iterator : public IteratorFacade<iterator, TransformedValue, std::input_iterator_tag,
500 TransformedValue>
501 {
502 BaseIt m_it;
503 Transform m_transform;
504
505 public:
506 using reference = TransformedValue;
507
508 constexpr iterator(BaseIt it, Transform transform)
509 : m_it(std::move(it)), m_transform(std::move(transform))
510 {
511 }
512
513 constexpr reference dereference() const { return std::invoke(m_transform, *m_it); }
514 constexpr void increment() { ++m_it; }
515 constexpr void decrement() { --m_it; }
516 constexpr bool equals(const iterator &o) const { return m_it == o.m_it; }
517 };
518
519 Range &m_range;
520 Transform m_transform;
521
522public:
523 constexpr TransformView(Range &range, Transform transform)
524 : m_range(range), m_transform(std::move(transform))
525 {
526 }
527
528 constexpr iterator begin() const { return iterator{ std::begin(m_range), m_transform }; }
529 constexpr iterator end() const { return iterator{ std::end(m_range), m_transform }; }
530};
531
532template <typename Transform>
534{
535 Transform transform;
536};
537
538template <typename Container, typename Transform>
539constexpr auto operator|(const Container &container, TransformAdaptor<Transform> adaptor)
540{
541 return TransformView<const Container, Transform>(container, std::move(adaptor.transform));
542}
543
544} // namespace impl
545
546template <typename Container, typename Predicate>
547constexpr auto filter(const Container &container, Predicate pred)
548{
549 return impl::FilterView<const Container, Predicate>(container, std::move(pred));
550}
551
552template <typename Predicate>
553constexpr auto filter(Predicate pred)
554{
555 return impl::FilterAdaptor<Predicate>{ std::move(pred) };
556}
557
558template <typename Container, typename Transform>
559constexpr auto transform(const Container &container, Transform t)
560{
561 return impl::TransformView<const Container, Transform>(container, std::move(t));
562}
563
564template <typename Transform>
565constexpr auto transform(Transform t)
566{
567 return impl::TransformAdaptor<Transform>{ std::move(t) };
568}
569
570inline constexpr impl::keys_tag keys{};
571inline constexpr impl::values_tag values{};
572
573#endif
574
575#if __cpp_lib_ranges_stride >= 202207L
576using std::views::stride;
577#else
578
579namespace impl {
580
582{
583 std::ptrdiff_t n;
584};
585
586// Minimal stand-in for std::ranges::ref_view — lets StrideView store an lvalue container by
587// reference without copying it, matching how std::views::all/std::ranges::ref_view behave.
588template <typename Range>
590{
591 Range &m_range;
592
593public:
594 constexpr explicit ref_view(Range &range) : m_range(range) { }
595
596 constexpr auto begin() const { return std::begin(m_range); }
597 constexpr auto end() const { return std::end(m_range); }
598 constexpr auto data() const { return std::data(m_range); }
599 constexpr auto size() const { return std::size(m_range); }
600 constexpr bool empty() const { return std::empty(m_range); }
601};
602
603template <typename Range>
605{
606 using BaseIt = decltype(std::begin(std::declval<const Range &>()));
607 using StrideReference = decltype(*std::declval<BaseIt>());
609
610 class iterator
611 : public IteratorFacade<iterator, StrideValue, std::input_iterator_tag, StrideReference>
612 {
613 BaseIt m_it;
614 BaseIt m_end;
615 std::ptrdiff_t m_stride;
616
617 public:
618 using reference = StrideReference;
619
620 constexpr iterator(BaseIt it, BaseIt end, std::ptrdiff_t stride)
621 : m_it(std::move(it)), m_end(std::move(end)), m_stride(stride)
622 {
623 }
624
625 constexpr reference dereference() const { return *m_it; }
626
627 constexpr void increment()
628 {
629 for (std::ptrdiff_t i = 0; i < m_stride && m_it != m_end; ++i)
630 ++m_it;
631 }
632
633 constexpr bool equals(const iterator &o) const { return m_it == o.m_it; }
634 };
635
636 Range m_range;
637 std::ptrdiff_t m_n;
638
639public:
640 constexpr StrideView(Range range, std::ptrdiff_t n) : m_range(std::move(range)), m_n(n) { }
641
642 constexpr iterator begin() const { return { std::begin(m_range), std::end(m_range), m_n }; }
643 constexpr iterator end() const { return { std::end(m_range), std::end(m_range), m_n }; }
644
645 constexpr std::ptrdiff_t size() const
646 {
647 const std::ptrdiff_t total = std::ptrdiff_t(std::size(m_range));
648 return (total + m_n - 1) / m_n;
649 }
650 constexpr bool empty() const { return std::empty(m_range); }
651
652 constexpr auto operator[](std::ptrdiff_t n) const
653 -> decltype(*std::begin(std::declval<const Range &>()))
654 {
655 return *(std::begin(m_range) + n * m_n);
656 }
657};
658
659// Mirrors std::views::all(): an lvalue container is wrapped in a ref_view (pointer only, no
660// copy); an rvalue (a view like QSpan, or another view produced earlier in a pipe chain) is
661// moved into the StrideView directly, since it is already cheap to own.
662template <typename Range>
663constexpr auto make_stride_view(Range &&range, std::ptrdiff_t n)
664{
665 if constexpr (std::is_lvalue_reference_v<Range>) {
666 using Container = std::remove_reference_t<Range>;
667 return StrideView<ref_view<Container>>{ ref_view<Container>{ range }, n };
668 } else {
669 return StrideView<Range>{ std::move(range), n };
670 }
671}
672
673// operator| is in impl so ADL finds it via the StrideAdaptor type
674template <typename Range>
675constexpr auto operator|(Range &&range, StrideAdaptor adaptor)
676{
677 return make_stride_view(std::forward<Range>(range), adaptor.n);
678}
679
680} // namespace impl
681
682template <typename Range>
683constexpr auto stride(Range &&range, std::ptrdiff_t n)
684{
685 return impl::make_stride_view(std::forward<Range>(range), n);
686}
687constexpr auto stride(std::ptrdiff_t n)
688{
689 return impl::StrideAdaptor{ n };
690}
691
692#endif
693
694inline constexpr auto filter_nonnull = views::filter([](const auto &arg) {
695 return bool(arg);
696});
697
698} // namespace QtMultimediaPrivate::views
699
700QT_END_NAMESPACE
701
702#endif // QMULTIMEDIA_RANGES_P_H
constexpr FilterView(Container &container, Predicate pred)
constexpr StrideView(Range range, std::ptrdiff_t n)
constexpr auto operator[](std::ptrdiff_t n) const -> decltype(*std::begin(std::declval< const Range & >()))
constexpr TransformView(Range &range, Transform transform)
Combined button and popup list for selecting options.
std::optional< qsizetype > findAdtsSync(QSpan< const std::byte > data, qsizetype from)
std::optional< OggStreamInfo > oggStreamInfo(QSpan< const std::byte > data)
std::optional< qsizetype > findFlacSync(QSpan< const std::byte > data, qsizetype from)
AudioCodec sniffCodec(QSpan< const std::byte > header)
std::optional< qsizetype > findMpegSync(QSpan< const std::byte > data, qsizetype from)
qsizetype adtsFrameSize(QSpan< const std::byte > data, qsizetype offset)
std::optional< FlacStreamInfo > flacStreamInfo(QSpan< const std::byte > data)
std::optional< qsizetype > flacAudioOffset(QSpan< const std::byte > data)
qsizetype mpegFrameSize(QSpan< const std::byte > data, qsizetype offset)
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|(Range &&range, StrideAdaptor adaptor)
constexpr auto operator|(const Container &container, FilterAdaptor< Predicate > adaptor)
constexpr auto make_stride_view(Range &&range, std::ptrdiff_t n)
constexpr auto stride(std::ptrdiff_t n)
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)
constexpr auto stride(Range &&range, std::ptrdiff_t n)
QSpan< U > take(QSpan< U, E > span, qsizetype n)
QSpan< U > drop(QSpan< U, E > span, qsizetype n)
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