1 // This code is derived from code distributed as part of Google LevelDB.
2 // The original is available in leveldb as util/coding.cc.
3 // This file was retrieved Jul 15, 2013 by Robert Escriva.
4
5 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style license that can be
7 // found in the LICENSE file. See the AUTHORS file for names of contributors.
8
9 // C
10 #include <stdlib.h>
11
12 // e
13 #include "e/varint.h"
14
15 namespace
16 {
17
18 const char*
decode_32_fallback(const char * p,const char * limit,uint32_t * value)19 decode_32_fallback(const char* p,
20 const char* limit,
21 uint32_t* value)
22
23 {
24 uint32_t result = 0;
25
26 for (uint32_t shift = 0; shift <= 28 && p < limit; shift += 7)
27 {
28 uint32_t byte = *(reinterpret_cast<const unsigned char*>(p));
29 p++;
30
31 if (byte & 128)
32 {
33 // More bytes are present
34 result |= ((byte & 127) << shift);
35 }
36 else
37 {
38 result |= (byte << shift);
39 *value = result;
40 return reinterpret_cast<const char*>(p);
41 }
42 }
43
44 return NULL;
45 }
46
47 } // namespace
48
49 const char*
varint32_decode(const char * p,const char * limit,uint32_t * value)50 e :: varint32_decode(const char* p,
51 const char* limit,
52 uint32_t* value)
53
54 {
55 if (p < limit)
56 {
57 uint32_t result = *(reinterpret_cast<const unsigned char*>(p));
58
59 if ((result & 128) == 0)
60 {
61 *value = result;
62 return p + 1;
63 }
64 }
65
66 return decode_32_fallback(p, limit, value);
67 }
68
69 const char*
varint64_decode(const char * p,const char * limit,uint64_t * value)70 e :: varint64_decode(const char* p, const char* limit, uint64_t* value)
71 {
72 uint64_t result = 0;
73
74 for (uint32_t shift = 0; shift <= 63 && p < limit; shift += 7)
75 {
76 uint64_t byte = *(reinterpret_cast<const unsigned char*>(p));
77 p++;
78
79 if (byte & 128)
80 {
81 // More bytes are present
82 result |= ((byte & 127) << shift);
83 }
84 else
85 {
86 result |= (byte << shift);
87 *value = result;
88 return reinterpret_cast<const char*>(p);
89 }
90 }
91
92 return NULL;
93 }
94
95 char*
varint32_encode(char * dst,uint32_t v)96 e :: varint32_encode(char* dst, uint32_t v)
97 {
98 // Operate on characters as unsigneds
99 unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
100 static const int B = 128;
101
102 if (v < (1<<7))
103 {
104 *(ptr++) = v;
105 }
106 else if (v < (1<<14))
107 {
108 *(ptr++) = v | B;
109 *(ptr++) = v>>7;
110 }
111 else if (v < (1<<21))
112 {
113 *(ptr++) = v | B;
114 *(ptr++) = (v>>7) | B;
115 *(ptr++) = v>>14;
116 }
117 else if (v < (1<<28))
118 {
119 *(ptr++) = v | B;
120 *(ptr++) = (v>>7) | B;
121 *(ptr++) = (v>>14) | B;
122 *(ptr++) = v>>21;
123 }
124 else
125 {
126 *(ptr++) = v | B;
127 *(ptr++) = (v>>7) | B;
128 *(ptr++) = (v>>14) | B;
129 *(ptr++) = (v>>21) | B;
130 *(ptr++) = v>>28;
131 }
132
133 return reinterpret_cast<char*>(ptr);
134 }
135
136 char*
varint64_encode(char * dst,uint64_t v)137 e :: varint64_encode(char* dst, uint64_t v)
138 {
139 static const unsigned B = 128;
140 unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
141
142 while (v >= B)
143 {
144 *(ptr++) = (v & (B-1)) | B;
145 v >>= 7;
146 }
147
148 *(ptr++) = static_cast<unsigned char>(v);
149 return reinterpret_cast<char*>(ptr);
150 }
151