tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

cord_buffer.h (22786B)


      1 // Copyright 2021 The Abseil Authors
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 //
     15 // -----------------------------------------------------------------------------
     16 // File: cord_buffer.h
     17 // -----------------------------------------------------------------------------
     18 //
     19 // This file defines an `absl::CordBuffer` data structure to hold data for
     20 // eventual inclusion within an existing `Cord` data structure. Cord buffers are
     21 // useful for building large Cords that may require custom allocation of its
     22 // associated memory.
     23 //
     24 #ifndef ABSL_STRINGS_CORD_BUFFER_H_
     25 #define ABSL_STRINGS_CORD_BUFFER_H_
     26 
     27 #include <algorithm>
     28 #include <cassert>
     29 #include <cstddef>
     30 #include <cstdint>
     31 #include <memory>
     32 #include <utility>
     33 
     34 #include "absl/base/config.h"
     35 #include "absl/base/macros.h"
     36 #include "absl/numeric/bits.h"
     37 #include "absl/strings/internal/cord_internal.h"
     38 #include "absl/strings/internal/cord_rep_flat.h"
     39 #include "absl/types/span.h"
     40 
     41 namespace absl {
     42 ABSL_NAMESPACE_BEGIN
     43 
     44 class Cord;
     45 class CordBufferTestPeer;
     46 
     47 // CordBuffer
     48 //
     49 // CordBuffer manages memory buffers for purposes such as zero-copy APIs as well
     50 // as applications building cords with large data requiring granular control
     51 // over the allocation and size of cord data. For example, a function creating
     52 // a cord of random data could use a CordBuffer as follows:
     53 //
     54 //   absl::Cord CreateRandomCord(size_t length) {
     55 //     absl::Cord cord;
     56 //     while (length > 0) {
     57 //       CordBuffer buffer = CordBuffer::CreateWithDefaultLimit(length);
     58 //       absl::Span<char> data = buffer.available_up_to(length);
     59 //       FillRandomValues(data.data(), data.size());
     60 //       buffer.IncreaseLengthBy(data.size());
     61 //       cord.Append(std::move(buffer));
     62 //       length -= data.size();
     63 //     }
     64 //     return cord;
     65 //   }
     66 //
     67 // CordBuffer instances are by default limited to a capacity of `kDefaultLimit`
     68 // bytes. `kDefaultLimit` is currently just under 4KiB, but this default may
     69 // change in the future and/or for specific architectures. The default limit is
     70 // aimed to provide a good trade-off between performance and memory overhead.
     71 // Smaller buffers typically incur more compute cost while larger buffers are
     72 // more CPU efficient but create significant memory overhead because of such
     73 // allocations being less granular. Using larger buffers may also increase the
     74 // risk of memory fragmentation.
     75 //
     76 // Applications create a buffer using one of the `CreateWithDefaultLimit()` or
     77 // `CreateWithCustomLimit()` methods. The returned instance will have a non-zero
     78 // capacity and a zero length. Applications use the `data()` method to set the
     79 // contents of the managed memory, and once done filling the buffer, use the
     80 // `IncreaseLengthBy()` or 'SetLength()' method to specify the length of the
     81 // initialized data before adding the buffer to a Cord.
     82 //
     83 // The `CreateWithCustomLimit()` method is intended for applications needing
     84 // larger buffers than the default memory limit, allowing the allocation of up
     85 // to a capacity of `kCustomLimit` bytes minus some minimum internal overhead.
     86 // The usage of `CreateWithCustomLimit()` should be limited to only those use
     87 // cases where the distribution of the input is relatively well known, and/or
     88 // where the trade-off between the efficiency gains outweigh the risk of memory
     89 // fragmentation. See the documentation for `CreateWithCustomLimit()` for more
     90 // information on using larger custom limits.
     91 //
     92 // The capacity of a `CordBuffer` returned by one of the `Create` methods may
     93 // be larger than the requested capacity due to rounding, alignment and
     94 // granularity of the memory allocator. Applications should use the `capacity`
     95 // method to obtain the effective capacity of the returned instance as
     96 // demonstrated in the provided example above.
     97 //
     98 // CordBuffer is a move-only class. All references into the managed memory are
     99 // invalidated when an instance is moved into either another CordBuffer instance
    100 // or a Cord. Writing to a location obtained by a previous call to `data()`
    101 // after an instance was moved will lead to undefined behavior.
    102 //
    103 // A `moved from` CordBuffer instance will have a valid, but empty state.
    104 // CordBuffer is thread compatible.
    105 class CordBuffer {
    106 public:
    107  // kDefaultLimit
    108  //
    109  // Default capacity limits of allocated CordBuffers.
    110  // See the class comments for more information on allocation limits.
    111  static constexpr size_t kDefaultLimit = cord_internal::kMaxFlatLength;
    112 
    113  // kCustomLimit
    114  //
    115  // Maximum size for CreateWithCustomLimit() allocated buffers.
    116  // Note that the effective capacity may be slightly less
    117  // because of internal overhead of internal cord buffers.
    118  static constexpr size_t kCustomLimit = 64U << 10;
    119 
    120  // Constructors, Destructors and Assignment Operators
    121 
    122  // Creates an empty CordBuffer.
    123  CordBuffer() = default;
    124 
    125  // Destroys this CordBuffer instance and, if not empty, releases any memory
    126  // managed by this instance, invalidating previously returned references.
    127  ~CordBuffer();
    128 
    129  // CordBuffer is move-only
    130  CordBuffer(CordBuffer&& rhs) noexcept;
    131  CordBuffer& operator=(CordBuffer&&) noexcept;
    132  CordBuffer(const CordBuffer&) = delete;
    133  CordBuffer& operator=(const CordBuffer&) = delete;
    134 
    135  // CordBuffer::MaximumPayload()
    136  //
    137  // Returns the guaranteed maximum payload for a CordBuffer returned by the
    138  // `CreateWithDefaultLimit()` method. While small, each internal buffer inside
    139  // a Cord incurs an overhead to manage the length, type and reference count
    140  // for the buffer managed inside the cord tree. Applications can use this
    141  // method to get approximate number of buffers required for a given byte
    142  // size, etc.
    143  //
    144  // For example:
    145  //   const size_t payload = absl::CordBuffer::MaximumPayload();
    146  //   const size_t buffer_count = (total_size + payload - 1) / payload;
    147  //   buffers.reserve(buffer_count);
    148  static constexpr size_t MaximumPayload();
    149 
    150  // Overload to the above `MaximumPayload()` except that it returns the
    151  // maximum payload for a CordBuffer returned by the `CreateWithCustomLimit()`
    152  // method given the provided `block_size`.
    153  static constexpr size_t MaximumPayload(size_t block_size);
    154 
    155  // CordBuffer::CreateWithDefaultLimit()
    156  //
    157  // Creates a CordBuffer instance of the desired `capacity`, capped at the
    158  // default limit `kDefaultLimit`. The returned buffer has a guaranteed
    159  // capacity of at least `min(kDefaultLimit, capacity)`. See the class comments
    160  // for more information on buffer capacities and intended usage.
    161  static CordBuffer CreateWithDefaultLimit(size_t capacity);
    162 
    163  // CordBuffer::CreateWithCustomLimit()
    164  //
    165  // Creates a CordBuffer instance of the desired `capacity` rounded to an
    166  // appropriate power of 2 size less than, or equal to `block_size`.
    167  // Requires `block_size` to be a power of 2.
    168  //
    169  // If `capacity` is less than or equal to `kDefaultLimit`, then this method
    170  // behaves identical to `CreateWithDefaultLimit`, which means that the caller
    171  // is guaranteed to get a buffer of at least the requested capacity.
    172  //
    173  // If `capacity` is greater than or equal to `block_size`, then this method
    174  // returns a buffer with an `allocated size` of `block_size` bytes. Otherwise,
    175  // this methods returns a buffer with a suitable smaller power of 2 block size
    176  // to satisfy the request. The actual size depends on a number of factors, and
    177  // is typically (but not necessarily) the highest or second highest power of 2
    178  // value less than or equal to `capacity`.
    179  //
    180  // The 'allocated size' includes a small amount of overhead required for
    181  // internal state, which is currently 13 bytes on 64-bit platforms. For
    182  // example: a buffer created with `block_size` and `capacity' set to 8KiB
    183  // will have an allocated size of 8KiB, and an effective internal `capacity`
    184  // of 8KiB - 13 = 8179 bytes.
    185  //
    186  // To demonstrate this in practice, let's assume we want to read data from
    187  // somewhat larger files using approximately 64KiB buffers:
    188  //
    189  //   absl::Cord ReadFromFile(int fd, size_t n) {
    190  //     absl::Cord cord;
    191  //     while (n > 0) {
    192  //       CordBuffer buffer = CordBuffer::CreateWithCustomLimit(64 << 10, n);
    193  //       absl::Span<char> data = buffer.available_up_to(n);
    194  //       ReadFileDataOrDie(fd, data.data(), data.size());
    195  //       buffer.IncreaseLengthBy(data.size());
    196  //       cord.Append(std::move(buffer));
    197  //       n -= data.size();
    198  //     }
    199  //     return cord;
    200  //   }
    201  //
    202  // If we'd use this function to read a file of 659KiB, we may get the
    203  // following pattern of allocated cord buffer sizes:
    204  //
    205  //   CreateWithCustomLimit(64KiB, 674816) --> ~64KiB (65523)
    206  //   CreateWithCustomLimit(64KiB, 674816) --> ~64KiB (65523)
    207  //   ...
    208  //   CreateWithCustomLimit(64KiB,  19586) --> ~16KiB (16371)
    209  //   CreateWithCustomLimit(64KiB,   3215) -->   3215 (at least 3215)
    210  //
    211  // The reason the method returns a 16K buffer instead of a roughly 19K buffer
    212  // is to reduce memory overhead and fragmentation risks. Using carefully
    213  // chosen power of 2 values reduces the entropy of allocated memory sizes.
    214  //
    215  // Additionally, let's assume we'd use the above function on files that are
    216  // generally smaller than 64K. If we'd use 'precise' sized buffers for such
    217  // files, than we'd get a very wide distribution of allocated memory sizes
    218  // rounded to 4K page sizes, and we'd end up with a lot of unused capacity.
    219  //
    220  // In general, application should only use custom sizes if the data they are
    221  // consuming or storing is expected to be many times the chosen block size,
    222  // and be based on objective data and performance metrics. For example, a
    223  // compress function may work faster and consume less CPU when using larger
    224  // buffers. Such an application should pick a size offering a reasonable
    225  // trade-off between expected data size, compute savings with larger buffers,
    226  // and the cost or fragmentation effect of larger buffers.
    227  // Applications must pick a reasonable spot on that curve, and make sure their
    228  // data meets their expectations in size distributions such as "mostly large".
    229  static CordBuffer CreateWithCustomLimit(size_t block_size, size_t capacity);
    230 
    231  // CordBuffer::available()
    232  //
    233  // Returns the span delineating the available capacity in this buffer
    234  // which is defined as `{ data() + length(), capacity() - length() }`.
    235  absl::Span<char> available();
    236 
    237  // CordBuffer::available_up_to()
    238  //
    239  // Returns the span delineating the available capacity in this buffer limited
    240  // to `size` bytes. This is equivalent to `available().subspan(0, size)`.
    241  absl::Span<char> available_up_to(size_t size);
    242 
    243  // CordBuffer::data()
    244  //
    245  // Returns a non-null reference to the data managed by this instance.
    246  // Applications are allowed to write up to `capacity` bytes of instance data.
    247  // CordBuffer data is uninitialized by default. Reading data from an instance
    248  // that has not yet been initialized will lead to undefined behavior.
    249  char* data();
    250  const char* data() const;
    251 
    252  // CordBuffer::length()
    253  //
    254  // Returns the length of this instance. The default length of a CordBuffer is
    255  // 0, indicating an 'empty' CordBuffer. Applications must specify the length
    256  // of the data in a CordBuffer before adding it to a Cord.
    257  size_t length() const;
    258 
    259  // CordBuffer::capacity()
    260  //
    261  // Returns the capacity of this instance. All instances have a non-zero
    262  // capacity: default and `moved from` instances have a small internal buffer.
    263  size_t capacity() const;
    264 
    265  // CordBuffer::IncreaseLengthBy()
    266  //
    267  // Increases the length of this buffer by the specified 'n' bytes.
    268  // Applications must make sure all data in this buffer up to the new length
    269  // has been initialized before adding a CordBuffer to a Cord: failure to do so
    270  // will lead to undefined behavior.  Requires `length() + n <= capacity()`.
    271  // Typically, applications will use 'available_up_to()` to get a span of the
    272  // desired capacity, and use `span.size()` to increase the length as in:
    273  //   absl::Span<char> span = buffer.available_up_to(desired);
    274  //   buffer.IncreaseLengthBy(span.size());
    275  //   memcpy(span.data(), src, span.size());
    276  //   etc...
    277  void IncreaseLengthBy(size_t n);
    278 
    279  // CordBuffer::SetLength()
    280  //
    281  // Sets the data length of this instance. Applications must make sure all data
    282  // of the specified length has been initialized before adding a CordBuffer to
    283  // a Cord: failure to do so will lead to undefined behavior.
    284  // Setting the length to a small value or zero does not release any memory
    285  // held by this CordBuffer instance. Requires `length <= capacity()`.
    286  // Applications should preferably use the `IncreaseLengthBy()` method above
    287  // in combination with the 'available()` or `available_up_to()` methods.
    288  void SetLength(size_t length);
    289 
    290 private:
    291  // Make sure we don't accidentally over promise.
    292  static_assert(kCustomLimit <= cord_internal::kMaxLargeFlatSize, "");
    293 
    294  // Assume the cost of an 'uprounded' allocation to CeilPow2(size) versus
    295  // the cost of allocating at least 1 extra flat <= 4KB:
    296  // - Flat overhead = 13 bytes
    297  // - Btree amortized cost / node =~ 13 bytes
    298  // - 64 byte granularity of tcmalloc at 4K =~ 32 byte average
    299  // CPU cost and efficiency requires we should at least 'save' something by
    300  // splitting, as a poor man's measure, we say the slop needs to be
    301  // at least double the cost offset to make it worth splitting: ~128 bytes.
    302  static constexpr size_t kMaxPageSlop = 128;
    303 
    304  // Overhead for allocation a flat.
    305  static constexpr size_t kOverhead = cord_internal::kFlatOverhead;
    306 
    307  using CordRepFlat = cord_internal::CordRepFlat;
    308 
    309  // `Rep` is the internal data representation of a CordBuffer. The internal
    310  // representation has an internal small size optimization similar to
    311  // std::string (SSO).
    312  struct Rep {
    313    // Inline SSO size of a CordBuffer
    314    static constexpr size_t kInlineCapacity = sizeof(intptr_t) * 2 - 1;
    315 
    316    // Creates a default instance with kInlineCapacity.
    317    Rep() : short_rep{} {}
    318 
    319    // Creates an instance managing an allocated non zero CordRep.
    320    explicit Rep(cord_internal::CordRepFlat* rep) : long_rep{rep} {
    321      assert(rep != nullptr);
    322    }
    323 
    324    // Returns true if this instance manages the SSO internal buffer.
    325    bool is_short() const {
    326      constexpr size_t offset = offsetof(Short, raw_size);
    327      return (reinterpret_cast<const char*>(this)[offset] & 1) != 0;
    328    }
    329 
    330    // Returns the available area of the internal SSO data
    331    absl::Span<char> short_available() {
    332      const size_t length = short_length();
    333      return absl::Span<char>(short_rep.data + length,
    334                              kInlineCapacity - length);
    335    }
    336 
    337    // Returns the available area of the internal SSO data
    338    absl::Span<char> long_available() const {
    339      assert(!is_short());
    340      const size_t length = long_rep.rep->length;
    341      return absl::Span<char>(long_rep.rep->Data() + length,
    342                              long_rep.rep->Capacity() - length);
    343    }
    344 
    345    // Returns the length of the internal SSO data.
    346    size_t short_length() const {
    347      assert(is_short());
    348      return static_cast<size_t>(short_rep.raw_size >> 1);
    349    }
    350 
    351    // Sets the length of the internal SSO data.
    352    // Disregards any previously set CordRep instance.
    353    void set_short_length(size_t length) {
    354      short_rep.raw_size = static_cast<char>((length << 1) + 1);
    355    }
    356 
    357    // Adds `n` to the current short length.
    358    void add_short_length(size_t n) {
    359      assert(is_short());
    360      short_rep.raw_size += static_cast<char>(n << 1);
    361    }
    362 
    363    // Returns reference to the internal SSO data buffer.
    364    char* data() {
    365      assert(is_short());
    366      return short_rep.data;
    367    }
    368    const char* data() const {
    369      assert(is_short());
    370      return short_rep.data;
    371    }
    372 
    373    // Returns a pointer the external CordRep managed by this instance.
    374    cord_internal::CordRepFlat* rep() const {
    375      assert(!is_short());
    376      return long_rep.rep;
    377    }
    378 
    379    // The internal representation takes advantage of the fact that allocated
    380    // memory is always on an even address, and uses the least significant bit
    381    // of the first or last byte (depending on endianness) as the inline size
    382    // indicator overlapping with the least significant byte of the CordRep*.
    383 #if defined(ABSL_IS_BIG_ENDIAN)
    384    struct Long {
    385      explicit Long(cord_internal::CordRepFlat* rep_arg) : rep(rep_arg) {}
    386      void* padding;
    387      cord_internal::CordRepFlat* rep;
    388    };
    389    struct Short {
    390      char data[sizeof(Long) - 1];
    391      char raw_size = 1;
    392    };
    393 #else
    394    struct Long {
    395      explicit Long(cord_internal::CordRepFlat* rep_arg) : rep(rep_arg) {}
    396      cord_internal::CordRepFlat* rep;
    397      void* padding;
    398    };
    399    struct Short {
    400      char raw_size = 1;
    401      char data[sizeof(Long) - 1];
    402    };
    403 #endif
    404 
    405    union {
    406      Long long_rep;
    407      Short short_rep;
    408    };
    409  };
    410 
    411  // Power2 functions
    412  static bool IsPow2(size_t size) { return absl::has_single_bit(size); }
    413  static size_t Log2Floor(size_t size) {
    414    return static_cast<size_t>(absl::bit_width(size) - 1);
    415  }
    416  static size_t Log2Ceil(size_t size) {
    417    return static_cast<size_t>(absl::bit_width(size - 1));
    418  }
    419 
    420  // Implementation of `CreateWithCustomLimit()`.
    421  // This implementation allows for future memory allocation hints to
    422  // be passed down into the CordRepFlat allocation function.
    423  template <typename... AllocationHints>
    424  static CordBuffer CreateWithCustomLimitImpl(size_t block_size,
    425                                              size_t capacity,
    426                                              AllocationHints... hints);
    427 
    428  // Consumes the value contained in this instance and resets the instance.
    429  // This method returns a non-null Cordrep* if the current instances manages a
    430  // CordRep*, and resets the instance to an empty SSO instance. If the current
    431  // instance is an SSO instance, then this method returns nullptr and sets
    432  // `short_value` to the inlined data value. In either case, the current
    433  // instance length is reset to zero.
    434  // This method is intended to be used by Cord internal functions only.
    435  cord_internal::CordRep* ConsumeValue(absl::string_view& short_value) {
    436    cord_internal::CordRep* rep = nullptr;
    437    if (rep_.is_short()) {
    438      short_value = absl::string_view(rep_.data(), rep_.short_length());
    439    } else {
    440      rep = rep_.rep();
    441    }
    442    rep_.set_short_length(0);
    443    return rep;
    444  }
    445 
    446  // Internal constructor.
    447  explicit CordBuffer(cord_internal::CordRepFlat* rep) : rep_(rep) {
    448    assert(rep != nullptr);
    449  }
    450 
    451  Rep rep_;
    452 
    453  friend class Cord;
    454  friend class CordBufferTestPeer;
    455 };
    456 
    457 inline constexpr size_t CordBuffer::MaximumPayload() {
    458  return cord_internal::kMaxFlatLength;
    459 }
    460 
    461 inline constexpr size_t CordBuffer::MaximumPayload(size_t block_size) {
    462  return (std::min)(kCustomLimit, block_size) - cord_internal::kFlatOverhead;
    463 }
    464 
    465 inline CordBuffer CordBuffer::CreateWithDefaultLimit(size_t capacity) {
    466  if (capacity > Rep::kInlineCapacity) {
    467    auto* rep = cord_internal::CordRepFlat::New(capacity);
    468    rep->length = 0;
    469    return CordBuffer(rep);
    470  }
    471  return CordBuffer();
    472 }
    473 
    474 template <typename... AllocationHints>
    475 inline CordBuffer CordBuffer::CreateWithCustomLimitImpl(
    476    size_t block_size, size_t capacity, AllocationHints... hints) {
    477  assert(IsPow2(block_size));
    478  capacity = (std::min)(capacity, kCustomLimit);
    479  block_size = (std::min)(block_size, kCustomLimit);
    480  if (capacity + kOverhead >= block_size) {
    481    capacity = block_size;
    482  } else if (capacity <= kDefaultLimit) {
    483    capacity = capacity + kOverhead;
    484  } else if (!IsPow2(capacity)) {
    485    // Check if rounded up to next power 2 is a good enough fit
    486    // with limited waste making it an acceptable direct fit.
    487    const size_t rounded_up = size_t{1} << Log2Ceil(capacity);
    488    const size_t slop = rounded_up - capacity;
    489    if (slop >= kOverhead && slop <= kMaxPageSlop + kOverhead) {
    490      capacity = rounded_up;
    491    } else {
    492      // Round down to highest power of 2 <= capacity.
    493      // Consider a more aggressive step down if that may reduce the
    494      // risk of fragmentation where 'people are holding it wrong'.
    495      const size_t rounded_down = size_t{1} << Log2Floor(capacity);
    496      capacity = rounded_down;
    497    }
    498  }
    499  const size_t length = capacity - kOverhead;
    500  auto* rep = CordRepFlat::New(CordRepFlat::Large(), length, hints...);
    501  rep->length = 0;
    502  return CordBuffer(rep);
    503 }
    504 
    505 inline CordBuffer CordBuffer::CreateWithCustomLimit(size_t block_size,
    506                                                    size_t capacity) {
    507  return CreateWithCustomLimitImpl(block_size, capacity);
    508 }
    509 
    510 inline CordBuffer::~CordBuffer() {
    511  if (!rep_.is_short()) {
    512    cord_internal::CordRepFlat::Delete(rep_.rep());
    513  }
    514 }
    515 
    516 inline CordBuffer::CordBuffer(CordBuffer&& rhs) noexcept : rep_(rhs.rep_) {
    517  rhs.rep_.set_short_length(0);
    518 }
    519 
    520 inline CordBuffer& CordBuffer::operator=(CordBuffer&& rhs) noexcept {
    521  if (!rep_.is_short()) cord_internal::CordRepFlat::Delete(rep_.rep());
    522  rep_ = rhs.rep_;
    523  rhs.rep_.set_short_length(0);
    524  return *this;
    525 }
    526 
    527 inline absl::Span<char> CordBuffer::available() {
    528  return rep_.is_short() ? rep_.short_available() : rep_.long_available();
    529 }
    530 
    531 inline absl::Span<char> CordBuffer::available_up_to(size_t size) {
    532  return available().subspan(0, size);
    533 }
    534 
    535 inline char* CordBuffer::data() {
    536  return rep_.is_short() ? rep_.data() : rep_.rep()->Data();
    537 }
    538 
    539 inline const char* CordBuffer::data() const {
    540  return rep_.is_short() ? rep_.data() : rep_.rep()->Data();
    541 }
    542 
    543 inline size_t CordBuffer::capacity() const {
    544  return rep_.is_short() ? Rep::kInlineCapacity : rep_.rep()->Capacity();
    545 }
    546 
    547 inline size_t CordBuffer::length() const {
    548  return rep_.is_short() ? rep_.short_length() : rep_.rep()->length;
    549 }
    550 
    551 inline void CordBuffer::SetLength(size_t length) {
    552  ABSL_HARDENING_ASSERT(length <= capacity());
    553  if (rep_.is_short()) {
    554    rep_.set_short_length(length);
    555  } else {
    556    rep_.rep()->length = length;
    557  }
    558 }
    559 
    560 inline void CordBuffer::IncreaseLengthBy(size_t n) {
    561  ABSL_HARDENING_ASSERT(n <= capacity() && length() + n <= capacity());
    562  if (rep_.is_short()) {
    563    rep_.add_short_length(n);
    564  } else {
    565    rep_.rep()->length += n;
    566  }
    567 }
    568 
    569 ABSL_NAMESPACE_END
    570 }  // namespace absl
    571 
    572 #endif  // ABSL_STRINGS_CORD_BUFFER_H_