1 #ifndef PROTOZERO_TYPES_HPP
2 #define PROTOZERO_TYPES_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 types.hpp
15  *
16  * @brief Contains the declaration of low-level types used in the pbf format.
17  */
18 
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <string>
24 #include <utility>
25 
26 #include <protozero/config.hpp>
27 
28 namespace protozero {
29 
30 /**
31  * The type used for field tags (field numbers).
32  */
33 using pbf_tag_type = uint32_t;
34 
35 /**
36  * The type used to encode type information.
37  * See the table on
38  *    https://developers.google.com/protocol-buffers/docs/encoding
39  */
40 enum class pbf_wire_type : uint32_t {
41     varint           = 0, // int32/64, uint32/64, sint32/64, bool, enum
42     fixed64          = 1, // fixed64, sfixed64, double
43     length_delimited = 2, // string, bytes, embedded messages,
44                             // packed repeated fields
45     fixed32          = 5, // fixed32, sfixed32, float
46     unknown          = 99 // used for default setting in this library
47 };
48 
49 /**
50  * Get the tag and wire type of the current field in one integer suitable
51  * for comparison with a switch statement.
52  *
53  * See pbf_reader.tag_and_type() for an example how to use this.
54  */
55 template <typename T>
tag_and_type(T tag,pbf_wire_type wire_type)56 constexpr inline uint32_t tag_and_type(T tag, pbf_wire_type wire_type) noexcept {
57     return (static_cast<uint32_t>(static_cast<pbf_tag_type>(tag)) << 3) | static_cast<uint32_t>(wire_type);
58 }
59 
60 /**
61  * The type used for length values, such as the length of a field.
62  */
63 using pbf_length_type = uint32_t;
64 
65 #ifdef PROTOZERO_USE_VIEW
66 using data_view = PROTOZERO_USE_VIEW;
67 #else
68 
69 /**
70  * Holds a pointer to some data and a length.
71  *
72  * This class is supposed to be compatible with the std::string_view
73  * that will be available in C++17.
74  */
75 class data_view {
76 
77     const char* m_data;
78     std::size_t m_size;
79 
80 public:
81 
82     /**
83      * Default constructor. Construct an empty data_view.
84      */
data_view()85     constexpr data_view() noexcept
86         : m_data(nullptr),
87           m_size(0) {
88     }
89 
90     /**
91      * Create data_view from pointer and size.
92      *
93      * @param ptr Pointer to the data.
94      * @param length Length of the data.
95      */
data_view(const char * ptr,std::size_t length)96     constexpr data_view(const char* ptr, std::size_t length) noexcept
97         : m_data(ptr),
98           m_size(length) {
99     }
100 
101     /**
102      * Create data_view from string.
103      *
104      * @param str String with the data.
105      */
data_view(const std::string & str)106     data_view(const std::string& str) noexcept
107         : m_data(str.data()),
108           m_size(str.size()) {
109     }
110 
111     /**
112      * Create data_view from zero-terminated string.
113      *
114      * @param ptr Pointer to the data.
115      */
data_view(const char * ptr)116     data_view(const char* ptr) noexcept
117         : m_data(ptr),
118           m_size(std::strlen(ptr)) {
119     }
120 
121     /**
122      * Swap the contents of this object with the other.
123      *
124      * @param other Other object to swap data with.
125      */
swap(data_view & other)126     void swap(data_view& other) noexcept {
127         using std::swap;
128         swap(m_data, other.m_data);
129         swap(m_size, other.m_size);
130     }
131 
132     /// Return pointer to data.
data() const133     constexpr const char* data() const noexcept {
134         return m_data;
135     }
136 
137     /// Return length of data in bytes.
size() const138     constexpr std::size_t size() const noexcept {
139         return m_size;
140     }
141 
142     /// Returns true if size is 0.
empty() const143     constexpr bool empty() const noexcept {
144         return m_size == 0;
145     }
146 
147     /**
148      * Convert data view to string.
149      *
150      * @pre Must not be default constructed data_view.
151      */
to_string() const152     std::string to_string() const {
153         protozero_assert(m_data);
154         return std::string{m_data, m_size};
155     }
156 
157     /**
158      * Convert data view to string.
159      *
160      * @pre Must not be default constructed data_view.
161      */
operator std::string() const162     explicit operator std::string() const {
163         protozero_assert(m_data);
164         return std::string{m_data, m_size};
165     }
166 
167 }; // class data_view
168 
169 /**
170  * Swap two data_view objects.
171  *
172  * @param lhs First object.
173  * @param rhs Second object.
174  */
swap(data_view & lhs,data_view & rhs)175 inline void swap(data_view& lhs, data_view& rhs) noexcept {
176     lhs.swap(rhs);
177 }
178 
179 /**
180  * Two data_view instances are equal if they have the same size and the
181  * same content.
182  *
183  * @param lhs First object.
184  * @param rhs Second object.
185  */
operator ==(const data_view & lhs,const data_view & rhs)186 inline bool operator==(const data_view& lhs, const data_view& rhs) noexcept {
187     return lhs.size() == rhs.size() && std::equal(lhs.data(), lhs.data() + lhs.size(), rhs.data());
188 }
189 
190 /**
191  * Two data_view instances are not equal if they have different sizes or the
192  * content differs.
193  *
194  * @param lhs First object.
195  * @param rhs Second object.
196  */
operator !=(const data_view & lhs,const data_view & rhs)197 inline bool operator!=(const data_view& lhs, const data_view& rhs) noexcept {
198     return !(lhs == rhs);
199 }
200 
201 #endif
202 
203 
204 } // end namespace protozero
205 
206 #endif // PROTOZERO_TYPES_HPP
207