7#include <bond/core/config.h>
10#include <bond/core/containers.h>
11#include <bond/core/detail/checked.h>
12#include <bond/core/traits.h>
13#include <boost/static_assert.hpp>
21namespace output_buffer
24template <
typename T, u
int32_t N>
25struct VariableUnsignedUnchecked
27 BOOST_STATIC_ASSERT(N < 10);
29 static uint32_t Write(
char* p, T value)
31 uint8_t
byte =
static_cast<uint8_t
>(value);
36 std::memcpy(p + N - 1, &
byte, 1);
37 return VariableUnsignedUnchecked<T, N+1>::Write(p, value);
41 std::memcpy(p + N - 1, &
byte, 1);
49struct VariableUnsignedUnchecked<uint64_t, 10>
51 static uint32_t Write(
char* p, uint64_t value)
53 BOOST_VERIFY(value == 1);
54 const uint8_t
byte = 1;
55 std::memcpy(p + 9, &
byte, 1);
62struct VariableUnsignedUnchecked<uint32_t, 5>
64 static uint32_t Write(
char* p, uint32_t value)
66 const uint8_t
byte =
static_cast<uint8_t
>(value);
67 std::memcpy(p + 4, &
byte, 1);
74struct VariableUnsignedUnchecked<uint16_t, 3>
76 static uint32_t Write(
char* p, uint16_t value)
78 const uint8_t
byte =
static_cast<uint8_t
>(value);
79 std::memcpy(p + 2, &
byte, 1);
87template <
typename A = std::allocator<
char> >
93 : _allocator(allocator),
98 _minChainningSize(32),
99 _maxChainLength((uint32_t)-1),
108 uint32_t reserveBlobs = 128,
109 const A& allocator = A(),
110 uint32_t minChanningSize = 32,
111 uint32_t maxChainLength = (uint32_t)-1)
112 : _allocator(allocator),
117 _minChainningSize(minChanningSize),
118 _maxChainLength(maxChainLength),
119 _rangePtr(_buffer.get()),
122 _blobs.reserve(reserveBlobs);
129 uint32_t reserveBlobs = 128,
130 const A& allocator = A(),
131 uint32_t minChanningSize = 32,
132 uint32_t maxChainLength = (uint32_t)-1)
133 : _allocator(allocator),
134 _buffer(boost::allocate_shared_noinit<char[]>(_allocator, reserveSize)),
135 _bufferSize(reserveSize),
138 _minChainningSize(minChanningSize),
139 _maxChainLength(maxChainLength),
140 _rangePtr(_buffer.get()),
143 _blobs.reserve(reserveBlobs);
149 template <
typename T>
152 buffers.reserve(bond::detail::checked_add(_blobs.size(), 1U));
157 buffers.assign(_blobs.begin(), _blobs.end());
165 buffers.emplace_back(_buffer, _rangeOffset, _rangeSize);
177 blob current(_buffer, _rangeOffset, _rangeSize);
178 return merge(_allocator, merge(_allocator, _blobs.begin(), _blobs.end()), current);
183 void Write(
const T& value)
185#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
192 if (
sizeof(T) + _rangeSize + _rangeOffset <= _bufferSize)
194 *
reinterpret_cast<T*
>(_rangePtr + _rangeSize) = value;
195 _rangeSize +=
sizeof(T);
199 Write(&value,
sizeof(value));
208 Write(&value,
sizeof(value));
213 void Write(
const void* value, uint32_t size)
215 uint32_t sizePart = _bufferSize - _rangeSize - _rangeOffset;
216 const char* buffer =
static_cast<const char*
>(value);
230 std::memcpy(_rangePtr + _rangeSize,
235 _rangeSize += sizePart;
241 if (size != sizePart)
243 BOOST_ASSERT(_bufferSize == _rangeSize + _rangeOffset);
256 _blobs.emplace_back(_buffer, _rangeOffset, _rangeSize);
260 if (_bufferSize > ((std::numeric_limits<uint32_t>::max)() >> 1))
262 throw std::bad_alloc();
269 _bufferSize += _bufferSize ? _bufferSize / 2 : 4096;
270 _bufferSize = (std::max)(_bufferSize, size);
272 _buffer = boost::allocate_shared_noinit<char[]>(_allocator, _bufferSize);
278 _rangePtr = _buffer.get();
283 std::memcpy(_rangePtr,
289 void Write(
const blob& buffer)
291 if (buffer.size() < _minChainningSize || _blobs.size() >= _maxChainLength)
294 return Write(buffer.data(), buffer.size());
305 _blobs.emplace_back(_buffer, _rangeOffset, _rangeSize);
307 _rangeOffset += _rangeSize;
308 _rangePtr += _rangeSize;
319 _blobs.push_back(buffer);
330 void WriteVariableUnsigned(T value)
332 if (
sizeof(T) * 8 / 7 + _rangeSize + _rangeOffset < _bufferSize)
334 char* ptr = _rangePtr + _rangeSize;
335 _rangeSize += output_buffer::VariableUnsignedUnchecked<T, 1>::Write(ptr, value);
339 GenericWriteVariableUnsigned(*
this, value);
348 boost::shared_ptr<char[]> _buffer;
351 uint32_t _bufferSize;
357 uint32_t _rangeOffset;
360 uint32_t _minChainningSize;
363 uint32_t _maxChainLength;
369 std::vector<blob, typename std::allocator_traits<A>::template rebind_alloc<blob> > _blobs;
376 static_cast<uint32_t
>(other._blobs.capacity()),
378 other._minChainningSize,
379 other._maxChainLength);
Memory backed output stream.
Definition: output_buffer.h:89
blob GetBuffer() const
Get content of the stream as one contiguous memory blob.
Definition: output_buffer.h:172
OutputMemoryStream(const A &allocator=A())
Construct OutputMemoryStream using specified allocator instance.
Definition: output_buffer.h:92
void GetBuffers(T &buffers) const
Get content of the stream as a collection of memory blobs.
Definition: output_buffer.h:150
OutputMemoryStream(const boost::shared_ptr< char[]> &buffer, uint32_t size, uint32_t reserveBlobs=128, const A &allocator=A(), uint32_t minChanningSize=32, uint32_t maxChainLength=(uint32_t) -1)
Construct OutputMemoryStream from the first buffer of the specified size and a preallocated vector to...
Definition: output_buffer.h:106
OutputMemoryStream(uint32_t reserveSize, uint32_t reserveBlobs=128, const A &allocator=A(), uint32_t minChanningSize=32, uint32_t maxChainLength=(uint32_t) -1)
Construct OutputMemoryStream with the first buffer of the specified size and a preallocated vector to...
Definition: output_buffer.h:128
Memory blob.
Definition: blob.h:24
namespace bond
Definition: apply.h:17
OutputMemoryStream OutputBuffer
Type alias for memory backed output stream using std::allocator.
Definition: output_buffer.h:386