[#absl-CordBuffer-CreateWithCustomLimit] = xref:absl.adoc[absl]::xref:absl/CordBuffer.adoc[CordBuffer]::CreateWithCustomLimit :relfileprefix: ../../ :mrdocs: Creates a CordBuffer instance of the desired `capacity` rounded to an appropriate power of 2 size less than, or equal to `block_size`. Requires `block_size` to be a power of 2. == Synopsis Declared in `<absl/strings/cord_buffer.h>` [source,cpp,subs="verbatim,replacements,macros,-callouts"] ---- static xref:absl/CordBuffer.adoc[CordBuffer] CreateWithCustomLimit( size_t block_size, size_t capacity); ---- == Description If `capacity` is less than or equal to `kDefaultLimit`, then this method behaves identical to `CreateWithDefaultLimit`, which means that the caller is guaranteed to get a buffer of at least the requested capacity. If `capacity` is greater than or equal to `block_size`, then this method returns a buffer with an `allocated size` of `block_size` bytes. Otherwise, this methods returns a buffer with a suitable smaller power of 2 block size to satisfy the request. The actual size depends on a number of factors, and is typically (but not necessarily) the highest or second highest power of 2 value less than or equal to `capacity`. The 'allocated size' includes a small amount of overhead required for internal state, which is currently 13 bytes on 64‐bit platforms. For example: a buffer created with `block_size` and `capacity' set to 8KiB will have an allocated size of 8KiB, and an effective internal `capacity` of 8KiB ‐ 13 = 8179 bytes. To demonstrate this in practice, let's assume we want to read data from somewhat larger files using approximately 64KiB buffers: absl::Cord ReadFromFile(int fd, size_t n) { absl::Cord cord; while (n > 0) { CordBuffer buffer = CordBuffer::CreateWithCustomLimit(64 << 10, n); absl::Span<char> data = buffer.available_up_to(n); ReadFileDataOrDie(fd, data.data(), data.size()); buffer.IncreaseLengthBy(data.size()); cord.Append(std::move(buffer)); n ‐= data.size(); } return cord; } If we'd use this function to read a file of 659KiB, we may get the following pattern of allocated cord buffer sizes: CreateWithCustomLimit(64KiB, 674816) ‐‐> ~64KiB (65523) CreateWithCustomLimit(64KiB, 674816) ‐‐> ~64KiB (65523) ... CreateWithCustomLimit(64KiB, 19586) ‐‐> ~16KiB (16371) CreateWithCustomLimit(64KiB, 3215) ‐‐> 3215 (at least 3215) The reason the method returns a 16K buffer instead of a roughly 19K buffer is to reduce memory overhead and fragmentation risks. Using carefully chosen power of 2 values reduces the entropy of allocated memory sizes. Additionally, let's assume we'd use the above function on files that are generally smaller than 64K. If we'd use 'precise' sized buffers for such files, than we'd get a very wide distribution of allocated memory sizes rounded to 4K page sizes, and we'd end up with a lot of unused capacity. In general, application should only use custom sizes if the data they are consuming or storing is expected to be many times the chosen block size, and be based on objective data and performance metrics. For example, a compress function may work faster and consume less CPU when using larger buffers. Such an application should pick a size offering a reasonable trade‐off between expected data size, compute savings with larger buffers, and the cost or fragmentation effect of larger buffers. Applications must pick a reasonable spot on that curve, and make sure their data meets their expectations in size distributions such as "mostly large". == Return Value A new CordBuffer sized according to `block_size` and `capacity`. == Parameters [cols="1,4"] |=== | Name| Description | *block_size* | The power‐of‐2 upper bound on the allocated size. | *capacity* | The desired capacity of the buffer. |=== [.small]#Created with https://www.mrdocs.com[MrDocs]#