diff --git a/src/groups/bmq/bmqp/bmqp_messageproperties.cpp b/src/groups/bmq/bmqp/bmqp_messageproperties.cpp index aeae9be2e3..cf3f01853c 100644 --- a/src/groups/bmq/bmqp/bmqp_messageproperties.cpp +++ b/src/groups/bmq/bmqp/bmqp_messageproperties.cpp @@ -259,108 +259,84 @@ bool MessageProperties::streamInPropertyValue(const Property& p) const BSLS_ASSERT_SAFE(p.d_value.isUnset()); BSLS_ASSERT_SAFE(p.d_offset); - bmqu::BlobPosition position; - int rc = bmqu::BlobUtil::findOffsetSafe(&position, *d_blob_p, p.d_offset); - BSLS_ASSERT_SAFE(rc == 0); + bmqu::BlobSection section; + const int rc = bmqu::BlobUtil::findBlobSectionSafe(§ion, + *d_blob_p, + bmqu::BlobPosition(), + p.d_offset, + p.d_length); + if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(0 != rc)) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + return false; // RETURN + } switch (p.d_type) { case bmqt::PropertyType::e_BOOL: { char value; - rc = bmqu::BlobUtil::readNBytes(&value, - *d_blob_p, - position, - sizeof(value)); - + section.readTo(&value, *d_blob_p, sizeof(char)); p.d_value = value == 1 ? true : false; break; } case bmqt::PropertyType::e_CHAR: { char value; - rc = bmqu::BlobUtil::readNBytes(&value, - *d_blob_p, - position, - sizeof(value)); - + section.readTo(&value, *d_blob_p, sizeof(char)); p.d_value = value; break; } case bmqt::PropertyType::e_SHORT: { bdlb::BigEndianInt16 nboValue; - rc = bmqu::BlobUtil::readNBytes(reinterpret_cast(&nboValue), - *d_blob_p, - position, - sizeof(nboValue)); - + section.readTo(reinterpret_cast(&nboValue), + *d_blob_p, + sizeof(bdlb::BigEndianInt16)); p.d_value = static_cast(nboValue); break; } case bmqt::PropertyType::e_INT32: { bdlb::BigEndianInt32 nboValue; - rc = bmqu::BlobUtil::readNBytes(reinterpret_cast(&nboValue), - *d_blob_p, - position, - sizeof(nboValue)); - + section.readTo(reinterpret_cast(&nboValue), + *d_blob_p, + sizeof(bdlb::BigEndianInt32)); p.d_value = static_cast(nboValue); break; } case bmqt::PropertyType::e_INT64: { bdlb::BigEndianInt64 nboValue; - rc = bmqu::BlobUtil::readNBytes(reinterpret_cast(&nboValue), - *d_blob_p, - position, - sizeof(nboValue)); - + section.readTo(reinterpret_cast(&nboValue), + *d_blob_p, + sizeof(bdlb::BigEndianInt64)); p.d_value = static_cast(nboValue); break; } - case bmqt::PropertyType::e_STRING: { // Try to avoid copying the string. 'd_blop' already keeps a copy. - bmqu::BlobPosition end; - const int ret = - bmqu::BlobUtil::findOffset(&end, *d_blob_p, position, p.d_length); - bool doCopy = true; - if (ret == 0) { - // Do not align - if (bmqu::BlobUtil::isDataContinuous(position, end)) { - // Section is good - char* start = d_blob_p->buffer(position.buffer()).data() + - position.byte(); - - p.d_value = bsl::string_view(start, p.d_length); - doCopy = false; - } + if (section.isDataContinuous()) { + // Shallow copy + const bmqu::BlobPosition& start = section.start(); + char* data = d_blob_p->buffer(start.buffer()).data() + + start.byte(); + p.d_value = bsl::string_view(data, p.d_length); } - if (doCopy) { - bsl::string value(p.d_length, ' ', d_allocator_p); - rc = bmqu::BlobUtil::readNBytes(&value[0], - *d_blob_p, - position, - p.d_length); - p.d_value = value; + else { + bsl::string copy(p.d_length, ' ', d_allocator_p); + section.readTo(copy.data(), *d_blob_p, p.d_length); + p.d_value = bslmf::MovableRefUtil::move(copy); } break; } case bmqt::PropertyType::e_BINARY: { - bsl::vector value(p.d_length, d_allocator_p); - rc = bmqu::BlobUtil::readNBytes(&value[0], - *d_blob_p, - position, - p.d_length); - - p.d_value = value; + bsl::vector copy(p.d_length, d_allocator_p); + section.readTo(copy.data(), *d_blob_p, p.d_length); + p.d_value = bslmf::MovableRefUtil::move(copy); break; } - case bmqt::PropertyType::e_UNDEFINED: + case bmqt::PropertyType::e_UNDEFINED: BSLA_FALLTHROUGH; default: BSLS_ASSERT_OPT(0 && "Invalid data type for property value."); - rc = -1; - break; // BREAK + return false; } - return rc == 0; + return true; } // CREATORS diff --git a/src/groups/bmq/bmqu/bmqu_blob.h b/src/groups/bmq/bmqu/bmqu_blob.h index a63a8eaec1..e93d34ab8d 100644 --- a/src/groups/bmq/bmqu/bmqu_blob.h +++ b/src/groups/bmq/bmqu/bmqu_blob.h @@ -33,6 +33,7 @@ // BDE #include +#include // for bsl::memcpy #include namespace BloombergLP { @@ -141,6 +142,14 @@ class BlobSection { /// Return the end position of the section. const BlobPosition& end() const; + /// @brief Check if the data segment pointed at by this object + /// is continous (placed in the same blob buffer). + /// @return true if the segment is continuous, false otherwise. + /// NOTE: this function doesn't check if blob positions are valid. + bool isDataContinuous() const; + + void readTo(char* buf, const bdlbb::Blob& blob, size_t numBytes) const; + /// Write the string representation of this object to the specified /// output `stream`, and return a reference to `stream`. Optionally /// specify an initial indentation `level`, whose absolute value is @@ -208,6 +217,12 @@ struct BlobUtil { const BlobPosition& start, int offset); + static int findBlobSectionSafe(BlobSection* section, + const bdlbb::Blob& blob, + const BlobPosition& start, + int offset, + int length); + /// Return `true` if the specified `section` is a valid section of the /// specified `blob`, and `false` otherwise. A section is valid if /// `section.start() < section.end()` and both the start and the end @@ -215,15 +230,6 @@ struct BlobUtil { static bool isValidSection(const bdlbb::Blob& blob, const BlobSection& section); - /// @brief Check if the data segment defined by `start` and `end` - /// positions is continous (placed in the same blob buffer). - /// @param start the start position in a blob - /// @param end the end position in a blob - /// @return true if the segment is continuous, false otherwise. - /// NOTE: this function doesn't check if blob positions are valid. - static bool isDataContinuous(const bmqu::BlobPosition& start, - const bmqu::BlobPosition& end); - /// Find the distance from the specified `section`s `start()` to the /// `section`s `end()` in the specified `blob` and return it in the /// specified `size`. Return `0` on success or a negative value if the @@ -553,6 +559,29 @@ inline const BlobPosition& BlobSection::end() const return d_end; } +inline bool BlobSection::isDataContinuous() const +{ + return (d_start.buffer() == d_end.buffer() || + (d_start.buffer() + 1 == d_end.buffer() && d_end.byte() == 0)); +} + +inline void +BlobSection::readTo(char* buf, const bdlbb::Blob& blob, size_t numBytes) const +{ + // PRECONDITIONS + BSLS_ASSERT_SAFE(buf); + + if (isDataContinuous()) { + bsl::memcpy(buf, + blob.buffer(d_start.buffer()).data() + d_start.byte(), + numBytes); + } + else { + // Rare path + bmqu::BlobUtil::readNBytes(buf, blob, d_start, numBytes); + } +} + // --------------- // struct BlobUtil // --------------- @@ -593,6 +622,37 @@ BlobUtil::findOffset(BlobPosition* pos, const bdlbb::Blob& blob, int offset) return findOffset(pos, blob, BlobPosition(), offset); } +inline int BlobUtil::findBlobSectionSafe(BlobSection* section, + const bdlbb::Blob& blob, + const BlobPosition& start, + int offset, + int length) +{ + // PRECONDITIONS + BSLS_ASSERT_SAFE(section); + + // Check if 'start' is a valid position in the blob. + if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(!isValidPos(blob, start))) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + return -1; // RETURN + } + + if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( + 0 != findOffset(§ion->start(), blob, start, offset))) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + return -2; // RETURN + } + + if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( + 0 != + findOffset(§ion->end(), blob, section->start(), length))) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + return -2; // RETURN + } + + return 0; +} + inline int BlobUtil::positionToOffsetSafe(int* offset, const bdlbb::Blob& blob, const BlobPosition& position) @@ -640,13 +700,6 @@ TYPE* BlobUtil::getAlignedObject(TYPE* storage, copyFromBlob)); } -inline bool BlobUtil::isDataContinuous(const bmqu::BlobPosition& start, - const bmqu::BlobPosition& end) -{ - return (start.buffer() == end.buffer() || - (start.buffer() + 1 == end.buffer() && end.byte() == 0)); -} - } // close package namespace // FREE OPERATORS