// Copyright 2021 The Abseil Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: cord_buffer.h // ----------------------------------------------------------------------------- // // This file defines an `absl::CordBuffer` data structure to hold data for // eventual inclusion within an existing `Cord` data structure. Cord buffers are // useful for building large Cords that may require custom allocation of its // associated memory. // #ifndef ABSL_STRINGS_CORD_BUFFER_H_ #define ABSL_STRINGS_CORD_BUFFER_H_ #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> #include <memory> #include <utility> #include "absl/base/config.h" #include "absl/base/macros.h" #include "absl/numeric/bits.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/types/span.h" namespace absl { ABSL_NAMESPACE_BEGIN class Cord; class CordBufferTestPeer; // CordBuffer // // CordBuffer manages memory buffers for purposes such as zero-copy APIs as well // as applications building cords with large data requiring granular control // over the allocation and size of cord data. For example, a function creating // a cord of random data could use a CordBuffer as follows: // // absl::Cord CreateRandomCord(size_t length) { // absl::Cord cord; // while (length > 0) { // CordBuffer buffer = CordBuffer::CreateWithDefaultLimit(length); // absl::Span<char> data = buffer.available_up_to(length); // FillRandomValues(data.data(), data.size()); // buffer.IncreaseLengthBy(data.size()); // cord.Append(std::move(buffer)); // length -= data.size(); // } // return cord; // } // // CordBuffer instances are by default limited to a capacity of `kDefaultLimit` // bytes. `kDefaultLimit` is currently just under 4KiB, but this default may // change in the future and/or for specific architectures. The default limit is // aimed to provide a good trade-off between performance and memory overhead. // Smaller buffers typically incur more compute cost while larger buffers are // more CPU efficient but create significant memory overhead because of such // allocations being less granular. Using larger buffers may also increase the // risk of memory fragmentation. // // Applications create a buffer using one of the `CreateWithDefaultLimit()` or // `CreateWithCustomLimit()` methods. The returned instance will have a non-zero // capacity and a zero length. Applications use the `data()` method to set the // contents of the managed memory, and once done filling the buffer, use the // `IncreaseLengthBy()` or 'SetLength()' method to specify the length of the // initialized data before adding the buffer to a Cord. // // The `CreateWithCustomLimit()` method is intended for applications needing // larger buffers than the default memory limit, allowing the allocation of up // to a capacity of `kCustomLimit` bytes minus some minimum internal overhead. // The usage of `CreateWithCustomLimit()` should be limited to only those use // cases where the distribution of the input is relatively well known, and/or // where the trade-off between the efficiency gains outweigh the risk of memory // fragmentation. See the documentation for `CreateWithCustomLimit()` for more // information on using larger custom limits. // // The capacity of a `CordBuffer` returned by one of the `Create` methods may // be larger than the requested capacity due to rounding, alignment and // granularity of the memory allocator. Applications should use the `capacity` // method to obtain the effective capacity of the returned instance as // demonstrated in the provided example above. // // CordBuffer is a move-only class. All references into the managed memory are // invalidated when an instance is moved into either another CordBuffer instance // or a Cord. Writing to a location obtained by a previous call to `data()` // after an instance was moved will lead to undefined behavior. // // A `moved from` CordBuffer instance will have a valid, but empty state. // CordBuffer is thread compatible. class CordBuffer { … }; inline constexpr size_t CordBuffer::MaximumPayload() { … } inline constexpr size_t CordBuffer::MaximumPayload(size_t block_size) { … } inline CordBuffer CordBuffer::CreateWithDefaultLimit(size_t capacity) { … } template <typename... AllocationHints> inline CordBuffer CordBuffer::CreateWithCustomLimitImpl( size_t block_size, size_t capacity, AllocationHints... hints) { … } inline CordBuffer CordBuffer::CreateWithCustomLimit(size_t block_size, size_t capacity) { … } inline CordBuffer::~CordBuffer() { … } inline CordBuffer::CordBuffer(CordBuffer&& rhs) noexcept : … { … } inline CordBuffer& CordBuffer::operator=(CordBuffer&& rhs) noexcept { … } inline absl::Span<char> CordBuffer::available() { … } inline absl::Span<char> CordBuffer::available_up_to(size_t size) { … } inline char* CordBuffer::data() { … } inline const char* CordBuffer::data() const { … } inline size_t CordBuffer::capacity() const { … } inline size_t CordBuffer::length() const { … } inline void CordBuffer::SetLength(size_t length) { … } inline void CordBuffer::IncreaseLengthBy(size_t n) { … } ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CORD_BUFFER_H_