JASSv2
protobuf.h
Go to the documentation of this file.
1 /*
2  PROTOBUF.H
3  ----------
4  Copyright (c) 2019 Andrew Trotman
5  Released under the 2-clause BSD license (See:https://en.wikipedia.org/wiki/BSD_licenses)
6 */
15 #pragma once
16 
17 #include <stdint.h>
18 #include "slice.h"
19 
20 namespace JASS
21  {
22  /*
23  CLASS PROTOBUF
24  --------------
25  */
31  class protobuf
32  {
33  public:
34  /*
35  ENUM PROTOBUF::WIRE_TYPE
36  ------------------------
37  */
42  enum wire_type
43  {
44  VARINT = 0,
46  BLOB = 2,
48  GROUP_END = 4,
50  };
51 
52  private:
53  /*
54  PROTOBUF::UN_ZIGZAG()
55  ---------------------
56  */
67  inline static int64_t un_zigzag(uint64_t bits)
68  {
69  return (int64_t)(bits >> 1) ^ -((int64_t)(bits & 0x1));
70  }
71 
72  public:
73  /*
74  PROTOBUF::GET_UINT64_T()
75  ------------------------
76  */
77  /*
78  @brief Read and decode an unsigned 64-bit VARINT integer.
79  @details The spec (https://developers.google.com/protocol-buffers/docs/encoding) states:
80  "Each byte in a varint, except the last byte, has the most significant bit (msb) set - this indicates
81  that there are further bytes to come. The lower 7 bits of each byte are used to store the two's complement
82  representation of the number in groups of 7 bits, least significant group first."
83  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
84  @return The decoded integer
85  */
86  uint64_t static get_uint64_t(const uint8_t *&stream)
87  {
88  uint64_t got;
89  uint64_t next;
90  uint8_t shift = 0;
91 
92  if (((got = *stream++) & 0x80) == 0)
93  return got;
94 
95  got &= 0x7F;
96 
97  while (1)
98  {
99  shift += 7;
100  if (((next = *stream++) & 0x80) == 0)
101  return got | next << shift;
102  got |= (next & 0x7F) << shift;
103  }
104 
105  return got;
106  }
107 
108  /*
109  PROTOBUF::GET_INT64_T()
110  -----------------------
111  */
112  /*
113  @brief Read and decode a signed 64-bit VARINT integer.
114  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
115  @return The decoded integer
116  */
117  inline static uint64_t get_int64_t(const uint8_t *&stream)
118  {
119  return un_zigzag(get_uint64_t(stream));
120  }
121 
122  /*
123  PROTOBUF::GET_UINT32_T()
124  ------------------------
125  */
126  /*
127  @brief Read and decode an unsigned 32-bit VARINT integer.
128  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
129  @return The decoded integer
130  */
131  inline static uint32_t get_uint32_t(const uint8_t *&stream)
132  {
133  return static_cast<uint32_t>(un_zigzag(get_uint64_t(stream)));
134  }
135 
136  /*
137  PROTOBUF::GET_INT32_T()
138  -----------------------
139  */
140  /*
141  @brief Read and decode a signed 32-bit VARINT integer.
142  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
143  @return The decoded integer
144  */
145  inline static int32_t get_int32_t(const uint8_t *&stream)
146  {
147  return static_cast<int32_t>(un_zigzag(get_uint64_t(stream)));
148  }
149 
150  /*
151  PROTOBUF::GET_BLOB()
152  --------------------
153  */
154  /*
155  @brief Read and decode a blob or string.
156  @details The spec (https://developers.google.com/protocol-buffers/docs/encoding) states:
157  "The value is a varint encoded length followed by the specified number of bytes of data."
158  @param stream [in,out] A reference to a pointer to the start of the value, points to the next byte on return.
159  @return A slice of stream containing the blob
160  */
161  inline static slice get_blob(const uint8_t *&stream)
162  {
163  size_t length = get_uint64_t(stream);
164  const uint8_t *at = &stream[0];
165  stream += length;
166 
167  return slice(const_cast<uint8_t *>(at), length);
168  }
169 
170  /*
171  PROTOBUF::GET_64_T()
172  --------------------
173  */
174  /*
175  @brief Read and decode a 64-bit number.
176  @details The spec (https://developers.google.com/protocol-buffers/docs/encoding) states:
177  "Non-varint numeric types are simple – double and fixed64 have wire type 1, which tells the parser to expect a
178  fixed 64-bit lump of data" and "The values are stored in little-endian byte order."
179  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
180  @return The decoded integer
181  */
182  inline static uint64_t get_64_t(const uint8_t *&stream)
183  {
184  uint64_t answer;
185 
186  answer = static_cast<uint64_t>(*stream++) << 0;
187  answer |= static_cast<uint64_t>(*stream++) << 8;
188  answer |= static_cast<uint64_t>(*stream++) << 16;
189  answer |= static_cast<uint64_t>(*stream++) << 24;
190  answer |= static_cast<uint64_t>(*stream++) << 32;
191  answer |= static_cast<uint64_t>(*stream++) << 40;
192  answer |= static_cast<uint64_t>(*stream++) << 48;
193  answer |= static_cast<uint64_t>(*stream++) << 56;
194 
195  return answer;
196  }
197 
198  /*
199  PROTOBUF::GET_32_T()
200  --------------------
201  */
202  /*
203  @brief Read and decode a 64-bit number.
204  @details The spec (https://developers.google.com/protocol-buffers/docs/encoding) states:
205  "Non-varint numeric types are simple" ... "float and fixed32 have wire type 5, which tells it to expect 32 bits"
206  and "The values are stored in little-endian byte order."
207  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
208  @return The decoded integer
209  */
210  inline static uint32_t get_32_t(const uint8_t *&stream)
211  {
212  uint32_t answer;
213 
214  answer = static_cast<uint32_t>(*stream++) << 0;
215  answer |= static_cast<uint32_t>(*stream++) << 8;
216  answer |= static_cast<uint32_t>(*stream++) << 16;
217  answer |= static_cast<uint32_t>(*stream++) << 24;
218 
219  return answer;
220  }
221 
222  /*
223  PROTOBUF::GET_DOUBLE()
224  ----------------------
225  */
226  /*
227  @brief Read and decode a double .
228  @details The spec (https://developers.google.com/protocol-buffers/docs/encoding) states:
229  "Non-varint numeric types are simple – double and fixed64 have wire type 1, which tells the parser to expect a fixed 64-bit lump of data"
230  and "the values are stored in little-endian byte order."
231  @param stream [in, out] A reference to a pointer to the start of the value, points to the next byte on return.
232  @return The decoded integer
233  */
234  inline static double get_double(const uint8_t *&stream)
235  {
236  union
237  {
238  uint64_t byte_sequence;
239  double number;
240  } answer;
241 
242  answer.byte_sequence = get_64_t(stream);
243  return answer.number;
244  }
245 
246  /*
247  PROTOBUF::GET_TYPE_AND_FIELD()
248  ------------------------------
249  */
259  static uint8_t get_type_and_field(wire_type &type, const uint8_t *&stream)
260  {
261  uint8_t encoding = *stream++;
262 
263  type = static_cast<wire_type>(encoding & 0x07);
264 
265  return encoding >> 3;
266  }
267  } ;
268  }
Little endian 32-bit number, integer or floating point types.
Definition: protobuf.h:49
C++ slices (string-descriptors)
Definition: slice.h:27
Depricated in protobuf 3.
Definition: protobuf.h:48
static int64_t un_zigzag(uint64_t bits)
Turn unsigned ZigZaged integer into a signed integer.
Definition: protobuf.h:67
Variable byte encoded integer of up-to 64 bits, signed or unsigned.
Definition: protobuf.h:44
Functions to read a protobuf buffer.
Definition: protobuf.h:31
Little endian 64-bit number, integer or floating point types.
Definition: protobuf.h:45
Slices (also known as string-descriptors) for C++.
Depricated in protobuf 3.
Definition: protobuf.h:47
Definition: compress_integer_elias_delta_simd.c:23
static uint8_t get_type_and_field(wire_type &type, const uint8_t *&stream)
Extract the field number and its type from the stream.
Definition: protobuf.h:259
wire_type
The known protobuf types for protobuf 3.
Definition: protobuf.h:42
Blob or string. length VARINT then data.
Definition: protobuf.h:46