Go to the documentation of this file.
15 #include "absl/strings/cord.h"
27 #include <type_traits>
28 #include <unordered_set>
31 #include "absl/base/casts.h"
32 #include "absl/base/internal/raw_logging.h"
33 #include "absl/base/macros.h"
34 #include "absl/base/port.h"
35 #include "absl/container/fixed_array.h"
36 #include "absl/container/inlined_vector.h"
38 #include "absl/strings/escaping.h"
40 #include "absl/strings/internal/cord_internal.h"
43 #include "absl/strings/internal/cord_rep_flat.h"
44 #include "absl/strings/internal/cordz_statistics.h"
45 #include "absl/strings/internal/cordz_update_scope.h"
46 #include "absl/strings/internal/cordz_update_tracker.h"
47 #include "absl/strings/internal/resize_uninitialized.h"
48 #include "absl/strings/str_cat.h"
49 #include "absl/strings/str_format.h"
50 #include "absl/strings/str_join.h"
51 #include "absl/strings/string_view.h"
56 using ::absl::cord_internal::CordRep;
57 using ::absl::cord_internal::CordRepBtree;
58 using ::absl::cord_internal::CordRepCrc;
59 using ::absl::cord_internal::CordRepExternal;
60 using ::absl::cord_internal::CordRepFlat;
61 using ::absl::cord_internal::CordRepSubstring;
62 using ::absl::cord_internal::CordzUpdateTracker;
63 using ::absl::cord_internal::InlineData;
70 static void DumpNode(CordRep*
rep,
bool include_data, std::ostream* os,
73 bool full_validation);
81 #ifdef EXTRA_CORD_VALIDATION
82 assert(node ==
nullptr ||
VerifyNode(node, node,
true));
83 #else // EXTRA_CORD_VALIDATION
84 assert(node ==
nullptr ||
VerifyNode(node, node,
false));
85 #endif // EXTRA_CORD_VALIDATION
108 auto*
root = CordRepBtree::Create(flat);
115 if (
length == 0)
return nullptr;
119 namespace cord_internal {
122 assert(!
data.empty());
141 src.size() < src.capacity() / 2
143 return NewTree(src.data(), src.size(), 0);
146 struct StringReleaser {
156 rep->base =
rep->template get<0>().data.data();
163 #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
168 static_assert(
kMaxInline == 15,
"set_data is hard-coded for a length of 15");
178 return data_.as_chars();
182 size_t tag = inline_size();
187 set_inline_size(
static_cast<char>(
tag));
207 if (!
data_.is_empty()) {
211 EmplaceTree(tree,
method);
218 SetTree(tree, scope);
222 assert(tree !=
nullptr);
223 assert(tree->
length != 0);
224 assert(!tree->
IsCrc());
225 if (
data_.is_tree()) {
226 AppendTreeToTree(tree,
method);
228 AppendTreeToInlined(tree,
method);
235 if (!
data_.is_empty()) {
237 tree = CordRepBtree::Prepend(CordRepBtree::Create(flat), tree);
239 EmplaceTree(tree,
method);
247 SetTree(tree, scope);
251 assert(tree !=
nullptr);
252 assert(tree->
length != 0);
253 assert(!tree->
IsCrc());
254 if (
data_.is_tree()) {
255 PrependTreeToTree(tree,
method);
257 PrependTreeToInlined(tree,
method);
266 size_t*
size,
size_t max_length) {
267 if (
root->IsBtree() &&
root->refcount.IsOne()) {
270 *region = span.
data();
277 if (!
dst->IsFlat() || !
dst->refcount.IsOne()) {
292 dst->length += size_increase;
295 *
size = size_increase;
300 assert(&src !=
this);
301 assert(is_tree() || src.
is_tree());
333 const size_t n = src.
size();
342 template <
typename T, Cord::EnableIfString<T>>
400 if (tree !=
nullptr) {
422 if (src.
empty())
return;
428 if (
root !=
nullptr) {
448 appended =
std::min(src.
size(),
rep->flat()->Capacity() - inline_length);
450 memcpy(
rep->flat()->Data() + inline_length, src.
data(), appended);
451 rep->length = inline_length + appended;
462 const size_t min_growth = std::max<size_t>(
rep->length / 10, src.
size());
478 template <
typename C>
483 if (src.contents_.is_tree()) {
496 const size_t src_size = src.contents_.size();
498 CordRep* src_tree = src.contents_.tree();
499 if (src_tree ==
nullptr) {
527 size_t min_capacity) {
534 return {
nullptr,
rep};
536 return {
rep,
nullptr};
542 const size_t size =
data.inline_size();
554 if (tree !=
nullptr) {
557 if (
result.extracted !=
nullptr) {
574 template <
typename T, Cord::EnableIfString<T>>
588 if (src_tree !=
nullptr) {
601 if (src.
empty())
return;
619 assert(!src.
empty());
631 assert(!src.
empty());
645 template <
typename T, Cord::EnableIfString<T>>
660 " exceeds Cord's size ",
size()));
662 if (tree ==
nullptr) {
690 " exceeds Cord's size ",
size()));
692 if (tree ==
nullptr) {
723 if (tree ==
nullptr) {
731 it.AdvanceBytes(
pos);
733 while (remaining_size >
it->size()) {
735 remaining_size -=
it->size();
748 tree = CordRepSubstring::Substring(tree,
pos,
new_size);
760 int ClampResult(
int memcmp_res) {
761 return static_cast<int>(memcmp_res > 0) -
static_cast<int>(memcmp_res < 0);
765 size_t* size_to_compare) {
767 assert(*size_to_compare >= compared_size);
768 *size_to_compare -= compared_size;
770 int memcmp_res = ::memcmp(lhs->
data(), rhs->
data(), compared_size);
771 if (memcmp_res != 0)
return memcmp_res;
783 template <
typename ResultType>
784 ResultType ComputeCompareResult(
int memcmp_res) {
785 return ClampResult(memcmp_res);
788 bool ComputeCompareResult<bool>(
int memcmp_res) {
789 return memcmp_res == 0;
811 CordRepBtree* tree = node->
btree();
812 int height = tree->height();
814 tree = tree->Edge(CordRepBtree::kFront)->btree();
816 return tree->Data(tree->begin());
833 assert(node->
IsExternal() &&
"Expect FLAT or EXTERNAL node here");
855 return absl::nullopt;
861 size_t size_to_compare)
const {
863 if (!chunk->empty())
return true;
865 if (
it->bytes_remaining_ == 0)
return false;
875 assert(compared_size <= lhs_chunk.
size());
876 assert(compared_size <= rhs.
size());
879 size_to_compare -= compared_size;
882 int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare);
883 if (comparison_result != 0)
return comparison_result;
884 if (size_to_compare == 0)
return 0;
887 return static_cast<int>(rhs.
empty()) -
static_cast<int>(lhs_chunk.
empty());
891 size_t size_to_compare)
const {
893 if (!chunk->empty())
return true;
895 if (
it->bytes_remaining_ == 0)
return false;
908 assert(compared_size <= lhs_chunk.
size());
909 assert(compared_size <= rhs_chunk.
size());
912 size_to_compare -= compared_size;
914 while (
advance(&lhs_it, &lhs_chunk) &&
advance(&rhs_it, &rhs_chunk)) {
915 int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare);
916 if (memcmp_res != 0)
return memcmp_res;
917 if (size_to_compare == 0)
return 0;
920 return static_cast<int>(rhs_chunk.
empty()) -
921 static_cast<int>(lhs_chunk.
empty());
925 return c.contents_.FindFlatStartPiece();
933 template <
typename ResultType,
typename RHS>
935 size_t size_to_compare) {
940 assert(size_to_compare >= compared_size);
941 int memcmp_res = ::memcmp(lhs_chunk.
data(), rhs_chunk.
data(), compared_size);
942 if (compared_size == size_to_compare || memcmp_res != 0) {
943 return ComputeCompareResult<ResultType>(memcmp_res);
946 return ComputeCompareResult<ResultType>(
951 return GenericCompare<bool>(*
this, rhs, size_to_compare);
955 return GenericCompare<bool>(*
this, rhs, size_to_compare);
958 template <
typename RHS>
960 size_t lhs_size = lhs.
size();
961 size_t rhs_size = rhs.size();
962 if (lhs_size == rhs_size) {
963 return GenericCompare<int>(lhs, rhs, lhs_size);
965 if (lhs_size < rhs_size) {
966 auto data_comp_res = GenericCompare<int>(lhs, rhs, lhs_size);
967 return data_comp_res == 0 ? -1 : data_comp_res;
970 auto data_comp_res = GenericCompare<int>(lhs, rhs, rhs_size);
971 return data_comp_res == 0 ? +1 : data_comp_res;
983 size_t my_size =
size();
984 size_t rhs_size = rhs.
size();
986 if (my_size < rhs_size)
return false;
989 tmp.RemovePrefix(my_size - rhs_size);
990 return tmp.EqualsImpl(rhs, rhs_size);
994 size_t my_size =
size();
995 size_t rhs_size = rhs.
size();
997 if (my_size < rhs_size)
return false;
1000 tmp.RemovePrefix(my_size - rhs_size);
1001 return tmp.EqualsImpl(rhs, rhs_size);
1030 memcpy(
dst, chunk.data(), chunk.size());
1031 dst += chunk.size();
1037 "Attempted to iterate past `end()`");
1044 while (
n > current_chunk_.size()) {
1045 memcpy(
data, current_chunk_.data(), current_chunk_.size());
1046 data += current_chunk_.size();
1047 n -= current_chunk_.size();
1051 if (
n < current_chunk_.size()) {
1052 RemoveChunkPrefix(
n);
1059 if (btree_reader_) {
1060 size_t chunk_size = current_chunk_.
size();
1062 subcord =
Cord(current_chunk_.substr(0,
n),
method);
1063 if (
n < chunk_size) {
1064 current_chunk_.remove_prefix(
n);
1066 current_chunk_ = btree_reader_.Next();
1070 current_chunk_ = btree_reader_.Read(
n, chunk_size,
rep);
1073 bytes_remaining_ -=
n;
1078 assert(current_leaf_ !=
nullptr);
1079 if (
n == current_leaf_->length) {
1080 bytes_remaining_ = 0;
1081 current_chunk_ = {};
1091 ? current_leaf_->substring()->child
1095 const size_t offset = current_chunk_.data() -
data;
1099 bytes_remaining_ -=
n;
1100 current_chunk_.remove_prefix(
n);
1108 if (
rep ==
nullptr) {
1113 assert(
rep !=
nullptr);
1134 size_t total_size =
size();
1142 new_rep->
length = total_size;
1143 new_buffer = new_rep->
flat()->
Data();
1146 new_buffer = std::allocator<char>().allocate(total_size);
1150 std::allocator<char>().deallocate(
const_cast<char*
>(
s.data()),
1161 assert(
rep !=
nullptr);
1173 if (
child->IsFlat()) {
1177 }
else if (
child->IsExternal()) {
1181 }
else if (
child->IsBtree()) {
1192 assert(
rep !=
nullptr);
1207 bool success =
GetFlatAux(current_node, &chunk);
1216 const int kIndentStep = 1;
1221 *os <<
" " << std::setw(7) <<
rep->
length;
1223 if (include_data) *os << static_cast<void*>(
rep);
1225 *os <<
" " << std::setw(
indent) <<
"";
1227 *os <<
"CRC crc=" <<
rep->
crc()->
crc <<
"\n";
1236 *os <<
"EXTERNAL [";
1248 if (
stack.empty())
break;
1259 std::ostringstream
buf;
1260 buf <<
"Error at node " << node <<
" in:";
1279 if (node->IsFlat()) {
1282 }
else if (node->IsExternal()) {
1285 }
else if (node->IsSubstring()) {
1287 node->substring()->start < node->substring()->child->length,
1290 node->substring()->child->length,
1292 }
else if (node->IsCrc()) {
1299 }
while (!worklist.
empty());
1305 out.write(chunk.data(), chunk.size());
1310 namespace strings_internal {
1320 size_t CordTestAccess::SizeofCordRepExternal() {
1321 return sizeof(CordRepExternal);
1323 size_t CordTestAccess::SizeofCordRepSubstring() {
1324 return sizeof(CordRepSubstring);
cord_internal::InlineData data_
static CordRep * VerifyTree(CordRep *node)
void reduce_size(size_t n)
uint8_t AllocatedSizeToTag(size_t size)
absl::cord_internal::CordRep CordRep
constexpr bool IsBtree() const
absl::string_view FindFlatStartPiece() const
int SharedCompareImpl(const Cord &lhs, const RHS &rhs)
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
return memset(p, 0, total)
static CordRep::ExtractResult ExtractAppendBuffer(CordRep *rep, size_t min_capacity)
Cord & operator=(const Cord &x)
static void Unref(CordRep *rep)
static CordRepFlat * New(size_t len)
CordRepExternal * external()
ABSL_NAMESPACE_BEGIN std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
void PrependArray(absl::string_view src, MethodIdentifier method)
static void Dump(StringPiece pattern, Regexp::ParseFlags flags, std::string *forward, std::string *reverse)
const char * data() const
int Compare(absl::string_view rhs) const
absl::string_view FlattenSlowPath()
#define ABSL_INTERNAL_CHECK(condition, message)
static bool PrepareAppendRegion(CordRep *root, char **region, size_t *size, size_t max_length)
void PrependTreeToInlined(CordRep *tree, MethodIdentifier method)
static constexpr unsigned char kMaxInline
static void Append(State *state, const char *const str, const int length)
static constexpr size_t kMaxFlatLength
CordBuffer GetAppendBufferSlowPath(size_t capacity, size_t min_capacity)
CordRep * RemoveCrcNode(CordRep *rep)
std::string CEscape(absl::string_view src)
#define ABSL_NAMESPACE_END
constexpr bool IsCrc() const
constexpr bool empty() const noexcept
const char * as_chars() const
void InitializeCordRepExternal(absl::string_view data, CordRepExternal *rep)
#define ABSL_HARDENING_ASSERT(expr)
#define T(upbtypeconst, upbtype, ctype, default_value)
void RemoveSuffix(size_t n)
cord_internal::InlineData InlineData
void set_inline_size(size_t size)
absl::cord_internal::CordRep * clear()
void AppendTreeToInlined(CordRep *tree, MethodIdentifier method)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
absl::cord_internal::CordRep * as_tree() const
char GetCharacter(size_t offset) const
#define ABSL_NAMESPACE_BEGIN
ChunkRange Chunks() const
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
char operator[](size_t i) const
absl::optional< uint32_t > ExpectedChecksum() const
static CordRepFlat * CreateFlat(const char *data, size_t length, size_t alloc_hint)
void PrependPrecise(absl::string_view src, MethodIdentifier method)
constexpr size_type size() const noexcept
static void * tag(intptr_t t)
CordRepSubstring * RemoveSuffix(size_t length, CordRep *rep)
RefCountedPtr< grpc_tls_certificate_provider > root
void set_data(const char *data, size_t n)
static bool VerifyNode(CordRep *root, CordRep *start_node, bool full_validation)
static bool GetFlatAux(absl::cord_internal::CordRep *rep, absl::string_view *fragment)
void CopyTo(std::string *dst) const
static void MaybeUntrackCord(CordzInfo *info)
RefcountAndFlags refcount
static CordRepBtree * ForceBtree(CordRep *rep)
static constexpr size_t kFlatOverhead
constexpr bool IsFlat() const
void push_back(const_reference v)
size_t remaining_inline_capacity() const
void AssignSlow(const InlineRep &src)
void Prepend(const Cord &src)
void AppendArray(absl::string_view src, MethodIdentifier method)
ABSL_ATTRIBUTE_REINITIALIZES void Clear()
bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const
static void advance(upb_pbdecoder *d, size_t len)
static void DumpNode(CordRep *rep, bool include_data, std::ostream *os, int indent=0)
absl::cord_internal::CordRep * TakeRep() const &
void AppendPrecise(absl::string_view src, MethodIdentifier method)
static void callback(void *arg, int status, int timeouts, struct hostent *host)
static absl::string_view GetFirstChunk(const Cord &c)
CordRep * as_tree() const
int CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const
static CordRepFlat * Create(absl::string_view data, size_t extra=0)
void RemovePrefix(size_t n)
constexpr bool IsSubstring() const
#define ABSL_PREDICT_TRUE(x)
int CompareImpl(const Cord &rhs) const
Cord Subcord(size_t pos, size_t new_size) const
void PrependTree(CordRep *tree, MethodIdentifier method)
constexpr bool IsExternal() const
CordRep * SubTree(size_t offset, size_t n)
CordRep * NewExternalRep(absl::string_view data, Releaser &&releaser)
static CordBuffer CreateWithDefaultLimit(size_t capacity)
static CordRep * NewTree(const char *data, size_t length, size_t alloc_hint)
Cord AdvanceAndReadBytes(size_t n)
void SetExpectedChecksum(uint32_t crc)
static void MaybeTrackCord(InlineData &cord, MethodIdentifier method)
absl::cord_internal::CordzInfo * cordz_info() const
void SmallMemmove(char *dst, const char *src, size_t n)
static void ForEachChunkAux(absl::cord_internal::CordRep *rep, absl::FunctionRef< void(absl::string_view)> callback)
absl::cord_internal::CordRep * tree() const
ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n)
void STLStringResizeUninitialized(string_type *s, size_t new_size)
constexpr size_t TagToLength(uint8_t tag)
void CopyCordToString(const Cord &src, std::string *dst)
constexpr size_type size() const noexcept
Cord & AssignLargeString(std::string &&src)
void CommitTree(const CordRep *old_rep, CordRep *rep, const CordzUpdateScope &scope, MethodIdentifier method)
friend ResultType GenericCompare(const Cord &lhs, const RHS &rhs, size_t size_to_compare)
absl::string_view string_view
CordRepFlat * MakeFlatWithExtraCapacity(size_t extra)
friend void CopyCordToString(const Cord &src, std::string *dst)
static CordRep * Ref(CordRep *rep)
void SetTreeOrEmpty(CordRep *rep, const CordzUpdateScope &scope)
static CordRep * NewBtree(const char *data, size_t length, size_t alloc_hint)
constexpr Cord() noexcept
CordzInfo * cordz_info() const
void PrependTreeToTree(CordRep *tree, MethodIdentifier method)
constexpr bool empty() const noexcept
bool empty() const noexcept
void AppendTreeToTree(CordRep *tree, MethodIdentifier method)
static CordRep * CordRepFromString(std::string &&src)
void EmplaceTree(CordRep *rep, MethodIdentifier method)
static std::string ReportError(CordRep *root, CordRep *node)
bool IsFlat(absl::string_view *fragment) const
void AppendTree(CordRep *tree, MethodIdentifier method)
static constexpr size_t kMinFlatLength
ChunkIterator chunk_begin() const
void CopyToArraySlowPath(char *dst) const
void SetTree(CordRep *rep, const CordzUpdateScope &scope)
CordRep * SkipCrcNode(CordRep *rep)
size_t inline_size() const
static CordBuffer CreateAppendBuffer(InlineData &data, size_t capacity)
bool EndsWith(absl::string_view rhs) const
constexpr const_pointer data() const noexcept
void remove_prefix(size_t n)
constexpr pointer data() const noexcept
CordRepSubstring * substring()
void Append(const Cord &src)
grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:02