• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CORE_FXCRT_ZIP_H_
6 #define CORE_FXCRT_ZIP_H_
7 
8 #include <stdint.h>
9 
10 #include <tuple>
11 #include <utility>
12 
13 #include "core/fxcrt/check_op.h"
14 #include "core/fxcrt/compiler_specific.h"
15 #include "core/fxcrt/span.h"
16 
17 namespace fxcrt {
18 
19 // Vastly simplified implementation of ideas from C++23 zip_view<>. Allows
20 // safe traversal of two or three ranges with a single bounds check per
21 // iteration.
22 
23 // Example two range usage:
24 //   struct RGB { uint8_t r; uint8_t g; uint8_t b; };
25 //   const uint8_t gray[256] = { ... };
26 //   RGB rgbs[260];
27 //   for (auto [in, out] : Zip(gray, rgbs)) {
28 //     out.r = in;
29 //     out.g = in;
30 //     out.b = in;
31 //   }
32 // which fills the first 256 elements of rgbs with the corresponding gray
33 // value in each component, say.
34 
35 // Differences include:
36 // - Only zips together two or three views instead of N.
37 // - Size is determined by the first view, which must be smaller than the
38 //   other view(s).
39 // - With two views, the first view is presumed to be "input-like" and is const,
40 //   second view is presumed to be "output-like" and is non-const.
41 // - With three views, the first two views are presumed to be "input-like" and
42 //   are const.
43 // - Only those methods required to support use in a range-based for-loop
44 //   are provided.
45 
46 template <typename T, typename U>
47 class ZipView2 {
48  public:
49   struct Iter {
50     bool operator==(const Iter& that) const { return first == that.first; }
51 
52     bool operator!=(const Iter& that) const { return first != that.first; }
53 
54     UNSAFE_BUFFER_USAGE Iter& operator++() {
55       // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE.
56       UNSAFE_BUFFERS(++first);
57       UNSAFE_BUFFERS(++second);
58       return *this;
59     }
60 
61     std::pair<typename T::reference, typename U::reference> operator*() const {
62       return {*first, *second};
63     }
64 
65     typename T::iterator first;
66     typename U::iterator second;
67   };
68 
ZipView2(T first,U second)69   ZipView2(T first, U second) : first_(first), second_(second) {
70     CHECK_LE(first.size(), second.size());
71   }
72 
begin()73   Iter begin() { return {first_.begin(), second_.begin()}; }
end()74   Iter end() { return {first_.end(), second_.end()}; }
75 
76  private:
77   T first_;
78   U second_;
79 };
80 
81 // Same as `ZipView2`, but with 2 inputs and 1 output.
82 template <typename T, typename U, typename V>
83 class ZipView3 {
84  public:
85   struct Iter {
86     bool operator==(const Iter& that) const { return first == that.first; }
87 
88     bool operator!=(const Iter& that) const { return first != that.first; }
89 
90     UNSAFE_BUFFER_USAGE Iter& operator++() {
91       // SAFETY: required from caller, enforced by UNSAFE_BUFFER_USAGE.
92       UNSAFE_BUFFERS(++first);
93       UNSAFE_BUFFERS(++second);
94       UNSAFE_BUFFERS(++third);
95       return *this;
96     }
97 
98     std::tuple<typename T::reference,
99                typename U::reference,
100                typename V::reference>
101     operator*() const {
102       return {*first, *second, *third};
103     }
104 
105     typename T::iterator first;
106     typename U::iterator second;
107     typename V::iterator third;
108   };
109 
ZipView3(T first,U second,V third)110   ZipView3(T first, U second, V third)
111       : first_(first), second_(second), third_(third) {
112     CHECK_LE(first.size(), second.size());
113     CHECK_LE(first.size(), third.size());
114   }
115 
begin()116   Iter begin() { return {first_.begin(), second_.begin(), third_.begin()}; }
end()117   Iter end() { return {first_.end(), second_.end(), third_.end()}; }
118 
119  private:
120   T first_;
121   U second_;
122   V third_;
123 };
124 
125 template <typename T, typename U>
Zip(const T & first,U && second)126 auto Zip(const T& first, U&& second) {
127   return ZipView2(pdfium::span(first), pdfium::span(second));
128 }
129 
130 template <typename T, typename U, typename V>
Zip(const T & first,const U & second,V && third)131 auto Zip(const T& first, const U& second, V&& third) {
132   return ZipView3(pdfium::span(first), pdfium::span(second),
133                   pdfium::span(third));
134 }
135 
136 }  // namespace fxcrt
137 
138 #endif  // CORE_FXCRT_ZIP_H_
139