1 #ifndef PROTOZERO_ITERATORS_HPP
2 #define PROTOZERO_ITERATORS_HPP
3 
4 /*****************************************************************************
5 
6 protozero - Minimalistic protocol buffer decoder and encoder in C++.
7 
8 This file is from https://github.com/mapbox/protozero where you can find more
9 documentation.
10 
11 *****************************************************************************/
12 
13 /**
14  * @file iterators.hpp
15  *
16  * @brief Contains the iterators for access to packed repeated fields.
17  */
18 
19 #include <cstring>
20 #include <iterator>
21 #include <utility>
22 
23 #include <protozero/config.hpp>
24 #include <protozero/varint.hpp>
25 
26 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
27 # include <protozero/byteswap.hpp>
28 #endif
29 
30 namespace protozero {
31 
32 /**
33  * A range of iterators based on std::pair. Created from beginning and
34  * end iterators. Used as a return type from some pbf_reader methods
35  * that is easy to use with range-based for loops.
36  */
37 template <typename T, typename P = std::pair<T, T>>
38 class iterator_range :
39 #ifdef PROTOZERO_STRICT_API
40     protected
41 #else
42     public
43 #endif
44         P {
45 
46 public:
47 
48     /// The type of the iterators in this range.
49     using iterator = T;
50 
51     /// The value type of the underlying iterator.
52     using value_type = typename std::iterator_traits<T>::value_type;
53 
54     /**
55      * Default constructor. Create empty iterator_range.
56      */
iterator_range()57     constexpr iterator_range() :
58         P(iterator{}, iterator{}) {
59     }
60 
61     /**
62      * Create iterator range from two iterators.
63      *
64      * @param first_iterator Iterator to beginning or range.
65      * @param last_iterator Iterator to end or range.
66      */
iterator_range(iterator && first_iterator,iterator && last_iterator)67     constexpr iterator_range(iterator&& first_iterator, iterator&& last_iterator) :
68         P(std::forward<iterator>(first_iterator),
69           std::forward<iterator>(last_iterator)) {
70     }
71 
72     /// Return iterator to beginning of range.
begin() const73     constexpr iterator begin() const noexcept {
74         return this->first;
75     }
76 
77     /// Return iterator to end of range.
end() const78     constexpr iterator end() const noexcept {
79         return this->second;
80     }
81 
82     /// Return iterator to beginning of range.
cbegin() const83     constexpr iterator cbegin() const noexcept {
84         return this->first;
85     }
86 
87     /// Return iterator to end of range.
cend() const88     constexpr iterator cend() const noexcept {
89         return this->second;
90     }
91 
92     /// Return true if this range is empty.
empty() const93     constexpr std::size_t empty() const noexcept {
94         return begin() == end();
95     }
96 
97     /**
98      * Get element at the beginning of the range.
99      *
100      * @pre Range must not be empty.
101      */
front() const102     value_type front() const {
103         protozero_assert(!empty());
104         return *(this->first);
105     }
106 
107     /**
108      * Advance beginning of range by one.
109      *
110      * @pre Range must not be empty.
111      */
drop_front()112     void drop_front() {
113         protozero_assert(!empty());
114         ++this->first;
115     }
116 
117     /**
118      * Swap the contents of this range with the other.
119      *
120      * @param other Other range to swap data with.
121      */
swap(iterator_range & other)122     void swap(iterator_range& other) noexcept {
123         using std::swap;
124         swap(this->first, other.first);
125         swap(this->second, other.second);
126     }
127 
128 }; // struct iterator_range
129 
130 /**
131  * Swap two iterator_ranges.
132  *
133  * @param lhs First range.
134  * @param rhs Second range.
135  */
136 template <typename T>
swap(iterator_range<T> & lhs,iterator_range<T> & rhs)137 inline void swap(iterator_range<T>& lhs, iterator_range<T>& rhs) noexcept {
138     lhs.swap(rhs);
139 }
140 
141 /**
142  * A forward iterator used for accessing packed repeated fields of fixed
143  * length (fixed32, sfixed32, float, double).
144  */
145 template <typename T>
146 class const_fixed_iterator {
147 
148     /// Pointer to current iterator position
149     const char* m_data;
150 
151     /// Pointer to end iterator position
152     const char* m_end;
153 
154 public:
155 
156     using iterator_category = std::forward_iterator_tag;
157     using value_type        = T;
158     using difference_type   = std::ptrdiff_t;
159     using pointer           = value_type*;
160     using reference         = value_type&;
161 
const_fixed_iterator()162     const_fixed_iterator() noexcept :
163         m_data(nullptr),
164         m_end(nullptr) {
165     }
166 
const_fixed_iterator(const char * data,const char * end)167     const_fixed_iterator(const char* data, const char* end) noexcept :
168         m_data(data),
169         m_end(end) {
170     }
171 
172     const_fixed_iterator(const const_fixed_iterator&) noexcept = default;
173     const_fixed_iterator(const_fixed_iterator&&) noexcept = default;
174 
175     const_fixed_iterator& operator=(const const_fixed_iterator&) noexcept = default;
176     const_fixed_iterator& operator=(const_fixed_iterator&&) noexcept = default;
177 
178     ~const_fixed_iterator() noexcept = default;
179 
operator *() const180     value_type operator*() const {
181         value_type result;
182         std::memcpy(&result, m_data, sizeof(value_type));
183 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
184         detail::byteswap_inplace(&result);
185 #endif
186         return result;
187     }
188 
operator ++()189     const_fixed_iterator& operator++() {
190         m_data += sizeof(value_type);
191         return *this;
192     }
193 
operator ++(int)194     const_fixed_iterator operator++(int) {
195         const const_fixed_iterator tmp(*this);
196         ++(*this);
197         return tmp;
198     }
199 
operator ==(const const_fixed_iterator & rhs) const200     bool operator==(const const_fixed_iterator& rhs) const noexcept {
201         return m_data == rhs.m_data && m_end == rhs.m_end;
202     }
203 
operator !=(const const_fixed_iterator & rhs) const204     bool operator!=(const const_fixed_iterator& rhs) const noexcept {
205         return !(*this == rhs);
206     }
207 
208 }; // class const_fixed_iterator
209 
210 /**
211  * A forward iterator used for accessing packed repeated varint fields
212  * (int32, uint32, int64, uint64, bool, enum).
213  */
214 template <typename T>
215 class const_varint_iterator {
216 
217 protected:
218 
219     /// Pointer to current iterator position
220     const char* m_data;
221 
222     /// Pointer to end iterator position
223     const char* m_end;
224 
225 public:
226 
227     using iterator_category = std::forward_iterator_tag;
228     using value_type        = T;
229     using difference_type   = std::ptrdiff_t;
230     using pointer           = value_type*;
231     using reference         = value_type&;
232 
const_varint_iterator()233     const_varint_iterator() noexcept :
234         m_data(nullptr),
235         m_end(nullptr) {
236     }
237 
const_varint_iterator(const char * data,const char * end)238     const_varint_iterator(const char* data, const char* end) noexcept :
239         m_data(data),
240         m_end(end) {
241     }
242 
243     const_varint_iterator(const const_varint_iterator&) noexcept = default;
244     const_varint_iterator(const_varint_iterator&&) noexcept = default;
245 
246     const_varint_iterator& operator=(const const_varint_iterator&) noexcept = default;
247     const_varint_iterator& operator=(const_varint_iterator&&) noexcept = default;
248 
249     ~const_varint_iterator() noexcept = default;
250 
operator *() const251     value_type operator*() const {
252         const char* d = m_data; // will be thrown away
253         return static_cast<value_type>(decode_varint(&d, m_end));
254     }
255 
operator ++()256     const_varint_iterator& operator++() {
257         skip_varint(&m_data, m_end);
258         return *this;
259     }
260 
operator ++(int)261     const_varint_iterator operator++(int) {
262         const const_varint_iterator tmp(*this);
263         ++(*this);
264         return tmp;
265     }
266 
operator ==(const const_varint_iterator & rhs) const267     bool operator==(const const_varint_iterator& rhs) const noexcept {
268         return m_data == rhs.m_data && m_end == rhs.m_end;
269     }
270 
operator !=(const const_varint_iterator & rhs) const271     bool operator!=(const const_varint_iterator& rhs) const noexcept {
272         return !(*this == rhs);
273     }
274 
275 }; // class const_varint_iterator
276 
277 /**
278  * A forward iterator used for accessing packed repeated svarint fields
279  * (sint32, sint64).
280  */
281 template <typename T>
282 class const_svarint_iterator : public const_varint_iterator<T> {
283 
284 public:
285 
286     using iterator_category = std::forward_iterator_tag;
287     using value_type        = T;
288     using difference_type   = std::ptrdiff_t;
289     using pointer           = value_type*;
290     using reference         = value_type&;
291 
const_svarint_iterator()292     const_svarint_iterator() noexcept :
293         const_varint_iterator<T>() {
294     }
295 
const_svarint_iterator(const char * data,const char * end)296     const_svarint_iterator(const char* data, const char* end) noexcept :
297         const_varint_iterator<T>(data, end) {
298     }
299 
300     const_svarint_iterator(const const_svarint_iterator&) = default;
301     const_svarint_iterator(const_svarint_iterator&&) = default;
302 
303     const_svarint_iterator& operator=(const const_svarint_iterator&) = default;
304     const_svarint_iterator& operator=(const_svarint_iterator&&) = default;
305 
306     ~const_svarint_iterator() = default;
307 
operator *() const308     value_type operator*() const {
309         const char* d = this->m_data; // will be thrown away
310         return static_cast<value_type>(decode_zigzag64(decode_varint(&d, this->m_end)));
311     }
312 
operator ++()313     const_svarint_iterator& operator++() {
314         skip_varint(&this->m_data, this->m_end);
315         return *this;
316     }
317 
operator ++(int)318     const_svarint_iterator operator++(int) {
319         const const_svarint_iterator tmp(*this);
320         ++(*this);
321         return tmp;
322     }
323 
324 }; // class const_svarint_iterator
325 
326 } // end namespace protozero
327 
328 #endif // PROTOZERO_ITERATORS_HPP
329