Bond
 
Loading...
Searching...
No Matches
input_buffer.h
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#pragma once
5
6#include <bond/core/config.h>
7
8#include <bond/core/blob.h>
9#include <bond/core/exception.h>
10#include <bond/core/traits.h>
11#include <boost/static_assert.hpp>
12#include <cstring>
13
14namespace bond
15{
16
17namespace input_buffer
18{
19
20template <typename T, uint32_t Shift>
21struct VariableUnsignedUnchecked
22{
23 BOOST_STATIC_ASSERT(Shift < 56);
24 static void Read(const char*& p, T& value)
25 {
26 T byte = *p++;
27 value |= (byte & 0x7f) << Shift;
28
29 if (byte >= 0x80)
30 VariableUnsignedUnchecked<T, Shift + 7>::Read(p, value);
31 }
32};
33
34
35// Specialization for the first byte
36template <typename T>
37struct VariableUnsignedUnchecked<T, 0>
38{
39 static void Read(const char*& p, T& value)
40 {
41 T byte = *p++;
42 value = (byte & 0x7f);
43
44 if (byte >= 0x80)
45 VariableUnsignedUnchecked<T, 7>::Read(p, value);
46 }
47};
48
49
50// Specialization for the last byte of uint16_t
51template <>
52struct VariableUnsignedUnchecked<uint16_t, 14>
53{
54 static void Read(const char*& p, uint16_t& value)
55 {
56 uint16_t byte = *p++;
57 value |= byte << 14;
58 }
59};
60
61
62// Specialization for the last byte of uint32_t
63template <>
64struct VariableUnsignedUnchecked<uint32_t, 28>
65{
66 static void Read(const char*& p, uint32_t& value)
67 {
68 uint32_t byte = *p++;
69 value |= byte << 28;
70 }
71};
72
73
74// Specialization for the last 2 bytes of uint64_t
75template <>
76struct VariableUnsignedUnchecked<uint64_t, 56>
77{
78 static void Read(const char*& p, uint64_t& value)
79 {
80 uint64_t byte = *p++;
81 value |= byte << 56;
82
83 if (byte >= 0x80)
84 p++;
85 }
86};
87
88}
89
92{
93public:
96 : _pointer()
97 {}
98
105 : _blob(blob),
106 _pointer()
107 {}
108
114 InputBuffer(const void* buffer, uint32_t length)
115 : _blob(buffer, length),
116 _pointer()
117 {}
118
119
120 bool operator==(const InputBuffer& rhs) const
121 {
122 return _blob == rhs._blob
123 && _pointer == rhs._pointer;
124 }
125
126
127 void Read(uint8_t& value)
128 {
129 if (_blob.length() == _pointer)
130 {
131 EofException(sizeof(uint8_t));
132 }
133
134 value = static_cast<const uint8_t>(_blob.content()[_pointer++]);
135 }
136
137
138 template <typename T>
139 void Read(T& value)
140 {
141 BOOST_STATIC_ASSERT(std::is_arithmetic<T>::value || std::is_enum<T>::value);
142
143 if (sizeof(T) > _blob.length() - _pointer)
144 {
145 EofException(sizeof(T));
146 }
147
148#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
149 // x86/x64 performance tweak: we can access memory unaligned, so
150 // read directly from the buffer. Benchmarks show this as being
151 // slightly faster than memcpy.
152 value = *reinterpret_cast<const T*>(_blob.content() + _pointer);
153#else
154 //
155 // We can't use the trick above on platforms that don't support
156 // unaligned memory access, so just use memcpy.
157 //
158 const void* const src = _blob.content() + _pointer;
159 std::memcpy(&value, src, sizeof(T));
160#endif
161
162 _pointer += sizeof(T);
163 }
164
165
166 void Read(void *buffer, uint32_t size)
167 {
168 if (size > _blob.length() - _pointer)
169 {
170 EofException(size);
171 }
172
173 const void* const src = _blob.content() + _pointer;
174 std::memcpy(buffer, src, size);
175
176 _pointer += size;
177 }
178
179
180 void Read(blob& blob, uint32_t size)
181 {
182 if (size > _blob.length() - _pointer)
183 {
184 EofException(size);
185 }
186
187 blob.assign(_blob, _pointer, size);
188
189 _pointer += size;
190 }
191
192
193 void Skip(uint32_t size)
194 {
195 if (size > _blob.length() - _pointer)
196 {
197 return;
198 }
199
200 _pointer += size;
201 }
202
204 bool IsEof() const
205 {
206 return _pointer == _blob.length();
207 }
208
209
210 template <typename T>
211 void ReadVariableUnsigned(T& value)
212 {
213 if (_blob.length() > _pointer + sizeof(T) * 8 / 7)
214 {
215 const char* ptr = _blob.content() + _pointer;
216 input_buffer::VariableUnsignedUnchecked<T, 0>::Read(ptr, value);
217 _pointer = static_cast<uint32_t>(ptr - _blob.content());
218 }
219 else
220 {
221 GenericReadVariableUnsigned(*this, value);
222 }
223 }
224
225protected:
226 [[noreturn]] void EofException(uint32_t size) const
227 {
228 BOND_THROW(StreamException,
229 "Read out of bounds: " << size << " bytes requested, offset: "
230 << _pointer << ", length: " << _blob.length());
231 }
232
233 blob _blob;
234 uint32_t _pointer;
235
236
237 friend blob GetCurrentBuffer(const InputBuffer& input)
238 {
239 return input._blob.range(input._pointer);
240 }
241};
242
243
244inline InputBuffer CreateInputBuffer(const InputBuffer& /*other*/, const blob& blob)
245{
246 return InputBuffer(blob);
247}
248
249inline blob GetBufferRange(const blob& begin, const blob& end)
250{
251 return begin.range(0, begin.length() - end.length());
252}
253
254BOND_DEFINE_BUFFER_MAGIC(InputBuffer, 0x4249 /*IB*/);
255
256} // namespace bond
Memory backed input stream.
Definition: input_buffer.h:92
InputBuffer()
Default constructor.
Definition: input_buffer.h:95
InputBuffer(const blob &blob)
Construct from a blob.
Definition: input_buffer.h:104
InputBuffer(const void *buffer, uint32_t length)
Construct form a raw memory pointer.
Definition: input_buffer.h:114
bool IsEof() const
Check if the stream is at the end of the underlying memory buffer.
Definition: input_buffer.h:204
Memory blob.
Definition: blob.h:24
blob range(uint32_t offset, uint32_t length) const
Return a blob object for a range of this object.
Definition: blob.h:153
const char * content() const BOND_NOEXCEPT
Pointer to the content.
Definition: blob.h:192
uint32_t length() const BOND_NOEXCEPT
Length of the content.
Definition: blob.h:204
namespace bond
Definition: apply.h:17