summaryrefslogtreecommitdiff
path: root/absl/strings/cord.cc
diff options
context:
space:
mode:
authorGravatar Derek Mauro <dmauro@google.com>2022-06-06 09:09:23 -0700
committerGravatar Copybara-Service <copybara-worker@google.com>2022-06-06 09:10:20 -0700
commit48419595d31609762985a6b08be504ebe6d593e7 (patch)
tree847b61bba7752ec3c7863f8f15484bea0d20a4ce /absl/strings/cord.cc
parent9cdb98e73118f0485fdf5fadcb3e57ab852e65a1 (diff)
Release absl::CordBuffer
absl::CordBuffer holds data for eventual inclusion within an existing absl::Cord. CordBuffers are useful for building large Cords that may require custom allocation of its associated memory, a pattern that is common in zero-copy APIs. PiperOrigin-RevId: 453212229 Change-Id: I6a8adc3a8d206691cb1b0001a9161e5080dd1c5f
Diffstat (limited to 'absl/strings/cord.cc')
-rw-r--r--absl/strings/cord.cc68
1 files changed, 68 insertions, 0 deletions
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc
index c6ec1ecf..04dc7b90 100644
--- a/absl/strings/cord.cc
+++ b/absl/strings/cord.cc
@@ -34,6 +34,7 @@
#include "absl/base/port.h"
#include "absl/container/fixed_array.h"
#include "absl/container/inlined_vector.h"
+#include "absl/strings/cord_buffer.h"
#include "absl/strings/escaping.h"
#include "absl/strings/internal/cord_data_edge.h"
#include "absl/strings/internal/cord_internal.h"
@@ -520,6 +521,46 @@ inline void Cord::AppendImpl(C&& src) {
contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord);
}
+static CordRep::ExtractResult ExtractAppendBuffer(CordRep* rep,
+ size_t min_capacity) {
+ switch (rep->tag) {
+ case cord_internal::BTREE:
+ return CordRepBtree::ExtractAppendBuffer(rep->btree(), min_capacity);
+ default:
+ if (rep->IsFlat() && rep->refcount.IsOne() &&
+ rep->flat()->Capacity() - rep->length >= min_capacity) {
+ return {nullptr, rep};
+ }
+ return {rep, nullptr};
+ }
+}
+
+static CordBuffer CreateAppendBuffer(InlineData& data, size_t capacity) {
+ // Watch out for overflow, people can ask for size_t::max().
+ const size_t size = data.inline_size();
+ capacity = (std::min)(std::numeric_limits<size_t>::max() - size, capacity);
+ CordBuffer buffer = CordBuffer::CreateWithDefaultLimit(size + capacity);
+ cord_internal::SmallMemmove(buffer.data(), data.as_chars(), size);
+ buffer.SetLength(size);
+ data = {};
+ return buffer;
+}
+
+CordBuffer Cord::GetAppendBufferSlowPath(size_t capacity, size_t min_capacity) {
+ auto constexpr method = CordzUpdateTracker::kGetAppendBuffer;
+ CordRep* tree = contents_.tree();
+ if (tree != nullptr) {
+ CordzUpdateScope scope(contents_.cordz_info(), method);
+ CordRep::ExtractResult result = ExtractAppendBuffer(tree, min_capacity);
+ if (result.extracted != nullptr) {
+ contents_.SetTreeOrEmpty(result.tree, scope);
+ return CordBuffer(result.extracted->flat());
+ }
+ return CordBuffer::CreateWithDefaultLimit(capacity);
+ }
+ return CreateAppendBuffer(contents_.data_, capacity);
+}
+
void Cord::Append(const Cord& src) {
AppendImpl(src);
}
@@ -572,6 +613,33 @@ void Cord::PrependArray(absl::string_view src, MethodIdentifier method) {
contents_.PrependTree(rep, method);
}
+void Cord::AppendPrecise(absl::string_view src, MethodIdentifier method) {
+ assert(!src.empty());
+ assert(src.size() <= cord_internal::kMaxFlatLength);
+ if (contents_.remaining_inline_capacity() >= src.size()) {
+ const size_t inline_length = contents_.inline_size();
+ memcpy(contents_.data_.as_chars() + inline_length, src.data(), src.size());
+ contents_.set_inline_size(inline_length + src.size());
+ } else {
+ contents_.AppendTree(CordRepFlat::Create(src), method);
+ }
+}
+
+void Cord::PrependPrecise(absl::string_view src, MethodIdentifier method) {
+ assert(!src.empty());
+ assert(src.size() <= cord_internal::kMaxFlatLength);
+ if (contents_.remaining_inline_capacity() >= src.size()) {
+ const size_t inline_length = contents_.inline_size();
+ char data[InlineRep::kMaxInline + 1] = {0};
+ memcpy(data, src.data(), src.size());
+ memcpy(data + src.size(), contents_.data(), inline_length);
+ memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1);
+ contents_.set_inline_size(inline_length + src.size());
+ } else {
+ contents_.PrependTree(CordRepFlat::Create(src), method);
+ }
+}
+
template <typename T, Cord::EnableIfString<T>>
inline void Cord::Prepend(T&& src) {
if (src.size() <= kMaxBytesToCopy) {