First commit
[cpp_sandbox.git] / Sandbox / ReadVarint.cpp
1 #include "ReadVarint.h"
2
3 #include <iostream>
4 using namespace std;
5
6 // 'varint' is a way to encode integer in a variable number of byte. Using for serializing for example.
7 // Partial implementation of https://developers.google.com/protocol-buffers/docs/encoding
8
9 namespace ReadVarint
10 {
11 void readUInt(const uint8_t*& p, uint32_t res, uint32_t& result)
12 {
13 for (uint32_t i = 2; i < 5; i++)
14 {
15 uint32_t byte = static_cast<uint8_t>(p[i]);
16 res += (byte - 1) << (7 * i);
17 if (byte < 128)
18 {
19 p += (size_t)i + 1;
20 result = res;
21 return;
22 }
23 }
24
25 for (uint32_t i = 5; i < 10; i++)
26 {
27 uint32_t byte = static_cast<uint8_t>(p[i]);
28 if (byte < 128)
29 {
30 p += (size_t)i + 1;
31 result = res;
32 return;
33 }
34 }
35
36 result = res;
37 }
38
39 void readUInt(const uint8_t*& p, uint32_t res32, uint64_t& result)
40 {
41 uint64_t res = res32;
42 for (uint32_t i = 2; i < 10; i++)
43 {
44 uint64_t byte = static_cast<uint8_t>(p[i]);
45 res += (byte - 1) << (7 * i);
46 if (byte < 128)
47 {
48 p += (size_t)i + 1;
49 result = res;
50 return;
51 }
52 }
53
54 result = 0;
55 }
56
57 template<typename T>
58 T readUInt(const uint8_t*& p)
59 {
60 p += 1; // Skip the first byte (type + field n°)
61
62 uint32_t res = p[0];
63 if (!(res & 0x80))
64 {
65 p += 1;
66 return res;
67 }
68
69 uint32_t byte = p[1];
70 res += (byte - 1) << 7;
71 if (!(byte & 0x80))
72 {
73 p += 2;
74 return res;
75 }
76
77 T result;
78 readUInt(p, res, result);
79 return result;
80 }
81 }
82
83 void ReadVarint::tests()
84 {
85 const uint8_t bytes[] = {
86 0x08, 0x03, // v1 = 3.
87 0x10, 0xdf, 0xd0, 0x03, // v2 = 59487.
88
89 0x1a, 0x0a, // v3 = 10.
90
91 0x20, 0xb7, 0xac, 0xe5, 0x85, 0x08, 0x28, // v4 = 2159629879
92
93 0xb4, 0xdb, 0x9b, 0xf0, 0xe6, 0x97, 0xb8, 0xc1, 0x59, 0x38 // v5 = 6449964724842327476
94 };
95
96 const uint8_t* p = bytes; // Pointer on const bytes.
97
98 auto v1 = readUInt<uint32_t>(p);
99 auto v2 = readUInt<uint32_t>(p);
100 auto v3 = readUInt<uint32_t>(p);
101 auto v4 = readUInt<uint64_t>(p);
102 auto v5 = readUInt<uint64_t>(p);
103
104 cout << "p = " << hex << (int)(*p) << dec << endl;
105
106 cout << "v1 = " << v1 << ", v2 = " << v2 << ", v3 = " << v3 << ", v4 = " << v4 << ", v5 = " << v5<< endl;
107 }