Bond
 
Loading...
Searching...
No Matches
blob.h
Go to the documentation of this file.
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
5#pragma once
6
7#include <bond/core/config.h>
8
9#include "container_interface.h"
10#include "detail/checked.h"
11
12#include <boost/make_shared.hpp>
13#include <boost/shared_array.hpp>
14
15#include <stdint.h>
16#include <cstring>
17
19namespace bond
20{
21
23class blob
24{
25public:
26 typedef int8_t value_type;
27 typedef const char* const_iterator;
28
30 blob() BOND_NOEXCEPT
31 : _buffer(),
32 _length()
33 {
34 }
35
39 blob(const void* content, uint32_t length)
40 : _buffer(boost::shared_ptr<const void>(), static_cast<const char*>(content)), // Alias to an empty shared_ptr in order to store
41 // only a content pointer without the control block.
42 _length(length)
43 {
44 bond::detail::checked_add(_buffer.get(), length);
45 }
46
48 blob(const boost::shared_ptr<const char[]>& buffer, uint32_t length)
49 : _buffer(buffer),
50 _length(length)
51 {
52 bond::detail::checked_add(_buffer.get(), length);
53 }
54
56 blob(const boost::shared_ptr<const char[]>& buffer, uint32_t offset, uint32_t length)
57 : _buffer(buffer, bond::detail::checked_add(buffer.get(), offset)),
58 _length(length)
59 {
60 bond::detail::checked_add(_buffer.get(), length);
61 }
62
64 blob(const boost::shared_ptr<char[]>& buffer, uint32_t length)
65 : _buffer(buffer),
66 _length(length)
67 {
68 bond::detail::checked_add(_buffer.get(), length);
69 }
70
72 blob(const boost::shared_ptr<char[]>& buffer, uint32_t offset, uint32_t length)
73 : _buffer(buffer, bond::detail::checked_add(buffer.get(), offset)),
74 _length(length)
75 {
76 bond::detail::checked_add(_buffer.get(), length);
77 }
78
82 template <typename T, template <typename U> class SmartPtr>
83 blob(const SmartPtr<T>& buffer, uint32_t length)
84 : _buffer(wrap_in_shared_ptr(buffer)),
85 _length(length)
86 {
87 bond::detail::checked_add(_buffer.get(), length);
88 }
89
93 template <typename T, template <typename U> class SmartPtr>
94 blob(const SmartPtr<T>& buffer, uint32_t offset, uint32_t length)
95 : _buffer(wrap_in_shared_ptr(buffer, offset)),
96 _length(length)
97 {
98 bond::detail::checked_add(_buffer.get(), length);
99 }
100
102 blob(blob&& that) BOND_NOEXCEPT_IF(
103 std::is_nothrow_move_constructible<boost::shared_ptr<const char[]> >::value)
104 : _buffer(std::move(that._buffer)),
105 _length(std::move(that._length))
106 {
107 that._length = 0;
108 }
109
110 blob& operator=(blob&& that) BOND_NOEXCEPT_IF(
111 std::is_nothrow_move_assignable<boost::shared_ptr<const char[]> >::value)
112 {
113 _buffer = std::move(that._buffer);
114 _length = std::move(that._length);
115 that._length = 0;
116 return *this;
117 }
118
119 blob(const blob& that) = default;
120 blob& operator=(const blob& that) = default;
121
123 void assign(const blob& from, uint32_t offset, uint32_t length)
124 {
125 if (bond::detail::checked_add(offset, length) > from._length)
126 {
127 throw std::invalid_argument("Total of offset and length too large; must be less than or equal to length of blob");
128 }
129
130 _buffer = boost::shared_ptr<const char[]>(from._buffer, from._buffer.get() + offset);
131 _length = length;
132 }
133
135 template <typename T>
136 void assign(const T& buffer, uint32_t length)
137 {
138 blob temp(buffer, length);
139
140 swap(temp);
141 }
142
144 template <typename T>
145 void assign(const T& buffer, uint32_t offset, uint32_t length)
146 {
147 blob temp(buffer, offset, length);
148
149 swap(temp);
150 }
151
153 blob range(uint32_t offset, uint32_t length) const
154 {
155 if (bond::detail::checked_add(offset, length) > _length)
156 {
157 throw std::invalid_argument("Total of offset and length too large; must be less than or equal to length of blob");
158 }
159
160 return blob(_buffer, offset, length);
161 }
162
165 blob range(uint32_t offset) const
166 {
167 if (offset > _length)
168 {
169 throw std::invalid_argument("Offset too large; must be less than or equal to length of blob");
170 }
171
172 return blob(_buffer, offset, _length - offset);
173 }
174
176 void swap(blob& src) BOND_NOEXCEPT
177 {
178 std::swap(_length, src._length);
179 _buffer.swap(src._buffer);
180 }
181
184 void clear() BOND_NOEXCEPT
185 {
186 blob temp;
187
188 swap(temp);
189 }
190
192 const char* content() const BOND_NOEXCEPT
193 {
194 return _buffer.get();
195 }
196
198 const void* data() const BOND_NOEXCEPT
199 {
200 return _buffer.get();
201 }
202
204 uint32_t length() const BOND_NOEXCEPT
205 {
206 return _length;
207 }
208
210 uint32_t size() const BOND_NOEXCEPT
211 {
212 return _length;
213 }
214
216 bool empty() const BOND_NOEXCEPT
217 {
218 return 0 == length();
219 }
220
221 bool operator==(const blob& src) const BOND_NOEXCEPT
222 {
223 return this == &src
224 || ((_length == src._length)
225 && (0 == ::memcmp(_buffer.get(), src._buffer.get(), _length)));
226 }
227
229 const_iterator begin() const BOND_NOEXCEPT
230 {
231 return _buffer.get();
232 }
233
235 const_iterator end() const BOND_NOEXCEPT
236 {
237 return _buffer.get() + _length;
238 }
239
240
241 template <typename T>
242 friend T blob_cast(const blob& from);
243
244 template <typename A>
245 friend blob blob_prolong(blob src, const A& allocator);
246
247private:
248 template <typename T>
249 struct deleter
250 {
251 deleter(const T& p)
252 : p(p)
253 {}
254
255 void operator()(void const *)
256 {
257 p.reset();
258 }
259
260 T p;
261 };
262
263 template <typename T, template <typename U> class SmartPtr>
264 static boost::shared_ptr<const char[]> wrap_in_shared_ptr(const SmartPtr<T>& p, uint32_t offset = 0)
265 {
266 boost::shared_ptr<const char[]> ptr(bond::detail::checked_add(static_cast<const char*>(static_cast<const void*>(p.get())), offset),
267 deleter<SmartPtr<T> >(p));
268 return ptr;
269 }
270
271 boost::shared_ptr<const char[]> _buffer;
272
273 uint32_t _length;
274};
275
277inline void swap(blob& src, blob& dst) BOND_NOEXCEPT
278{
279 src.swap(dst);
280}
281
282inline bool operator != (const blob& x, const blob& y) BOND_NOEXCEPT
283{
284 return !(x == y);
285}
286
287template <typename A>
288inline blob merge(const A& allocator, const blob& x, const blob& y)
289{
290 if (x.empty() || y.empty())
291 {
292 //
293 // one of provided blobs is empty,
294 // return the other one
295 //
296 return x.empty() ? y : x;
297 }
298 else
299 {
300 uint32_t length = detail::checked_add(x.length(), y.length());
301 boost::shared_ptr<char[]> buffer = boost::allocate_shared_noinit<char[]>(allocator, length);
302
303 ::memcpy(buffer.get(), x.content(), x.length());
304 ::memcpy(buffer.get() + x.length(), y.content(), y.length());
305
306 return blob(buffer, length);
307 }
308}
309
310template <typename t_It, typename A>
311inline blob merge(const A& allocator, t_It begin, t_It end)
312{
313 //
314 // calculate the size of resulting blob
315 //
316 uint32_t length = 0;
317 for (t_It it = begin; it != end; ++it)
318 {
319 length = detail::checked_add(length, it->length());
320 }
321
322 if (0 == length)
323 {
324 //
325 // empty blob to return
326 //
327 return blob();
328 }
329 else if (length == begin->length())
330 {
331 //
332 // just first blob in the sequence is not empty
333 //
334 return *begin;
335 }
336 else
337 {
338 //
339 // sequence of several non-empty blobs
340 //
341 BOOST_ASSERT(length > begin->length());
342
343 boost::shared_ptr<char[]> buffer = boost::allocate_shared_noinit<char[]>(allocator, length);
344
345 uint32_t offset = 0;
346 for (t_It it = begin; it != end; ++it)
347 {
348 ::memcpy(buffer.get() + offset, it->content(), it->length());
349
350 offset += it->length();
351 }
352
353 BOOST_ASSERT(offset == length);
354 return blob(buffer, length);
355 }
356}
357
358inline blob merge(const blob& x, const blob& y)
359{
360 return merge(std::allocator<char>(), x, y);
361}
362
363template <typename t_It>
364inline blob merge(t_It begin, t_It end)
365{
366 return merge(std::allocator<char>(), begin, end);
367}
368
369template <> struct
370is_list_container<blob>
371 : std::true_type {};
372
373
374template <typename T>
375inline T blob_cast(const blob& from)
376{
377 if (from._buffer.use_count() != 0)
378 {
379 boost::shared_array<char> ptr(const_cast<char*>(static_cast<const char*>(static_cast<const void*>(from._buffer.get()))),
380 blob::deleter<boost::shared_ptr<const char[]> >(from._buffer));
381
382 return T(ptr, static_cast<uint32_t>(0), from._length);
383 }
384 else
385 {
386 return T(from._buffer.get(), from._length);
387 }
388}
389
392template <typename A>
393inline blob blob_prolong(blob src, const A& allocator)
394{
395 if (src._buffer.use_count() != 0)
396 {
397 return src;
398 }
399
400 boost::shared_ptr<char[]> buffer = boost::allocate_shared_noinit<char[]>(allocator, src.length());
401 ::memcpy(buffer.get(), src.content(), src.length());
402 return blob(buffer, src.length());
403}
404
405inline blob blob_prolong(blob src)
406{
407 return blob_prolong(std::move(src), std::allocator<char>());
408}
409
410
411} // namespace bond
Memory blob.
Definition: blob.h:24
const void * data() const BOND_NOEXCEPT
Void pointer to the content.
Definition: blob.h:198
blob(const boost::shared_ptr< const char[]> &buffer, uint32_t offset, uint32_t length)
Construct from a boost::shared_ptr to const memory buffer.
Definition: blob.h:56
bool empty() const BOND_NOEXCEPT
Check if the blob is empty (i.e. lenght == 0)
Definition: blob.h:216
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
blob(const void *content, uint32_t length)
Construct from a raw pointer to memory buffer.
Definition: blob.h:39
blob(const SmartPtr< T > &buffer, uint32_t length)
Construct from a smart pointer other than boost::shared_ptr.
Definition: blob.h:83
const_iterator begin() const BOND_NOEXCEPT
Iterator for the beginning of the blob.
Definition: blob.h:229
uint32_t size() const BOND_NOEXCEPT
Length of the content.
Definition: blob.h:210
void swap(blob &src) BOND_NOEXCEPT
Swap with another blob.
Definition: blob.h:176
void clear() BOND_NOEXCEPT
Clear reference to the underlying memory buffer and reset the blob to empty.
Definition: blob.h:184
blob() BOND_NOEXCEPT
Default constructor.
Definition: blob.h:30
void assign(const T &buffer, uint32_t length)
Assign a new value from a raw or smart pointer.
Definition: blob.h:136
blob(const SmartPtr< T > &buffer, uint32_t offset, uint32_t length)
Construct from a smart pointer other than boost::shared_ptr.
Definition: blob.h:94
blob(blob &&that) BOND_NOEXCEPT_IF(std
Move constructor.
Definition: blob.h:102
const_iterator end() const BOND_NOEXCEPT
Iterator for the end of the blob.
Definition: blob.h:235
uint32_t length() const BOND_NOEXCEPT
Length of the content.
Definition: blob.h:204
blob(const boost::shared_ptr< const char[]> &buffer, uint32_t length)
Construct from a boost::shared_ptr to const memory buffer.
Definition: blob.h:48
void assign(const blob &from, uint32_t offset, uint32_t length)
Assign a new value from another blob object or its part.
Definition: blob.h:123
blob(const boost::shared_ptr< char[]> &buffer, uint32_t length)
Construct from a boost::shared_ptr to memory buffer.
Definition: blob.h:64
blob range(uint32_t offset) const
Return a blob object for a range from the specified offset to the end of the buffer.
Definition: blob.h:165
void assign(const T &buffer, uint32_t offset, uint32_t length)
Assign a new value from a raw or smart pointer.
Definition: blob.h:145
friend blob blob_prolong(blob src, const A &allocator)
Returns a blob with a copy of the data if the original one does not own the memory (i....
Definition: blob.h:393
blob(const boost::shared_ptr< char[]> &buffer, uint32_t offset, uint32_t length)
Construct from a boost::shared_ptr to memory buffer.
Definition: blob.h:72
namespace bond
Definition: apply.h:17
void swap(blob &src, blob &dst) BOND_NOEXCEPT
Swap two blobs.
Definition: blob.h:277
blob blob_prolong(blob src, const A &allocator)
Returns a blob with a copy of the data if the original one does not own the memory (i....
Definition: blob.h:393
STL namespace.