cord_buffer.h 22 KB

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