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