BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlbb_blobutil.h
Go to the documentation of this file.
1/// @file bdlbb_blobutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlbb_blobutil.h -*-C++-*-
8#ifndef INCLUDED_BDLBB_BLOBUTIL
9#define INCLUDED_BDLBB_BLOBUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlbb_blobutil bdlbb_blobutil
15/// @brief Provide a suite of utilities for I/O operations on `bdlbb::Blob`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlbb
19/// @{
20/// @addtogroup bdlbb_blobutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlbb_blobutil-purpose"> Purpose</a>
25/// * <a href="#bdlbb_blobutil-classes"> Classes </a>
26/// * <a href="#bdlbb_blobutil-description"> Description </a>
27///
28/// # Purpose {#bdlbb_blobutil-purpose}
29/// Provide a suite of utilities for I/O operations on `bdlbb::Blob`.
30///
31/// # Classes {#bdlbb_blobutil-classes}
32///
33/// - bdlbb::BlobUtil: suite of utilities on `bdlbb::Blob`
34/// - bdlbb::BlobUtilAsciiDumper: helper class for ascii dump of a `blbb::Blob`
35/// - bdlbb::BlobUtilHexDumper: helper class for hex dump of a `bdlbb::Blob`
36///
37/// @see bdlbb_blob
38///
39/// # Description {#bdlbb_blobutil-description}
40/// This `struct` provides a variety of utilities for `bdlbb::Blob`
41/// objects, `bdlbb::BlobUtil`, such as I/O functions, comparison functions, and
42/// streaming functions.
43/// @}
44/** @} */
45/** @} */
46
47/** @addtogroup bdl
48 * @{
49 */
50/** @addtogroup bdlbb
51 * @{
52 */
53/** @addtogroup bdlbb_blobutil
54 * @{
55 */
56
57#include <bdlscm_version.h>
58
59#include <bdlbb_blob.h>
60
61#include <bslma_allocator.h>
62
63#include <bsls_assert.h>
65#include <bsls_review.h>
66
67#include <bsl_algorithm.h>
68#include <bsl_cstring.h>
69#include <bsl_iosfwd.h>
70#include <bsl_utility.h>
71
72
73namespace bdlbb {
74
75 // ===============
76 // struct BlobUtil
77 // ===============
78
79/// This `struct` is a namespace for a collection of static methods used
80/// for manipulating and accessing `Blob` objects.
81struct BlobUtil {
82
83 // CLASS METHODS
84
85 /// Append the specified `length` bytes from the specified `offset` in
86 /// the specified `source` to the specified `dest`. Note that the data
87 /// memory from `source` is not copied, but rather new `BlobBuffer`s
88 /// referring to the same data memory are created and appended to
89 /// `dest`, hence `dest` is not required to have a `BlobBufferFactory`.
90 static void append(Blob *dest, const Blob& source, int offset, int length);
91
92 /// Append from the specified `offset` in the specified `source` to the
93 /// specified `dest`. Note that the data memory from `source` is not
94 /// copied, but rather new `BlobBuffer`s referring to the same data
95 /// memory are created and appended to `dest`, hence `dest` is not
96 /// required to have a `BlobBufferFactory`.
97 static void append(Blob *dest, const Blob& source, int offset);
98
99 /// Append the specified `source` to the specified `dest`. Note that
100 /// the data memory from `source` is not copied, but rather new
101 /// `BlobBuffer`s referring to the same data memory are created and
102 /// appended to `dest`, hence `dest` is not required to have a
103 /// `BlobBufferFactory`.
104 static void append(Blob *dest, const Blob& source);
105
106 /// Append the specified `length` bytes starting from the specified
107 /// `offset` from the specified `source` address to the specified
108 /// `dest`. The behavior of this function is undefined unless the range
109 /// `[source + offset, source + offset + length)` represents a readable
110 /// sequence of memory, and
111 /// `length <= dest->totalSize() - dest->length()` or
112 /// `0 != dest->factory()`.
113 static void append(Blob *dest, const char *source, int offset, int length);
114
115 /// Append the specified `length` bytes starting from the specified
116 /// `source` address to the specified `dest`. The behavior is undefined
117 /// unless the range `[source, source + length)` is valid memory, and
118 /// `length <= dest->totalSize() - dest->length()` or
119 /// `0 != dest->factory()`.
120 static void append(Blob *dest, const char *source, int length);
121
122 /// Append the specified `length` bytes to the specified `dest`, all new
123 /// bytes are to be set to the specified `fill`. The behavior is
124 /// undefined unless `length <= dest->totalSize() - dest->length()` or
125 /// `0 != dest->factory()`.
126 static void append(Blob *dest, int length, char fill);
127
128 /// Append the specified `length` bytes from the specified `source`
129 /// address to the specified `dest`. Use the existing capacity in
130 /// `dest` first, followed by that in the `buffer`, and finally allocate
131 /// from the blob buffer factory associated with the `dest`. Load any
132 /// unused space into the specified `buffer`. The behavior is undefined
133 /// unless the range `[source, source + length)` represents a readable
134 /// sequence of memory.
136 BlobBuffer *buffer,
137 const char *source,
138 int length);
139
140 /// Erase the specified `length` bytes starting at the specified
141 /// `offset` from the specified `blob`. The behavior is undefined
142 /// unless `offset >= 0`, `length >= 0`, and
143 /// `offset + length <= blob->length()`.
144 static void erase(Blob *blob, int offset, int length);
145
146 /// Insert the specified `sourceLength` bytes from the specified
147 /// `sourceOffset` in the specified `source` to the specified
148 /// `destOffset` in the specified `dest`.
149 static void insert(Blob *dest,
150 int destOffset,
151 const Blob& source,
152 int sourceOffset,
153 int sourceLength);
154
155 /// Insert from the specified `sourceOffset` in the specified `source`
156 /// to the specified `destOffset` in the specified `dest`.
157 static void insert(Blob *dest,
158 int destOffset,
159 const Blob& source,
160 int sourceOffset);
161
162 /// Insert the specified `source` to the specified `destOffset` in the
163 /// specified `dest`.
164 static void insert(Blob *dest, int destOffset, const Blob& source);
165
166 /// Return a value, designated here as `p`, such that for the specified
167 /// `blob`, `blob.buffer(p.first)` is the buffer that contains the byte
168 /// at the specified `position` in `blob`, and `p.second` is the offset
169 /// corresponding to `position` within said buffer. The behavior of
170 /// this function is undefined unless `0 <= position`,
171 /// `0 < blob.totalSize()`, and `position < blob.totalSize()`. Note
172 /// that (1) subsequent changes to `blob` may invalidate the result of
173 /// this function, and (2) `p.first` never indicates a zero-size buffer.
175 int position);
176
177 /// Copy the specified `length` bytes starting at the specified
178 /// `position` in the specified `srcBlob` to the specified `dstBuffer`.
179 /// The behavior of this function is undefined unless `0 <= length`,
180 /// `0 <= position`, `position <= srcBlob.totalSize() - length`, and
181 /// `dstBuffer` has room for `length` bytes. Note that this function
182 /// does *not* set `dstBuffer[length]` to 0.
183 static void copy(char *dstBuffer,
184 const Blob& srcBlob,
185 int position,
186 int length);
187
188 /// Copy into the specified `dst` starting at the specified `dstOffset`
189 /// the specified `length` bytes from the specified `src`. The behavior
190 /// is undefined unless `0 <= dstOffset`, `0 <= length`,
191 /// `dst || 0 == length`, `src || 0 == length`,
192 /// `!dst || dstOffset <= dst->length() - length`, and `src` refers to a
193 /// buffer with at least `length` bytes. Note that this operation does
194 /// not require `dst` to have a blob buffer factory in that it does not
195 /// create or destroy blobs -- it simply copies data from `src` into
196 /// `dst`, so `dst` must already have room for `length` bytes of data
197 /// added at `dstOffset`.
198 static void copy(Blob *dst,
199 int dstOffset,
200 const char *src,
201 int length);
202
203 /// Copy into the specified `dst` starting at the specified `dstOffset`
204 /// the specified `length` bytes starting at the specified `srcOffset`
205 /// in the specified `src`. The behavior is undefined unless
206 /// `0 <= dstOffset`, `0 <= srcOffset`, `0 <= length`,
207 /// `dst || 0 == length`, `!dst || dstOffset <= dst->length() - length`,
208 /// and `srcOffset <= src->length() - length`. Note that this operation
209 /// does not require `dst` to have a blob buffer factory in that it does
210 /// not create or destroy blobs -- it simply copies data from `src` into
211 /// `dst`, so `dst` must already have room for `length` bytes of data
212 /// added at `dstOffset`.
213 static void copy(Blob *dst,
214 int dstOffset,
215 const Blob& src,
216 int srcOffset,
217 int length);
218
219 /// Return the address of the byte at the specified `position` in the
220 /// specified `srcBlob`, if that address is aligned to the optionally
221 /// specified `alignment` and the specified `length` bytes are stored
222 /// contiguously; otherwise, *copy* `length` bytes to the specified
223 /// buffer `dstBuffer`, and return `dstBuffer`. If alignment is not
224 /// specified, none is enforced. (An address is aligned to A if, when
225 /// converted to an integral value `a`, `a & (A - 1)` is 0.) The
226 /// behavior of this function is undefined unless `0 < length`,
227 /// `0 <= position`, `alignment` is a power of two, `dstBuffer` is
228 /// aligned as required, `dstBuffer` has room for `length` bytes, and
229 /// `position <= srcBlob.totalSize() - length`.
230 static char *getContiguousRangeOrCopy(char *dstBuffer,
231 const Blob& srcBlob,
232 int position,
233 int length,
234 int alignment = 1);
235
236 /// Obtain contiguous storage for at least the specified `addLength`
237 /// bytes in the specified `blob` at position `blob->length()`, and then
238 /// grow `blob->length()` by `addLength`. If, upon entry, such storage
239 /// does not exist in `blob`, first trim the final data buffer, if any,
240 /// and insert a new buffer obtained from the specified `factory`.
241 /// Return a pointer to the beginning of the storage obtained. The
242 /// behavior of this function is undefined unless `0 < addLength`, and
243 /// `factory->allocate()`, if called, yields a block of memory of a size
244 /// at least as large as `addLength`.
245 static char *getContiguousDataBuffer(Blob *blob,
246 int addLength,
247 BlobBufferFactory *factory);
248
249 /// Write to the specified `stream` an ascii dump of the specified
250 /// `source`, and return a reference to the modifiable `stream`.
251 static bsl::ostream& asciiDump(bsl::ostream& stream, const Blob& source);
252
253 /// Write to the specified `stream` an ascii dump of the specified
254 /// `length` bytes of the specified `source` starting at the specified
255 /// `offset`, and return a reference to the modifiable `stream`. The
256 /// behavior is undefined unless `0 <= offset`, `0 <= length`,
257 /// `length <= source.length()` and
258 /// `offset <= source.length() - length`.
259 static bsl::ostream& asciiDump(bsl::ostream& stream,
260 const Blob& source,
261 int offset,
262 int length);
263
264 /// Write to the specified `stream` a hexdump of the specified `source`,
265 /// and return a reference to the modifiable `stream`.
266 static bsl::ostream& hexDump(bsl::ostream& stream, const Blob& source);
267
268 /// Write to the specified `stream` a hexdump of the specified `length`
269 /// bytes of the specified `source` starting at the specified `offset`,
270 /// and return a reference to the modifiable `stream`. The behavior is
271 /// undefined unless `0 <= offset`, `0 <= length`,
272 /// `length <= source.length()` and
273 /// `offset <= source.length() - length`.
274 static bsl::ostream& hexDump(bsl::ostream& stream,
275 const Blob& source,
276 int offset,
277 int length);
278
279 /// Append padding bytes to the specified `dest` so that its resulting
280 /// length is an integer multiple of the specified `alignment`.
281 /// Optionally specify `fillChar` with which the padding is to be
282 /// filled. If `fillChar` is not specified, a 0 byte will be used. The
283 /// behavior is undefined unless `alignment` is a power of 2, and less
284 /// than or equal to 64.
285 static void padToAlignment(Blob *dest,
286 int alignment,
287 char fillChar = '\0');
288
289 /// Prepend the specified `length` bytes from the specified `source`
290 /// address to the specified `dest`. Use the existing capacity in
291 /// `dest` first if `0 == dest->length()`, followed by that in the
292 /// `buffer`, and finally allocate from the blob buffer factory
293 /// associated with the `dest`. Load any unused space into the
294 /// specified `buffer`. The behavior is undefined unless the range
295 /// `[source, source + length)` represents a readable sequence of
296 /// memory.
298 BlobBuffer *buffer,
299 const char *source,
300 int length);
301
302 /// Read the specified `numBytes` from the specified `stream` and load
303 /// it into the specified `dest`, and return a reference to the
304 /// modifiable `stream`.
305 template <class STREAM>
306 static STREAM& read(STREAM& stream, Blob *dest, int numBytes);
307
308 /// Write the specified `source` to the specified `stream`, and return a
309 /// reference to the modifiable `stream`.
310 template <class STREAM>
311 static STREAM& write(STREAM& stream, const Blob& source);
312
313 /// Write to the specified `stream` the specified `numBytes` starting at
314 /// the specified `sourcePosition` in the specified `source` blob.
315 /// Return 0 on success or a non-zero value otherwise. Note that this
316 /// function will fail (immediately) if the length of `source` is less
317 /// than `numBytes`; or if there is any error writing to `stream`.
318 template <class STREAM>
319 static int write(STREAM& stream,
320 const Blob& source,
321 int sourcePosition,
322 int numBytes);
323
324 /// Compare, lexicographically, the data (data length and character data
325 /// values at each index position) stored by the specified `a` and `b`
326 /// blobs. Return 0 if the data stored by `a` is lexicographically
327 /// equal to the data stored by `b`, a negative value if `a` is
328 /// lexicographically less than `b`, and a positive value if `a` is
329 /// lexicographically greater than `b`.
330 static int compare(const Blob& a, const Blob& b);
331
332 /// Append the specified `buffer` after the last buffer of the specified
333 /// `dest` if neither the resulting total size of `dest` nor its
334 /// resulting total number of buffers exceeds `INT_MAX`. Return 0 on
335 /// success, and a non-zero value (with no effect) otherwise. The
336 /// length of the `dest` is unaffected.
337 static int appendBufferIfValid(Blob *dest, const BlobBuffer& buffer);
338
339 /// Append the specified move-insertable `buffer` after the last buffer
340 /// of the specified `dest` if neither the resulting total size of
341 /// `dest` nor its resulting total number of buffers exceeds `INT_MAX`.
342 /// Return 0 on success, and a non-zero value (with no effect)
343 /// otherwise. The length of the `dest` is unaffected. In case of
344 /// success the `buffer` is left in a valid but unspecified state.
345 static int appendBufferIfValid(Blob *dest,
347
348 /// Append the specified `buffer` after the last *data* buffer of the
349 /// specified `dest` if neither the resulting total size of `dest` nor
350 /// its resulting total number of buffers exceeds `INT_MAX`. Return 0
351 /// on success, and a non-zero value (with no effect) otherwise. The
352 /// last data buffer of the `dest` is trimmed, if necessary. The length
353 /// of the `dest` is incremented by the size of `buffer`.
354 static int appendDataBufferIfValid(Blob *dest, const BlobBuffer& buffer);
355
356 /// Append the specified move-insertable `buffer` after the last *data*
357 /// buffer of the specified `dest` if neither the resulting total size
358 /// of `dest` nor its resulting total number of buffers exceeds
359 /// `INT_MAX`. Return 0 on success, and a non-zero value (with no
360 /// effect) otherwise. The last data buffer of the `dest` is trimmed,
361 /// if necessary. The length of the `dest` is incremented by the size
362 /// of `buffer`. In case of success the `buffer` is left in a valid but
363 /// unspecified state.
364 static int appendDataBufferIfValid(Blob *dest,
366
367 /// Insert the specified `buffer` at the specified `index` in the
368 /// specified `dest` if `0 <= index <= dest->numBuffers()` and neither
369 /// the resulting total size of `dest` nor its resulting total number of
370 /// buffers exceeds `INT_MAX`. Return 0 on success, and a non-zero
371 /// value (with no effect) otherwise. Increment the length of the 'dest
372 /// by the size of the `buffer` if `buffer` is inserted *before* the
373 /// logical end of the `dest`. The length of the `dest` is <u>unchanged</u>
374 /// if inserting at a position following all data buffers (e.g.,
375 /// inserting into an empty blob or inserting a buffer to increase
376 /// capacity); in that case, the blob length must be changed by an
377 /// explicit call to `setLength`. Buffers at `index` and higher
378 /// positions (if any) are shifted up by one index position.
379 static int insertBufferIfValid(Blob *dest,
380 int index,
381 const BlobBuffer& buffer);
382
383 /// Insert the specified move-insertable `buffer` at the specified
384 /// `index` in the specified `dest` if
385 /// `0 <= index <= dest->numBuffers()` and neither the resulting total
386 /// size of `dest` nor its resulting total number of buffers exceeds
387 /// `INT_MAX`. Return 0 on success, and a non-zero value (with no
388 /// effect) otherwise. Increment the length of the 'dest by the size of
389 /// the `buffer` if `buffer` is inserted *before* the logical end of the
390 /// `dest`. The length of the `dest` is <u>unchanged</u> if inserting at a
391 /// position following all data buffers (e.g., inserting into an empty
392 /// blob or inserting a buffer to increase capacity); in that case, the
393 /// blob length must be changed by an explicit call to `setLength`.
394 /// Buffers at `index` and higher positions (if any) are shifted up by
395 /// one index position. In case of success the `buffer` is left in a
396 /// valid but unspecified state.
397 static int insertBufferIfValid(Blob *dest,
398 int index,
400
401 /// Insert the specified `buffer` before the beginning of the specified
402 /// `dest` if neither the resulting total size of `dest` nor its
403 /// resulting total number of buffers exceeds `INT_MAX`. Return 0 on
404 /// success, and a non-zero value (with no effect) otherwise. The
405 /// length of the `dest` is incremented by the length of the prepended
406 /// buffer.
407 static int prependDataBufferIfValid(Blob *dest, const BlobBuffer& buffer);
408
409 /// Insert the specified move-insertable `buffer` before the beginning
410 /// of the specified `dest` if neither the resulting total size of
411 /// `dest` nor its resulting total number of buffers exceeds `INT_MAX`.
412 /// Return 0 on success, and a non-zero value (with no effect)
413 /// otherwise. The length of the `dest` is incremented by the length of
414 /// the prepended buffer. In case of success the `buffer` is left in a
415 /// valid but unspecified state.
416 static int prependDataBufferIfValid(Blob *dest,
418
419 // ---------- DEPRECATED FUNCTIONS ------------- //
420
421 // DEPRECATED FUNCTIONS: basicAllocator is no longer used
422 static void append(Blob *dest,
423 const Blob& source,
424 int offset,
425 int length,
427
428 static void append(Blob *dest,
429 const Blob& source,
430 int offset,
432
433 static void append(Blob *dest, const Blob& source, bslma::Allocator *);
434};
435
436 // ==========================
437 // struct BlobUtilAsciiDumper
438 // ==========================
439
440/// Utility for ascii dumping a blob to standard output streams. This class
441/// has `operator<<` defined for it, so it can be used, for example, in
442/// `ball` logs.
444
445 // DATA
446 const Blob *d_blob_p; // data to be dumped (held, not owned)
447 int d_offset; // desired offset
448 int d_length; // desired number of bytes to be dumped
449
450 // CREATORS
451
452 /// Create an ascii dumper for the specified `blob` that dumps the
453 /// entire `blob` to the output stream when passed to `operator<<`. See
454 /// `operator<<(bsl::ostream&, const BlobUtilAsciiDumper&)` for details.
455 explicit BlobUtilAsciiDumper(const Blob *blob);
456
457 /// Create an ascii dumper for the specified `blob` that ascii dumps the
458 /// first `min(length, blob->length())` bytes of the `blob` to the
459 /// output stream when passed to `operator<<`. See
460 /// `operator<<(bsl::ostream&, const BlobUtilAsciiDumper&)` for details.
461 /// The behavior is undefined unless `0 <= length`.
462 BlobUtilAsciiDumper(const Blob *blob, int length);
463
464 /// Create a hex dumper for the specified `blob` that ascii dumps the
465 /// bytes of the `blob` starting with the `min(offset, blob->length())`
466 /// byte and until `min(offset + length, blob->length())` byte to the
467 /// output stream when passed to `operator<<`. See
468 /// `operator<<(bsl::ostream&, const BlobUtilAsciiDumper&)` for details.
469 /// The behavior is undefined unless `0 <= offset && 0 <= length`.
470 BlobUtilAsciiDumper(const Blob *blob, int offset, int length);
471};
472
473// FREE OPERATORS
474
475/// Ascii-dump to the specified `stream` the bytes of the blob referenced
476/// by the specified `rhs` starting with the
477/// `min(rhs.d_offset, rhs.d_blob_p->length())` byte and until
478/// `min(rhs.d_offset + rhs.d_length, rhs.d_blob_p->length())` byte, and
479/// return a reference to the modifiable `stream`.
480bsl::ostream& operator<<(bsl::ostream& stream, const BlobUtilAsciiDumper& rhs);
481
482 // ========================
483 // struct BlobUtilHexDumper
484 // ========================
485
486/// Utility for hex dumping a blob to standard output streams. This class
487/// has `operator<<` defined for it, so it can be used, for example, in
488/// `ball` logs.
490
491 // DATA
492 const Blob *d_blob_p; // data to be dumped (held, not owned)
493 int d_offset; // desired offset
494 int d_length; // desired number of bytes to be dumped
495
496 // CREATORS
497
498 /// Create a hex dumper for the specified `blob` that hex dumps the
499 /// entire `blob` to the output stream when passed to `operator<<`. See
500 /// `operator<<(bsl::ostream&, const BlobUtilHexDumper&)` for details.
501 explicit BlobUtilHexDumper(const Blob *blob);
502
503 /// Create a hex dumper for the specified `blob` that hex dumps the
504 /// first `min(length, blob->length())` bytes of the `blob` to the
505 /// output stream when passed to `operator<<`. See
506 /// `operator<<(bsl::ostream&, const BlobUtilHexDumper&)` for details.
507 /// The behavior is undefined unless `0 <= length`.
508 BlobUtilHexDumper(const Blob *blob, int length);
509
510 /// Create a hex dumper for the specified `blob` that hex dumps the
511 /// bytes of the `blob` starting with the `min(offset, blob->length())`
512 /// byte and until `min(offset + length, blob->length())` byte to the
513 /// output stream when passed to `operator<<`. See
514 /// `operator<<(bsl::ostream&, const BlobUtilHexDumper&)` for details.
515 /// The behavior is undefined unless `0 <= offset && 0 <= length`.
516 BlobUtilHexDumper(const Blob *blob, int offset, int length);
517};
518
519// FREE OPERATORS
520
521/// Hex-dump to the specified `stream` the bytes of the blob referenced by
522/// the specified `rhs` starting with the
523/// `min(rhs.d_offset, rhs.d_blob_p->length())` byte and until
524/// `min(rhs.d_offset + rhs.d_length, rhs.d_blob_p->length())` byte, and
525/// return a reference to the modifiable `stream`.
526bsl::ostream& operator<<(bsl::ostream& stream, const BlobUtilHexDumper& rhs);
527
528// ============================================================================
529// INLINE DEFINITIONS
530// ============================================================================
531
532 // ---------------
533 // struct BlobUtil
534 // ---------------
535
536// CLASS METHODS
537inline
538void BlobUtil::append(Blob *dest, const Blob& source, int offset)
539{
540 append(dest, source, offset, source.length() - offset);
541}
542
543inline
544void BlobUtil::append(Blob *dest, const Blob& source)
545{
546 append(dest, source, 0, source.length());
547}
548
549inline
551 const Blob& source,
552 int offset,
553 int length,
555{
556 return append(dest, source, offset, length);
557}
558
559inline
561 const Blob& source,
562 int offset,
564{
565 return append(dest, source, offset);
566}
567
568inline
569void BlobUtil::append(Blob *dest, const Blob& source, bslma::Allocator *)
570{
571 return append(dest, source);
572}
573
574inline
575void BlobUtil::append(Blob *dest, const char *source, int length)
576{
577 BSLS_ASSERT(0 != dest);
578 BSLS_ASSERT(0 != source || 0 == length);
579 BSLS_ASSERT(0 <= length);
580
581 if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 == length)) {
582 // There is no need to add even a single byte.
583 return; // RETURN
584 }
585
587 const int lastDataBufIdx = dest->numDataBuffers() - 1;
588 const BlobBuffer& lastBuf = dest->buffer(lastDataBufIdx);
589 const int offsetInBuf = dest->lastDataBufferLength();
590 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(lastBuf.size() - offsetInBuf >=
591 length)) {
592 dest->setLength(dest->length() + length);
593 bsl::memcpy(lastBuf.buffer().get() + offsetInBuf, source, length);
594 return; // RETURN
595 }
596 }
598 append(dest, source, 0, length);
599}
600
601inline
603 int destOffset,
604 const Blob& source,
605 int sourceOffset)
606{
607 insert(dest,
608 destOffset,
609 source,
610 sourceOffset,
611 source.length() - sourceOffset);
612}
613
614inline
615void BlobUtil::insert(Blob *dest, int destOffset, const Blob& source)
616{
617 insert(dest, destOffset, source, 0, source.length());
618}
619
620inline
621bsl::ostream& BlobUtil::hexDump(bsl::ostream& stream, const Blob& source)
622{
623 return hexDump(stream, source, 0, source.length());
624}
625
626inline
627void BlobUtil::padToAlignment(Blob *dest, int alignment, char fillChar)
628{
629 BSLS_ASSERT(0 != dest);
630 BSLS_ASSERT(static_cast<unsigned>(alignment) <= 64);
631
632 const int modMask = alignment - 1;
633
634 BSLS_ASSERT(0 == (alignment & modMask)); // power of 2
635
636 const int padLength = (alignment - (dest->length() & modMask)) & modMask;
637 char padBuffer[63];
638 bsl::memset(padBuffer, fillChar, padLength);
639
640 append(dest, padBuffer, padLength);
641}
642
643template <class STREAM>
644STREAM& BlobUtil::read(STREAM& stream, Blob *dest, int numBytes)
645{
646 BSLS_ASSERT(0 != dest);
647
648 dest->setLength(numBytes);
649
650 for (int numBytesRemaining = numBytes, i = 0; 0 < numBytesRemaining; ++i) {
651 BSLS_ASSERT(i < dest->numBuffers());
652
653 BlobBuffer buffer = dest->buffer(i);
654
655 const int bytesToRead = numBytesRemaining < buffer.size()
656 ? numBytesRemaining
657 : buffer.size();
658
659 stream.getArrayInt8(buffer.data(), bytesToRead);
660
661 numBytesRemaining -= bytesToRead;
662 }
663
664 return stream;
665}
666
667template <class STREAM>
668STREAM& BlobUtil::write(STREAM& stream, const Blob& source)
669{
670 int numBytes = source.length();
671
672 for (int numBytesRemaining = numBytes, i = 0; 0 < numBytesRemaining; ++i) {
673 BSLS_ASSERT(i < source.numBuffers());
674
675 BlobBuffer buffer = source.buffer(i);
676
677 const int bytesToWrite = numBytesRemaining < buffer.size()
678 ? numBytesRemaining
679 : buffer.size();
680
681 stream.putArrayInt8(buffer.data(), bytesToWrite);
682
683 numBytesRemaining -= bytesToWrite;
684 }
685
686 return stream;
687}
688
689template <class STREAM>
690int BlobUtil::write(STREAM& stream,
691 const Blob& source,
692 int sourcePosition,
693 int numBytes)
694{
695 BSLS_ASSERT(0 <= sourcePosition);
696 BSLS_ASSERT(0 <= numBytes);
697
698 if (sourcePosition + numBytes > source.length()) {
699 return -1; // RETURN
700 }
701
702 if (sourcePosition == 0 && numBytes == 0) {
703 return 0; // RETURN
704 }
705
706 int bufferIndex = 0;
707 int bytesSkipped = 0;
708 while (bytesSkipped + source.buffer(bufferIndex).size() <=
709 sourcePosition) {
710 bytesSkipped += source.buffer(bufferIndex).size();
711 ++bufferIndex;
712 }
713
714 int bytesRemaining = numBytes;
715 while (0 < bytesRemaining) {
716 const BlobBuffer& buffer = source.buffer(bufferIndex);
717
718 const int startingIndex = 0 < bytesSkipped || 0 == bufferIndex
719 ? sourcePosition - bytesSkipped
720 : 0;
721
722 const int bytesToCopy = bytesRemaining > buffer.size() - startingIndex
723 ? buffer.size() - startingIndex
724 : bytesRemaining;
725
726 stream.putArrayInt8(buffer.data() + startingIndex, bytesToCopy);
727 if (!stream) {
728 return -1; // RETURN
729 }
730
731 bytesRemaining -= bytesToCopy;
732 bytesSkipped = 0;
733 ++bufferIndex;
734 }
735
736 BSLS_ASSERT(bytesRemaining == 0);
737 return 0;
738}
739
740inline
742{
743 BlobBuffer objectToMove(buffer);
744 return appendBufferIfValid(dest,
745 bslmf::MovableRefUtil::move(objectToMove));
746}
747
748inline
751{
752 BlobBuffer& lvalue = buffer;
753
754 if (dest->totalSize() <= INT_MAX - lvalue.size()
755 && (dest->numBuffers() < INT_MAX)) {
757 return 0; // RETURN
758 }
759 return -1;
760}
761
762inline
764{
765 BlobBuffer objectToMove(buffer);
766 return appendDataBufferIfValid(dest,
767 bslmf::MovableRefUtil::move(objectToMove));
768}
769
770inline
773{
774 // Last data buffer can be trimmed during appending new buffer. Therefore,
775 // the potentially allowed size of the added buffer should be adjusted
776 // accordingly.
777
778 BlobBuffer& lvalue = buffer;
779
780 const int TRIMMED_SIZE =
781 0 == dest->numDataBuffers()
782 ? 0
783 : dest->buffer(dest->numDataBuffers() - 1).size() -
784 dest->lastDataBufferLength();
785
786 if ((dest->totalSize() - TRIMMED_SIZE <= INT_MAX - lvalue.size())
787 && (dest->numBuffers() < INT_MAX)) {
788
790 return 0; // RETURN
791 }
792 return -1;
793}
794
795inline
797 int index,
798 const BlobBuffer& buffer)
799{
800 BlobBuffer objectToMove(buffer);
801 return insertBufferIfValid(dest,
802 index,
803 bslmf::MovableRefUtil::move(objectToMove));
804}
805
806inline
808 int index,
810{
811 BlobBuffer& lvalue = buffer;
812
813 if (0 <= index
814 && dest->numBuffers() >= index
815 && (dest->totalSize() <= INT_MAX - lvalue.size())
816 && (dest->numBuffers() < INT_MAX)) {
817 dest->insertBuffer(index, bslmf::MovableRefUtil::move(lvalue));
818 return 0; // RETURN
819 }
820 return -1;
821}
822
823inline
825{
826 BlobBuffer objectToMove(buffer);
827 return prependDataBufferIfValid(dest,
828 bslmf::MovableRefUtil::move(objectToMove));
829}
830
831inline
834{
835 BlobBuffer& lvalue = buffer;
836
837 int bufferSize = lvalue.size();
838 if ((dest->totalSize() <= INT_MAX - bufferSize)
839 && (dest->numBuffers() < INT_MAX)) {
841 return 0; // RETURN
842 }
843 return -1;
844}
845
846 // --------------------------
847 // struct BlobUtilAsciiDumper
848 // --------------------------
849
850// CREATORS
851inline
853: d_blob_p(blob)
854, d_offset(0)
855, d_length(blob->length())
856{
857}
858
859inline
861: d_blob_p(blob)
862, d_offset(0)
863, d_length(length)
864{
865 BSLS_ASSERT(0 <= length);
866}
867
868inline
870 int offset,
871 int length)
872: d_blob_p(blob)
873, d_offset(offset)
874, d_length(length)
875{
876 BSLS_ASSERT(0 <= offset);
877 BSLS_ASSERT(0 <= length);
878}
879} // close package namespace
880
881// FREE OPERATORS
882inline
883bsl::ostream& bdlbb::operator<<(bsl::ostream& stream,
884 const BlobUtilAsciiDumper& rhs)
885{
886 int offset = bsl::min(rhs.d_offset, rhs.d_blob_p->length());
887 int length = bsl::min(rhs.d_length, rhs.d_blob_p->length() - offset);
888 return BlobUtil::asciiDump(stream, *rhs.d_blob_p, offset, length);
889}
890
891namespace bdlbb {
892
893 // ------------------------
894 // struct BlobUtilHexDumper
895 // ------------------------
896
897// CREATORS
898inline
900: d_blob_p(blob)
901, d_offset(0)
902, d_length(blob->length())
903{
904}
905
906inline
908: d_blob_p(blob)
909, d_offset(0)
910, d_length(length)
911{
912 BSLS_ASSERT(0 <= length);
913}
914
915inline
916BlobUtilHexDumper::BlobUtilHexDumper(const Blob *blob, int offset, int length)
917: d_blob_p(blob)
918, d_offset(offset)
919, d_length(length)
920{
921 BSLS_ASSERT(0 <= offset);
922 BSLS_ASSERT(0 <= length);
923}
924} // close package namespace
925
926// FREE OPERATORS
927inline
928bsl::ostream& bdlbb::operator<<(bsl::ostream& stream,
929 const BlobUtilHexDumper& rhs)
930{
931 int offset = bsl::min(rhs.d_offset, rhs.d_blob_p->length());
932 int length = bsl::min(rhs.d_length, rhs.d_blob_p->length() - offset);
933 return BlobUtil::hexDump(stream, *rhs.d_blob_p, offset, length);
934}
935
936
937
938#endif
939
940// ----------------------------------------------------------------------------
941// Copyright 2018 Bloomberg Finance L.P.
942//
943// Licensed under the Apache License, Version 2.0 (the "License");
944// you may not use this file except in compliance with the License.
945// You may obtain a copy of the License at
946//
947// http://www.apache.org/licenses/LICENSE-2.0
948//
949// Unless required by applicable law or agreed to in writing, software
950// distributed under the License is distributed on an "AS IS" BASIS,
951// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
952// See the License for the specific language governing permissions and
953// limitations under the License.
954// ----------------------------- END-OF-FILE ----------------------------------
955
956/** @} */
957/** @} */
958/** @} */
Definition bdlbb_blob.h:616
Definition bdlbb_blob.h:455
bsl::shared_ptr< char > & buffer()
Definition bdlbb_blob.h:1094
char * data() const
Definition bdlbb_blob.h:1115
int size() const
Return the size of the buffer represented by this object.
Definition bdlbb_blob.h:1121
Definition bdlbb_blob.h:642
void prependDataBuffer(const BlobBuffer &buffer)
Definition bdlbb_blob.h:1171
int lastDataBufferLength() const
Definition bdlbb_blob.h:1214
int length() const
Return the length of this blob.
Definition bdlbb_blob.h:1220
int numDataBuffers() const
Return the number of blob buffers containing data in this blob.
Definition bdlbb_blob.h:1232
const BlobBuffer & buffer(int index) const
Definition bdlbb_blob.h:1199
void insertBuffer(int index, const BlobBuffer &buffer)
Definition bdlbb_blob.h:1164
int numBuffers() const
Return the number of blob buffers held by this blob.
Definition bdlbb_blob.h:1226
void appendDataBuffer(const BlobBuffer &buffer)
Definition bdlbb_blob.h:1157
void appendBuffer(const BlobBuffer &buffer)
Definition bdlbb_blob.h:1150
int totalSize() const
Definition bdlbb_blob.h:1238
void setLength(int length)
Definition bslstl_pair.h:1210
element_type * get() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_sharedptr.h:5574
Definition bslma_allocator.h:457
Definition bslmf_movableref.h:751
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_UNLIKELY_HINT
Definition bsls_performancehint.h:484
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdlbb_blob.h:442
bsl::ostream & operator<<(bsl::ostream &stream, const BlobBuffer &buffer)
Definition bdlbb_blobutil.h:443
int d_offset
Definition bdlbb_blobutil.h:447
const Blob * d_blob_p
Definition bdlbb_blobutil.h:446
BlobUtilAsciiDumper(const Blob *blob)
Definition bdlbb_blobutil.h:852
int d_length
Definition bdlbb_blobutil.h:448
Definition bdlbb_blobutil.h:489
int d_length
Definition bdlbb_blobutil.h:494
BlobUtilHexDumper(const Blob *blob)
Definition bdlbb_blobutil.h:899
const Blob * d_blob_p
Definition bdlbb_blobutil.h:492
int d_offset
Definition bdlbb_blobutil.h:493
Definition bdlbb_blobutil.h:81
static int insertBufferIfValid(Blob *dest, int index, const BlobBuffer &buffer)
Definition bdlbb_blobutil.h:796
static char * getContiguousDataBuffer(Blob *blob, int addLength, BlobBufferFactory *factory)
static int appendBufferIfValid(Blob *dest, const BlobBuffer &buffer)
Definition bdlbb_blobutil.h:741
static void copy(Blob *dst, int dstOffset, const char *src, int length)
static void append(Blob *dest, const Blob &source, int offset, int length)
static bsl::ostream & hexDump(bsl::ostream &stream, const Blob &source, int offset, int length)
static void append(Blob *dest, const char *source, int offset, int length)
static char * getContiguousRangeOrCopy(char *dstBuffer, const Blob &srcBlob, int position, int length, int alignment=1)
static int compare(const Blob &a, const Blob &b)
static STREAM & read(STREAM &stream, Blob *dest, int numBytes)
Definition bdlbb_blobutil.h:644
static bsl::ostream & asciiDump(bsl::ostream &stream, const Blob &source, int offset, int length)
static void copy(Blob *dst, int dstOffset, const Blob &src, int srcOffset, int length)
static STREAM & write(STREAM &stream, const Blob &source)
Definition bdlbb_blobutil.h:668
static int appendDataBufferIfValid(Blob *dest, const BlobBuffer &buffer)
Definition bdlbb_blobutil.h:763
static void padToAlignment(Blob *dest, int alignment, char fillChar='\0')
Definition bdlbb_blobutil.h:627
static bsl::ostream & hexDump(bsl::ostream &stream, const Blob &source)
Definition bdlbb_blobutil.h:621
static void erase(Blob *blob, int offset, int length)
static bsl::ostream & asciiDump(bsl::ostream &stream, const Blob &source)
static void appendWithCapacityBuffer(Blob *dest, BlobBuffer *buffer, const char *source, int length)
static void insert(Blob *dest, int destOffset, const Blob &source, int sourceOffset, int sourceLength)
static int prependDataBufferIfValid(Blob *dest, const BlobBuffer &buffer)
Definition bdlbb_blobutil.h:824
static bsl::pair< int, int > findBufferIndexAndOffset(const Blob &blob, int position)
static void append(Blob *dest, int length, char fill)
static void prependWithCapacityBuffer(Blob *dest, BlobBuffer *buffer, const char *source, int length)
static void copy(char *dstBuffer, const Blob &srcBlob, int position, int length)
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060