1 #ifndef PROTOZERO_PBF_READER_HPP
2 #define PROTOZERO_PBF_READER_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 pbf_reader.hpp
15  *
16  * @brief Contains the pbf_reader class.
17  */
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <string>
22 #include <utility>
23 
24 #include <protozero/config.hpp>
25 #include <protozero/exception.hpp>
26 #include <protozero/iterators.hpp>
27 #include <protozero/types.hpp>
28 #include <protozero/varint.hpp>
29 
30 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
31 # include <protozero/byteswap.hpp>
32 #endif
33 
34 namespace protozero {
35 
36 /**
37  * This class represents a protobuf message. Either a top-level message or
38  * a nested sub-message. Top-level messages can be created from any buffer
39  * with a pointer and length:
40  *
41  * @code
42  *    std::string buffer;
43  *    // fill buffer...
44  *    pbf_reader message(buffer.data(), buffer.size());
45  * @endcode
46  *
47  * Sub-messages are created using get_message():
48  *
49  * @code
50  *    pbf_reader message(...);
51  *    message.next();
52  *    pbf_reader submessage = message.get_message();
53  * @endcode
54  *
55  * All methods of the pbf_reader class except get_bytes() and get_string()
56  * provide the strong exception guarantee, ie they either succeed or do not
57  * change the pbf_reader object they are called on. Use the get_view() method
58  * instead of get_bytes() or get_string(), if you need this guarantee.
59  */
60 class pbf_reader {
61 
62     // A pointer to the next unread data.
63     const char* m_data = nullptr;
64 
65     // A pointer to one past the end of data.
66     const char* m_end = nullptr;
67 
68     // The wire type of the current field.
69     pbf_wire_type m_wire_type = pbf_wire_type::unknown;
70 
71     // The tag of the current field.
72     pbf_tag_type m_tag = 0;
73 
74     template <typename T>
get_fixed()75     T get_fixed() {
76         T result;
77         skip_bytes(sizeof(T));
78         std::memcpy(&result, m_data - sizeof(T), sizeof(T));
79 #if PROTOZERO_BYTE_ORDER != PROTOZERO_LITTLE_ENDIAN
80         detail::byteswap_inplace(&result);
81 #endif
82         return result;
83     }
84 
85     template <typename T>
packed_fixed()86     iterator_range<const_fixed_iterator<T>> packed_fixed() {
87         protozero_assert(tag() != 0 && "call next() before accessing field value");
88         const auto len = get_len_and_skip();
89         protozero_assert(len % sizeof(T) == 0);
90         return iterator_range<const_fixed_iterator<T>>{const_fixed_iterator<T>(m_data - len, m_data),
91                                                        const_fixed_iterator<T>(m_data, m_data)};
92     }
93 
94     template <typename T>
get_varint()95     T get_varint() {
96         return static_cast<T>(decode_varint(&m_data, m_end));
97     }
98 
99     template <typename T>
get_svarint()100     T get_svarint() {
101         protozero_assert((has_wire_type(pbf_wire_type::varint) || has_wire_type(pbf_wire_type::length_delimited)) && "not a varint");
102         return static_cast<T>(decode_zigzag64(decode_varint(&m_data, m_end)));
103     }
104 
get_length()105     pbf_length_type get_length() {
106         return get_varint<pbf_length_type>();
107     }
108 
skip_bytes(pbf_length_type len)109     void skip_bytes(pbf_length_type len) {
110         if (m_data + len > m_end) {
111             throw end_of_buffer_exception();
112         }
113         m_data += len;
114 
115     // In debug builds reset the tag to zero so that we can detect (some)
116     // wrong code.
117 #ifndef NDEBUG
118         m_tag = 0;
119 #endif
120     }
121 
get_len_and_skip()122     pbf_length_type get_len_and_skip() {
123         const auto len = get_length();
124         skip_bytes(len);
125         return len;
126     }
127 
128     template <typename T>
get_packed()129     iterator_range<T> get_packed() {
130         protozero_assert(tag() != 0 && "call next() before accessing field value");
131         const auto len = get_len_and_skip();
132         return iterator_range<T>{T{m_data - len, m_data},
133                                  T{m_data, m_data}};
134     }
135 
136 public:
137 
138     /**
139      * Construct a pbf_reader message from a data_view. The pointer from the
140      * data_view will be stored inside the pbf_reader object, no data is
141      * copied. So you must make sure the view stays valid as long as the
142      * pbf_reader object is used.
143      *
144      * The buffer must contain a complete protobuf message.
145      *
146      * @post There is no current field.
147      */
pbf_reader(const data_view & view)148     explicit pbf_reader(const data_view& view) noexcept
149         : m_data(view.data()),
150           m_end(view.data() + view.size()),
151           m_wire_type(pbf_wire_type::unknown),
152           m_tag(0) {
153     }
154 
155     /**
156      * Construct a pbf_reader message from a data pointer and a length. The
157      * pointer will be stored inside the pbf_reader object, no data is copied.
158      * So you must make sure the buffer stays valid as long as the pbf_reader
159      * object is used.
160      *
161      * The buffer must contain a complete protobuf message.
162      *
163      * @post There is no current field.
164      */
pbf_reader(const char * data,std::size_t size)165     pbf_reader(const char* data, std::size_t size) noexcept
166         : m_data(data),
167           m_end(data + size),
168           m_wire_type(pbf_wire_type::unknown),
169           m_tag(0) {
170     }
171 
172     /**
173      * Construct a pbf_reader message from a data pointer and a length. The
174      * pointer will be stored inside the pbf_reader object, no data is copied.
175      * So you must make sure the buffer stays valid as long as the pbf_reader
176      * object is used.
177      *
178      * The buffer must contain a complete protobuf message.
179      *
180      * @post There is no current field.
181      */
pbf_reader(const std::pair<const char *,std::size_t> & data)182     explicit pbf_reader(const std::pair<const char*, std::size_t>& data) noexcept
183         : m_data(data.first),
184           m_end(data.first + data.second),
185           m_wire_type(pbf_wire_type::unknown),
186           m_tag(0) {
187     }
188 
189     /**
190      * Construct a pbf_reader message from a std::string. A pointer to the
191      * string internals will be stored inside the pbf_reader object, no data
192      * is copied. So you must make sure the string is unchanged as long as the
193      * pbf_reader object is used.
194      *
195      * The string must contain a complete protobuf message.
196      *
197      * @post There is no current field.
198      */
pbf_reader(const std::string & data)199     explicit pbf_reader(const std::string& data) noexcept
200         : m_data(data.data()),
201           m_end(data.data() + data.size()),
202           m_wire_type(pbf_wire_type::unknown),
203           m_tag(0) {
204     }
205 
206     /**
207      * pbf_reader can be default constructed and behaves like it has an empty
208      * buffer.
209      */
210     pbf_reader() noexcept = default;
211 
212     /// pbf_reader messages can be copied trivially.
213     pbf_reader(const pbf_reader&) noexcept = default;
214 
215     /// pbf_reader messages can be moved trivially.
216     pbf_reader(pbf_reader&&) noexcept = default;
217 
218     /// pbf_reader messages can be copied trivially.
219     pbf_reader& operator=(const pbf_reader& other) noexcept = default;
220 
221     /// pbf_reader messages can be moved trivially.
222     pbf_reader& operator=(pbf_reader&& other) noexcept = default;
223 
224     ~pbf_reader() = default;
225 
226     /**
227      * Swap the contents of this object with the other.
228      *
229      * @param other Other object to swap data with.
230      */
swap(pbf_reader & other)231     void swap(pbf_reader& other) noexcept {
232         using std::swap;
233         swap(m_data, other.m_data);
234         swap(m_end, other.m_end);
235         swap(m_wire_type, other.m_wire_type);
236         swap(m_tag, other.m_tag);
237     }
238 
239     /**
240      * In a boolean context the pbf_reader class evaluates to `true` if there
241      * are still fields available and to `false` if the last field has been
242      * read.
243      */
operator bool() const244     operator bool() const noexcept {
245         return m_data < m_end;
246     }
247 
248     /**
249      * Return the length in bytes of the current message. If you have
250      * already called next() and/or any of the get_*() functions, this will
251      * return the remaining length.
252      *
253      * This can, for instance, be used to estimate the space needed for a
254      * buffer. Of course you have to know reasonably well what data to expect
255      * and how it is encoded for this number to have any meaning.
256      */
length() const257     std::size_t length() const noexcept {
258         return std::size_t(m_end - m_data);
259     }
260 
261     /**
262      * Set next field in the message as the current field. This is usually
263      * called in a while loop:
264      *
265      * @code
266      *    pbf_reader message(...);
267      *    while (message.next()) {
268      *        // handle field
269      *    }
270      * @endcode
271      *
272      * @returns `true` if there is a next field, `false` if not.
273      * @pre There must be no current field.
274      * @post If it returns `true` there is a current field now.
275      */
next()276     bool next() {
277         if (m_data == m_end) {
278             return false;
279         }
280 
281         const auto value = get_varint<uint32_t>();
282         m_tag = pbf_tag_type(value >> 3);
283 
284         // tags 0 and 19000 to 19999 are not allowed as per
285         // https://developers.google.com/protocol-buffers/docs/proto
286         protozero_assert(((m_tag >     0 && m_tag < 19000) ||
287                           (m_tag > 19999 && m_tag <= ((1 << 29) - 1))) && "tag out of range");
288 
289         m_wire_type = pbf_wire_type(value & 0x07);
290         switch (m_wire_type) {
291             case pbf_wire_type::varint:
292             case pbf_wire_type::fixed64:
293             case pbf_wire_type::length_delimited:
294             case pbf_wire_type::fixed32:
295                 break;
296             default:
297                 throw unknown_pbf_wire_type_exception();
298         }
299 
300         return true;
301     }
302 
303     /**
304      * Set next field with given tag in the message as the current field.
305      * Fields with other tags are skipped. This is usually called in a while
306      * loop for repeated fields:
307      *
308      * @code
309      *    pbf_reader message(...);
310      *    while (message.next(17)) {
311      *        // handle field
312      *    }
313      * @endcode
314      *
315      * or you can call it just once to get the one field with this tag:
316      *
317      * @code
318      *    pbf_reader message(...);
319      *    if (message.next(17)) {
320      *        // handle field
321      *    }
322      * @endcode
323      *
324      * Note that this will not check the wire type. The two-argument version
325      * of this function will also check the wire type.
326      *
327      * @returns `true` if there is a next field with this tag.
328      * @pre There must be no current field.
329      * @post If it returns `true` there is a current field now with the given tag.
330      */
next(pbf_tag_type next_tag)331     bool next(pbf_tag_type next_tag) {
332         while (next()) {
333             if (m_tag == next_tag) {
334                 return true;
335             } else {
336                 skip();
337             }
338         }
339         return false;
340     }
341 
342     /**
343      * Set next field with given tag and wire type in the message as the
344      * current field. Fields with other tags are skipped. This is usually
345      * called in a while loop for repeated fields:
346      *
347      * @code
348      *    pbf_reader message(...);
349      *    while (message.next(17, pbf_wire_type::varint)) {
350      *        // handle field
351      *    }
352      * @endcode
353      *
354      * or you can call it just once to get the one field with this tag:
355      *
356      * @code
357      *    pbf_reader message(...);
358      *    if (message.next(17, pbf_wire_type::varint)) {
359      *        // handle field
360      *    }
361      * @endcode
362      *
363      * Note that this will also check the wire type. The one-argument version
364      * of this function will not check the wire type.
365      *
366      * @returns `true` if there is a next field with this tag.
367      * @pre There must be no current field.
368      * @post If it returns `true` there is a current field now with the given tag.
369      */
next(pbf_tag_type next_tag,pbf_wire_type type)370     bool next(pbf_tag_type next_tag, pbf_wire_type type) {
371         while (next()) {
372             if (m_tag == next_tag && m_wire_type == type) {
373                 return true;
374             } else {
375                 skip();
376             }
377         }
378         return false;
379     }
380 
381     /**
382      * The tag of the current field. The tag is the field number from the
383      * description in the .proto file.
384      *
385      * Call next() before calling this function to set the current field.
386      *
387      * @returns tag of the current field.
388      * @pre There must be a current field (ie. next() must have returned `true`).
389      */
tag() const390     pbf_tag_type tag() const noexcept {
391         return m_tag;
392     }
393 
394     /**
395      * Get the wire type of the current field. The wire types are:
396      *
397      * * 0 - varint
398      * * 1 - 64 bit
399      * * 2 - length-delimited
400      * * 5 - 32 bit
401      *
402      * All other types are illegal.
403      *
404      * Call next() before calling this function to set the current field.
405      *
406      * @returns wire type of the current field.
407      * @pre There must be a current field (ie. next() must have returned `true`).
408      */
wire_type() const409     pbf_wire_type wire_type() const noexcept {
410         return m_wire_type;
411     }
412 
413     /**
414      * Get the tag and wire type of the current field in one integer suitable
415      * for comparison with a switch statement.
416      *
417      * Use it like this:
418      *
419      * @code
420      *    pbf_reader message(...);
421      *    while (message.next()) {
422      *        switch (message.tag_and_type()) {
423      *            case tag_and_type(17, pbf_wire_type::length_delimited):
424      *                ....
425      *                break;
426      *            case tag_and_type(21, pbf_wire_type::varint):
427      *                ....
428      *                break;
429      *            default:
430      *                message.skip();
431      *        }
432      *    }
433      * @endcode
434      */
tag_and_type() const435     uint32_t tag_and_type() const noexcept {
436         return protozero::tag_and_type(tag(), wire_type());
437     }
438 
439     /**
440      * Check the wire type of the current field.
441      *
442      * @returns `true` if the current field has the given wire type.
443      * @pre There must be a current field (ie. next() must have returned `true`).
444      */
has_wire_type(pbf_wire_type type) const445     bool has_wire_type(pbf_wire_type type) const noexcept {
446         return wire_type() == type;
447     }
448 
449     /**
450      * Consume the current field.
451      *
452      * @pre There must be a current field (ie. next() must have returned `true`).
453      * @post The current field was consumed and there is no current field now.
454      */
skip()455     void skip() {
456         protozero_assert(tag() != 0 && "call next() before calling skip()");
457         switch (wire_type()) {
458             case pbf_wire_type::varint:
459                 skip_varint(&m_data, m_end);
460                 break;
461             case pbf_wire_type::fixed64:
462                 skip_bytes(8);
463                 break;
464             case pbf_wire_type::length_delimited:
465                 skip_bytes(get_length());
466                 break;
467             case pbf_wire_type::fixed32:
468                 skip_bytes(4);
469                 break;
470             default:
471                 protozero_assert(false && "can not be here because next() should have thrown already");
472         }
473     }
474 
475     ///@{
476     /**
477      * @name Scalar field accessor functions
478      */
479 
480     /**
481      * Consume and return value of current "bool" field.
482      *
483      * @pre There must be a current field (ie. next() must have returned `true`).
484      * @pre The current field must be of type "bool".
485      * @post The current field was consumed and there is no current field now.
486      */
get_bool()487     bool get_bool() {
488         protozero_assert(tag() != 0 && "call next() before accessing field value");
489         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
490         protozero_assert((*m_data & 0x80) == 0 && "not a 1 byte varint");
491         skip_bytes(1);
492         return m_data[-1] != 0; // -1 okay because we incremented m_data the line before
493     }
494 
495     /**
496      * Consume and return value of current "enum" field.
497      *
498      * @pre There must be a current field (ie. next() must have returned `true`).
499      * @pre The current field must be of type "enum".
500      * @post The current field was consumed and there is no current field now.
501      */
get_enum()502     int32_t get_enum() {
503         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
504         return get_varint<int32_t>();
505     }
506 
507     /**
508      * Consume and return value of current "int32" varint field.
509      *
510      * @pre There must be a current field (ie. next() must have returned `true`).
511      * @pre The current field must be of type "int32".
512      * @post The current field was consumed and there is no current field now.
513      */
get_int32()514     int32_t get_int32() {
515         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
516         return get_varint<int32_t>();
517     }
518 
519     /**
520      * Consume and return value of current "sint32" varint field.
521      *
522      * @pre There must be a current field (ie. next() must have returned `true`).
523      * @pre The current field must be of type "sint32".
524      * @post The current field was consumed and there is no current field now.
525      */
get_sint32()526     int32_t get_sint32() {
527         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
528         return get_svarint<int32_t>();
529     }
530 
531     /**
532      * Consume and return value of current "uint32" varint field.
533      *
534      * @pre There must be a current field (ie. next() must have returned `true`).
535      * @pre The current field must be of type "uint32".
536      * @post The current field was consumed and there is no current field now.
537      */
get_uint32()538     uint32_t get_uint32() {
539         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
540         return get_varint<uint32_t>();
541     }
542 
543     /**
544      * Consume and return value of current "int64" varint field.
545      *
546      * @pre There must be a current field (ie. next() must have returned `true`).
547      * @pre The current field must be of type "int64".
548      * @post The current field was consumed and there is no current field now.
549      */
get_int64()550     int64_t get_int64() {
551         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
552         return get_varint<int64_t>();
553     }
554 
555     /**
556      * Consume and return value of current "sint64" varint field.
557      *
558      * @pre There must be a current field (ie. next() must have returned `true`).
559      * @pre The current field must be of type "sint64".
560      * @post The current field was consumed and there is no current field now.
561      */
get_sint64()562     int64_t get_sint64() {
563         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
564         return get_svarint<int64_t>();
565     }
566 
567     /**
568      * Consume and return value of current "uint64" varint field.
569      *
570      * @pre There must be a current field (ie. next() must have returned `true`).
571      * @pre The current field must be of type "uint64".
572      * @post The current field was consumed and there is no current field now.
573      */
get_uint64()574     uint64_t get_uint64() {
575         protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint");
576         return get_varint<uint64_t>();
577     }
578 
579     /**
580      * Consume and return value of current "fixed32" field.
581      *
582      * @pre There must be a current field (ie. next() must have returned `true`).
583      * @pre The current field must be of type "fixed32".
584      * @post The current field was consumed and there is no current field now.
585      */
get_fixed32()586     uint32_t get_fixed32() {
587         protozero_assert(tag() != 0 && "call next() before accessing field value");
588         protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
589         return get_fixed<uint32_t>();
590     }
591 
592     /**
593      * Consume and return value of current "sfixed32" field.
594      *
595      * @pre There must be a current field (ie. next() must have returned `true`).
596      * @pre The current field must be of type "sfixed32".
597      * @post The current field was consumed and there is no current field now.
598      */
get_sfixed32()599     int32_t get_sfixed32() {
600         protozero_assert(tag() != 0 && "call next() before accessing field value");
601         protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
602         return get_fixed<int32_t>();
603     }
604 
605     /**
606      * Consume and return value of current "fixed64" field.
607      *
608      * @pre There must be a current field (ie. next() must have returned `true`).
609      * @pre The current field must be of type "fixed64".
610      * @post The current field was consumed and there is no current field now.
611      */
get_fixed64()612     uint64_t get_fixed64() {
613         protozero_assert(tag() != 0 && "call next() before accessing field value");
614         protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
615         return get_fixed<uint64_t>();
616     }
617 
618     /**
619      * Consume and return value of current "sfixed64" field.
620      *
621      * @pre There must be a current field (ie. next() must have returned `true`).
622      * @pre The current field must be of type "sfixed64".
623      * @post The current field was consumed and there is no current field now.
624      */
get_sfixed64()625     int64_t get_sfixed64() {
626         protozero_assert(tag() != 0 && "call next() before accessing field value");
627         protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
628         return get_fixed<int64_t>();
629     }
630 
631     /**
632      * Consume and return value of current "float" field.
633      *
634      * @pre There must be a current field (ie. next() must have returned `true`).
635      * @pre The current field must be of type "float".
636      * @post The current field was consumed and there is no current field now.
637      */
get_float()638     float get_float() {
639         protozero_assert(tag() != 0 && "call next() before accessing field value");
640         protozero_assert(has_wire_type(pbf_wire_type::fixed32) && "not a 32-bit fixed");
641         return get_fixed<float>();
642     }
643 
644     /**
645      * Consume and return value of current "double" field.
646      *
647      * @pre There must be a current field (ie. next() must have returned `true`).
648      * @pre The current field must be of type "double".
649      * @post The current field was consumed and there is no current field now.
650      */
get_double()651     double get_double() {
652         protozero_assert(tag() != 0 && "call next() before accessing field value");
653         protozero_assert(has_wire_type(pbf_wire_type::fixed64) && "not a 64-bit fixed");
654         return get_fixed<double>();
655     }
656 
657     /**
658      * Consume and return value of current "bytes", "string", or "message"
659      * field.
660      *
661      * @returns A data_view object.
662      * @pre There must be a current field (ie. next() must have returned `true`).
663      * @pre The current field must be of type "bytes", "string", or "message".
664      * @post The current field was consumed and there is no current field now.
665      */
get_view()666     data_view get_view() {
667         protozero_assert(tag() != 0 && "call next() before accessing field value");
668         protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
669         const auto len = get_len_and_skip();
670         return data_view{m_data - len, len};
671     }
672 
673 #ifndef PROTOZERO_STRICT_API
674     /**
675      * Consume and return value of current "bytes" or "string" field.
676      *
677      * @returns A pair with a pointer to the data and the length of the data.
678      * @pre There must be a current field (ie. next() must have returned `true`).
679      * @pre The current field must be of type "bytes" or "string".
680      * @post The current field was consumed and there is no current field now.
681      */
get_data()682     std::pair<const char*, pbf_length_type> get_data() {
683         protozero_assert(tag() != 0 && "call next() before accessing field value");
684         protozero_assert(has_wire_type(pbf_wire_type::length_delimited) && "not of type string, bytes or message");
685         const auto len = get_len_and_skip();
686         return std::make_pair(m_data - len, len);
687     }
688 #endif
689 
690     /**
691      * Consume and return value of current "bytes" field.
692      *
693      * @pre There must be a current field (ie. next() must have returned `true`).
694      * @pre The current field must be of type "bytes".
695      * @post The current field was consumed and there is no current field now.
696      */
get_bytes()697     std::string get_bytes() {
698         return std::string(get_view());
699     }
700 
701     /**
702      * Consume and return value of current "string" field.
703      *
704      * @pre There must be a current field (ie. next() must have returned `true`).
705      * @pre The current field must be of type "string".
706      * @post The current field was consumed and there is no current field now.
707      */
get_string()708     std::string get_string() {
709         return std::string(get_view());
710     }
711 
712     /**
713      * Consume and return value of current "message" field.
714      *
715      * @pre There must be a current field (ie. next() must have returned `true`).
716      * @pre The current field must be of type "message".
717      * @post The current field was consumed and there is no current field now.
718      */
get_message()719     pbf_reader get_message() {
720         return pbf_reader(get_view());
721     }
722 
723     ///@}
724 
725     /// Forward iterator for iterating over bool (int32 varint) values.
726     using const_bool_iterator   = const_varint_iterator< int32_t>;
727 
728     /// Forward iterator for iterating over enum (int32 varint) values.
729     using const_enum_iterator   = const_varint_iterator< int32_t>;
730 
731     /// Forward iterator for iterating over int32 (varint) values.
732     using const_int32_iterator  = const_varint_iterator< int32_t>;
733 
734     /// Forward iterator for iterating over sint32 (varint) values.
735     using const_sint32_iterator = const_svarint_iterator<int32_t>;
736 
737     /// Forward iterator for iterating over uint32 (varint) values.
738     using const_uint32_iterator = const_varint_iterator<uint32_t>;
739 
740     /// Forward iterator for iterating over int64 (varint) values.
741     using const_int64_iterator  = const_varint_iterator< int64_t>;
742 
743     /// Forward iterator for iterating over sint64 (varint) values.
744     using const_sint64_iterator = const_svarint_iterator<int64_t>;
745 
746     /// Forward iterator for iterating over uint64 (varint) values.
747     using const_uint64_iterator = const_varint_iterator<uint64_t>;
748 
749     ///@{
750     /**
751      * @name Repeated packed field accessor functions
752      */
753 
754     /**
755      * Consume current "repeated packed bool" field.
756      *
757      * @returns a pair of iterators to the beginning and one past the end of
758      *          the data.
759      * @pre There must be a current field (ie. next() must have returned `true`).
760      * @pre The current field must be of type "repeated packed bool".
761      * @post The current field was consumed and there is no current field now.
762      */
get_packed_bool()763     iterator_range<pbf_reader::const_bool_iterator> get_packed_bool() {
764         return get_packed<pbf_reader::const_bool_iterator>();
765     }
766 
767     /**
768      * Consume current "repeated packed enum" field.
769      *
770      * @returns a pair of iterators to the beginning and one past the end of
771      *          the data.
772      * @pre There must be a current field (ie. next() must have returned `true`).
773      * @pre The current field must be of type "repeated packed enum".
774      * @post The current field was consumed and there is no current field now.
775      */
get_packed_enum()776     iterator_range<pbf_reader::const_enum_iterator> get_packed_enum() {
777         return get_packed<pbf_reader::const_enum_iterator>();
778     }
779 
780     /**
781      * Consume current "repeated packed int32" field.
782      *
783      * @returns a pair of iterators to the beginning and one past the end of
784      *          the data.
785      * @pre There must be a current field (ie. next() must have returned `true`).
786      * @pre The current field must be of type "repeated packed int32".
787      * @post The current field was consumed and there is no current field now.
788      */
get_packed_int32()789     iterator_range<pbf_reader::const_int32_iterator> get_packed_int32() {
790         return get_packed<pbf_reader::const_int32_iterator>();
791     }
792 
793     /**
794      * Consume current "repeated packed sint32" field.
795      *
796      * @returns a pair of iterators to the beginning and one past the end of
797      *          the data.
798      * @pre There must be a current field (ie. next() must have returned `true`).
799      * @pre The current field must be of type "repeated packed sint32".
800      * @post The current field was consumed and there is no current field now.
801      */
get_packed_sint32()802     iterator_range<pbf_reader::const_sint32_iterator> get_packed_sint32() {
803         return get_packed<pbf_reader::const_sint32_iterator>();
804     }
805 
806     /**
807      * Consume current "repeated packed uint32" field.
808      *
809      * @returns a pair of iterators to the beginning and one past the end of
810      *          the data.
811      * @pre There must be a current field (ie. next() must have returned `true`).
812      * @pre The current field must be of type "repeated packed uint32".
813      * @post The current field was consumed and there is no current field now.
814      */
get_packed_uint32()815     iterator_range<pbf_reader::const_uint32_iterator> get_packed_uint32() {
816         return get_packed<pbf_reader::const_uint32_iterator>();
817     }
818 
819     /**
820      * Consume current "repeated packed int64" field.
821      *
822      * @returns a pair of iterators to the beginning and one past the end of
823      *          the data.
824      * @pre There must be a current field (ie. next() must have returned `true`).
825      * @pre The current field must be of type "repeated packed int64".
826      * @post The current field was consumed and there is no current field now.
827      */
get_packed_int64()828     iterator_range<pbf_reader::const_int64_iterator> get_packed_int64() {
829         return get_packed<pbf_reader::const_int64_iterator>();
830     }
831 
832     /**
833      * Consume current "repeated packed sint64" field.
834      *
835      * @returns a pair of iterators to the beginning and one past the end of
836      *          the data.
837      * @pre There must be a current field (ie. next() must have returned `true`).
838      * @pre The current field must be of type "repeated packed sint64".
839      * @post The current field was consumed and there is no current field now.
840      */
get_packed_sint64()841     iterator_range<pbf_reader::const_sint64_iterator> get_packed_sint64() {
842         return get_packed<pbf_reader::const_sint64_iterator>();
843     }
844 
845     /**
846      * Consume current "repeated packed uint64" field.
847      *
848      * @returns a pair of iterators to the beginning and one past the end of
849      *          the data.
850      * @pre There must be a current field (ie. next() must have returned `true`).
851      * @pre The current field must be of type "repeated packed uint64".
852      * @post The current field was consumed and there is no current field now.
853      */
get_packed_uint64()854     iterator_range<pbf_reader::const_uint64_iterator> get_packed_uint64() {
855         return get_packed<pbf_reader::const_uint64_iterator>();
856     }
857 
858     /**
859      * Consume current "repeated packed fixed32" field.
860      *
861      * @returns a pair of iterators to the beginning and one past the end of
862      *          the data.
863      * @pre There must be a current field (ie. next() must have returned `true`).
864      * @pre The current field must be of type "repeated packed fixed32".
865      * @post The current field was consumed and there is no current field now.
866      */
get_packed_fixed32()867     auto get_packed_fixed32() -> decltype(packed_fixed<uint32_t>()) {
868         return packed_fixed<uint32_t>();
869     }
870 
871     /**
872      * Consume current "repeated packed sfixed32" field.
873      *
874      * @returns a pair of iterators to the beginning and one past the end of
875      *          the data.
876      * @pre There must be a current field (ie. next() must have returned `true`).
877      * @pre The current field must be of type "repeated packed sfixed32".
878      * @post The current field was consumed and there is no current field now.
879      */
get_packed_sfixed32()880     auto get_packed_sfixed32() -> decltype(packed_fixed<int32_t>()) {
881         return packed_fixed<int32_t>();
882     }
883 
884     /**
885      * Consume current "repeated packed fixed64" field.
886      *
887      * @returns a pair of iterators to the beginning and one past the end of
888      *          the data.
889      * @pre There must be a current field (ie. next() must have returned `true`).
890      * @pre The current field must be of type "repeated packed fixed64".
891      * @post The current field was consumed and there is no current field now.
892      */
get_packed_fixed64()893     auto get_packed_fixed64() -> decltype(packed_fixed<uint64_t>()) {
894         return packed_fixed<uint64_t>();
895     }
896 
897     /**
898      * Consume current "repeated packed sfixed64" field.
899      *
900      * @returns a pair of iterators to the beginning and one past the end of
901      *          the data.
902      * @pre There must be a current field (ie. next() must have returned `true`).
903      * @pre The current field must be of type "repeated packed sfixed64".
904      * @post The current field was consumed and there is no current field now.
905      */
get_packed_sfixed64()906     auto get_packed_sfixed64() -> decltype(packed_fixed<int64_t>()) {
907         return packed_fixed<int64_t>();
908     }
909 
910     /**
911      * Consume current "repeated packed float" field.
912      *
913      * @returns a pair of iterators to the beginning and one past the end of
914      *          the data.
915      * @pre There must be a current field (ie. next() must have returned `true`).
916      * @pre The current field must be of type "repeated packed float".
917      * @post The current field was consumed and there is no current field now.
918      */
get_packed_float()919     auto get_packed_float() -> decltype(packed_fixed<float>()) {
920         return packed_fixed<float>();
921     }
922 
923     /**
924      * Consume current "repeated packed double" field.
925      *
926      * @returns a pair of iterators to the beginning and one past the end of
927      *          the data.
928      * @pre There must be a current field (ie. next() must have returned `true`).
929      * @pre The current field must be of type "repeated packed double".
930      * @post The current field was consumed and there is no current field now.
931      */
get_packed_double()932     auto get_packed_double() -> decltype(packed_fixed<double>()) {
933         return packed_fixed<double>();
934     }
935 
936     ///@}
937 
938 }; // class pbf_reader
939 
940 /**
941  * Swap two pbf_reader objects.
942  *
943  * @param lhs First object.
944  * @param rhs Second object.
945  */
swap(pbf_reader & lhs,pbf_reader & rhs)946 inline void swap(pbf_reader& lhs, pbf_reader& rhs) noexcept {
947     lhs.swap(rhs);
948 }
949 
950 } // end namespace protozero
951 
952 #endif // PROTOZERO_PBF_READER_HPP
953