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