File indexing completed on 2025-06-30 08:06:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 #ifndef ABSL_STRINGS_CORD_H_
0061 #define ABSL_STRINGS_CORD_H_
0062
0063 #include <algorithm>
0064 #include <cstddef>
0065 #include <cstdint>
0066 #include <cstring>
0067 #include <iosfwd>
0068 #include <iterator>
0069 #include <string>
0070 #include <type_traits>
0071
0072 #include "absl/base/attributes.h"
0073 #include "absl/base/config.h"
0074 #include "absl/base/internal/endian.h"
0075 #include "absl/base/internal/per_thread_tls.h"
0076 #include "absl/base/macros.h"
0077 #include "absl/base/nullability.h"
0078 #include "absl/base/optimization.h"
0079 #include "absl/base/port.h"
0080 #include "absl/container/inlined_vector.h"
0081 #include "absl/crc/internal/crc_cord_state.h"
0082 #include "absl/functional/function_ref.h"
0083 #include "absl/meta/type_traits.h"
0084 #include "absl/strings/cord_analysis.h"
0085 #include "absl/strings/cord_buffer.h"
0086 #include "absl/strings/internal/cord_data_edge.h"
0087 #include "absl/strings/internal/cord_internal.h"
0088 #include "absl/strings/internal/cord_rep_btree.h"
0089 #include "absl/strings/internal/cord_rep_btree_reader.h"
0090 #include "absl/strings/internal/cord_rep_crc.h"
0091 #include "absl/strings/internal/cordz_functions.h"
0092 #include "absl/strings/internal/cordz_info.h"
0093 #include "absl/strings/internal/cordz_statistics.h"
0094 #include "absl/strings/internal/cordz_update_scope.h"
0095 #include "absl/strings/internal/cordz_update_tracker.h"
0096 #include "absl/strings/internal/resize_uninitialized.h"
0097 #include "absl/strings/internal/string_constant.h"
0098 #include "absl/strings/string_view.h"
0099 #include "absl/types/compare.h"
0100 #include "absl/types/optional.h"
0101
0102 namespace absl {
0103 ABSL_NAMESPACE_BEGIN
0104 class Cord;
0105 class CordTestPeer;
0106 template <typename Releaser>
0107 Cord MakeCordFromExternal(absl::string_view, Releaser&&);
0108 void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
0109 void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
0110
0111
0112 enum class CordMemoryAccounting {
0113
0114
0115
0116
0117 kTotal,
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 kTotalMorePrecise,
0138
0139
0140
0141
0142
0143 kFairShare,
0144 };
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 class Cord {
0175 private:
0176 template <typename T>
0177 using EnableIfString =
0178 absl::enable_if_t<std::is_same<T, std::string>::value, int>;
0179
0180 public:
0181
0182
0183
0184 constexpr Cord() noexcept;
0185
0186
0187
0188 Cord(const Cord& src);
0189 Cord(Cord&& src) noexcept;
0190 Cord& operator=(const Cord& x);
0191 Cord& operator=(Cord&& x) noexcept;
0192
0193
0194
0195
0196 explicit Cord(absl::string_view src);
0197 Cord& operator=(absl::string_view src);
0198
0199
0200
0201
0202 template <typename T, EnableIfString<T> = 0>
0203 explicit Cord(T&& src);
0204 template <typename T, EnableIfString<T> = 0>
0205 Cord& operator=(T&& src);
0206
0207
0208
0209
0210 ~Cord() {
0211 if (contents_.is_tree()) DestroyCordSlow();
0212 }
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253 template <typename Releaser>
0254 friend Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser);
0255
0256
0257
0258
0259
0260 ABSL_ATTRIBUTE_REINITIALIZES void Clear();
0261
0262
0263
0264
0265
0266 void Append(const Cord& src);
0267 void Append(Cord&& src);
0268 void Append(absl::string_view src);
0269 template <typename T, EnableIfString<T> = 0>
0270 void Append(T&& src);
0271
0272
0273
0274
0275 void Append(CordBuffer buffer);
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 CordBuffer GetAppendBuffer(size_t capacity, size_t min_capacity = 16);
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 CordBuffer GetCustomAppendBuffer(size_t block_size, size_t capacity,
0322 size_t min_capacity = 16);
0323
0324
0325
0326
0327
0328 void Prepend(const Cord& src);
0329 void Prepend(absl::string_view src);
0330 template <typename T, EnableIfString<T> = 0>
0331 void Prepend(T&& src);
0332
0333
0334
0335
0336 void Prepend(CordBuffer buffer);
0337
0338
0339
0340
0341 void RemovePrefix(size_t n);
0342 void RemoveSuffix(size_t n);
0343
0344
0345
0346
0347
0348
0349 Cord Subcord(size_t pos, size_t new_size) const;
0350
0351
0352
0353
0354 void swap(Cord& other) noexcept;
0355
0356
0357
0358
0359 friend void swap(Cord& x, Cord& y) noexcept { x.swap(y); }
0360
0361
0362
0363
0364 size_t size() const;
0365
0366
0367
0368
0369 bool empty() const;
0370
0371
0372
0373
0374
0375 size_t EstimatedMemoryUsage(CordMemoryAccounting accounting_method =
0376 CordMemoryAccounting::kTotal) const;
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 int Compare(absl::string_view rhs) const;
0388 int Compare(const Cord& rhs) const;
0389
0390
0391
0392
0393 bool StartsWith(const Cord& rhs) const;
0394 bool StartsWith(absl::string_view rhs) const;
0395
0396
0397
0398
0399 bool EndsWith(absl::string_view rhs) const;
0400 bool EndsWith(const Cord& rhs) const;
0401
0402
0403
0404
0405 bool Contains(absl::string_view rhs) const;
0406 bool Contains(const Cord& rhs) const;
0407
0408
0409
0410
0411
0412 explicit operator std::string() const;
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423 friend void CopyCordToString(const Cord& src,
0424 absl::Nonnull<std::string*> dst);
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435 friend void AppendCordToString(const Cord& src,
0436 absl::Nonnull<std::string*> dst);
0437
0438 class CharIterator;
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468 class ChunkIterator {
0469 public:
0470 using iterator_category = std::input_iterator_tag;
0471 using value_type = absl::string_view;
0472 using difference_type = ptrdiff_t;
0473 using pointer = absl::Nonnull<const value_type*>;
0474 using reference = value_type;
0475
0476 ChunkIterator() = default;
0477
0478 ChunkIterator& operator++();
0479 ChunkIterator operator++(int);
0480 bool operator==(const ChunkIterator& other) const;
0481 bool operator!=(const ChunkIterator& other) const;
0482 reference operator*() const;
0483 pointer operator->() const;
0484
0485 friend class Cord;
0486 friend class CharIterator;
0487
0488 private:
0489 using CordRep = absl::cord_internal::CordRep;
0490 using CordRepBtree = absl::cord_internal::CordRepBtree;
0491 using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader;
0492
0493
0494 explicit ChunkIterator(absl::Nonnull<cord_internal::CordRep*> tree);
0495
0496
0497 explicit ChunkIterator(absl::Nonnull<const Cord*> cord);
0498
0499
0500 void InitTree(absl::Nonnull<cord_internal::CordRep*> tree);
0501
0502
0503
0504 void RemoveChunkPrefix(size_t n);
0505 Cord AdvanceAndReadBytes(size_t n);
0506 void AdvanceBytes(size_t n);
0507
0508
0509 ChunkIterator& AdvanceBtree();
0510 void AdvanceBytesBtree(size_t n);
0511
0512
0513
0514 absl::string_view current_chunk_;
0515
0516
0517
0518 absl::Nullable<absl::cord_internal::CordRep*> current_leaf_ = nullptr;
0519
0520 size_t bytes_remaining_ = 0;
0521
0522
0523 CordRepBtreeReader btree_reader_;
0524 };
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540 ChunkIterator chunk_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0541
0542
0543
0544
0545
0546
0547
0548
0549 ChunkIterator chunk_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563 class ChunkRange {
0564 public:
0565
0566
0567
0568
0569 using value_type = absl::string_view;
0570 using reference = value_type&;
0571 using const_reference = const value_type&;
0572 using iterator = ChunkIterator;
0573 using const_iterator = ChunkIterator;
0574
0575 explicit ChunkRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {}
0576
0577 ChunkIterator begin() const;
0578 ChunkIterator end() const;
0579
0580 private:
0581 absl::Nonnull<const Cord*> cord_;
0582 };
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601
0602
0603 ChunkRange Chunks() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628
0629 class CharIterator {
0630 public:
0631 using iterator_category = std::input_iterator_tag;
0632 using value_type = char;
0633 using difference_type = ptrdiff_t;
0634 using pointer = absl::Nonnull<const char*>;
0635 using reference = const char&;
0636
0637 CharIterator() = default;
0638
0639 CharIterator& operator++();
0640 CharIterator operator++(int);
0641 bool operator==(const CharIterator& other) const;
0642 bool operator!=(const CharIterator& other) const;
0643 reference operator*() const;
0644 pointer operator->() const;
0645
0646 friend Cord;
0647
0648 private:
0649 explicit CharIterator(absl::Nonnull<const Cord*> cord)
0650 : chunk_iterator_(cord) {}
0651
0652 ChunkIterator chunk_iterator_;
0653 };
0654
0655
0656
0657
0658
0659
0660
0661 static Cord AdvanceAndRead(absl::Nonnull<CharIterator*> it, size_t n_bytes);
0662
0663
0664
0665
0666
0667
0668 static void Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes);
0669
0670
0671
0672
0673
0674
0675 static absl::string_view ChunkRemaining(const CharIterator& it);
0676
0677
0678
0679
0680
0681
0682
0683
0684 CharIterator char_begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0685
0686
0687
0688
0689
0690
0691
0692
0693 CharIterator char_end() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705 class CharRange {
0706 public:
0707
0708
0709
0710
0711 using value_type = char;
0712 using reference = value_type&;
0713 using const_reference = const value_type&;
0714 using iterator = CharIterator;
0715 using const_iterator = CharIterator;
0716
0717 explicit CharRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {}
0718
0719 CharIterator begin() const;
0720 CharIterator end() const;
0721
0722 private:
0723 absl::Nonnull<const Cord*> cord_;
0724 };
0725
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745 CharRange Chars() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757 char operator[](size_t i) const;
0758
0759
0760
0761
0762
0763 absl::optional<absl::string_view> TryFlat() const
0764 ABSL_ATTRIBUTE_LIFETIME_BOUND;
0765
0766
0767
0768
0769
0770
0771 absl::string_view Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND;
0772
0773
0774
0775
0776
0777
0778 CharIterator Find(absl::string_view needle) const;
0779 CharIterator Find(const absl::Cord& needle) const;
0780
0781
0782 friend void AbslFormatFlush(absl::Nonnull<absl::Cord*> cord,
0783 absl::string_view part) {
0784 cord->Append(part);
0785 }
0786
0787
0788 template <typename Sink>
0789 friend void AbslStringify(Sink& sink, const absl::Cord& cord) {
0790 for (absl::string_view chunk : cord.Chunks()) {
0791 sink.Append(chunk);
0792 }
0793 }
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811
0812 void SetExpectedChecksum(uint32_t crc);
0813
0814
0815
0816 absl::optional<uint32_t> ExpectedChecksum() const;
0817
0818 template <typename H>
0819 friend H AbslHashValue(H hash_state, const absl::Cord& c) {
0820 absl::optional<absl::string_view> maybe_flat = c.TryFlat();
0821 if (maybe_flat.has_value()) {
0822 return H::combine(std::move(hash_state), *maybe_flat);
0823 }
0824 return c.HashFragmented(std::move(hash_state));
0825 }
0826
0827
0828
0829
0830
0831
0832 template <typename T>
0833
0834 constexpr Cord(strings_internal::StringConstant<T>);
0835
0836 private:
0837 using CordRep = absl::cord_internal::CordRep;
0838 using CordRepFlat = absl::cord_internal::CordRepFlat;
0839 using CordzInfo = cord_internal::CordzInfo;
0840 using CordzUpdateScope = cord_internal::CordzUpdateScope;
0841 using CordzUpdateTracker = cord_internal::CordzUpdateTracker;
0842 using InlineData = cord_internal::InlineData;
0843 using MethodIdentifier = CordzUpdateTracker::MethodIdentifier;
0844
0845
0846
0847 explicit Cord(absl::string_view src, MethodIdentifier method);
0848
0849 friend class CordTestPeer;
0850 friend bool operator==(const Cord& lhs, const Cord& rhs);
0851 friend bool operator==(const Cord& lhs, absl::string_view rhs);
0852
0853 #ifdef __cpp_impl_three_way_comparison
0854
0855
0856
0857
0858
0859 static inline std::strong_ordering ConvertCompareResultToStrongOrdering(
0860 int c) {
0861 if (c == 0) {
0862 return std::strong_ordering::equal;
0863 } else if (c < 0) {
0864 return std::strong_ordering::less;
0865 } else {
0866 return std::strong_ordering::greater;
0867 }
0868 }
0869
0870 friend inline std::strong_ordering operator<=>(const Cord& x, const Cord& y) {
0871 return ConvertCompareResultToStrongOrdering(x.Compare(y));
0872 }
0873
0874 friend inline std::strong_ordering operator<=>(const Cord& lhs,
0875 absl::string_view rhs) {
0876 return ConvertCompareResultToStrongOrdering(lhs.Compare(rhs));
0877 }
0878
0879 friend inline std::strong_ordering operator<=>(absl::string_view lhs,
0880 const Cord& rhs) {
0881 return ConvertCompareResultToStrongOrdering(-rhs.Compare(lhs));
0882 }
0883 #endif
0884
0885 friend absl::Nullable<const CordzInfo*> GetCordzInfoForTesting(
0886 const Cord& cord);
0887
0888
0889
0890 void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const;
0891
0892
0893
0894 absl::string_view FlattenSlowPath();
0895
0896
0897
0898
0899
0900
0901 class InlineRep {
0902 public:
0903 static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
0904 static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
0905
0906 constexpr InlineRep() : data_() {}
0907 explicit InlineRep(InlineData::DefaultInitType init) : data_(init) {}
0908 InlineRep(const InlineRep& src);
0909 InlineRep(InlineRep&& src);
0910 InlineRep& operator=(const InlineRep& src);
0911 InlineRep& operator=(InlineRep&& src) noexcept;
0912
0913 explicit constexpr InlineRep(absl::string_view sv,
0914 absl::Nullable<CordRep*> rep);
0915
0916 void Swap(absl::Nonnull<InlineRep*> rhs);
0917 size_t size() const;
0918
0919 absl::Nullable<const char*> data() const;
0920
0921 void set_data(absl::Nonnull<const char*> data, size_t n);
0922 absl::Nonnull<char*> set_data(size_t n);
0923
0924 absl::Nullable<absl::cord_internal::CordRep*> tree() const;
0925 absl::Nonnull<absl::cord_internal::CordRep*> as_tree() const;
0926 absl::Nonnull<const char*> as_chars() const;
0927
0928 absl::Nullable<absl::cord_internal::CordRep*> clear();
0929
0930 void reduce_size(size_t n);
0931 void remove_prefix(size_t n);
0932 void AppendArray(absl::string_view src, MethodIdentifier method);
0933 absl::string_view FindFlatStartPiece() const;
0934
0935
0936
0937 absl::Nonnull<CordRepFlat*> MakeFlatWithExtraCapacity(size_t extra);
0938
0939
0940
0941
0942
0943
0944 void SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope);
0945
0946
0947
0948 void SetTreeOrEmpty(absl::Nullable<CordRep*> rep,
0949 const CordzUpdateScope& scope);
0950
0951
0952
0953
0954
0955 void EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method);
0956
0957
0958
0959 void EmplaceTree(absl::Nonnull<CordRep*> rep, const InlineData& parent,
0960 MethodIdentifier method);
0961
0962
0963
0964
0965 void CommitTree(absl::Nullable<const CordRep*> old_rep,
0966 absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope,
0967 MethodIdentifier method);
0968
0969 void AppendTreeToInlined(absl::Nonnull<CordRep*> tree,
0970 MethodIdentifier method);
0971 void AppendTreeToTree(absl::Nonnull<CordRep*> tree,
0972 MethodIdentifier method);
0973 void AppendTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method);
0974 void PrependTreeToInlined(absl::Nonnull<CordRep*> tree,
0975 MethodIdentifier method);
0976 void PrependTreeToTree(absl::Nonnull<CordRep*> tree,
0977 MethodIdentifier method);
0978 void PrependTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method);
0979
0980 bool IsSame(const InlineRep& other) const { return data_ == other.data_; }
0981
0982 void CopyTo(absl::Nonnull<std::string*> dst) const {
0983
0984
0985
0986 absl::strings_internal::STLStringResizeUninitialized(dst, kMaxInline);
0987 data_.copy_max_inline_to(&(*dst)[0]);
0988
0989
0990 dst->erase(inline_size());
0991 }
0992
0993
0994 void CopyToArray(absl::Nonnull<char*> dst) const;
0995
0996 bool is_tree() const { return data_.is_tree(); }
0997
0998
0999 bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); }
1000
1001
1002 size_t remaining_inline_capacity() const {
1003 return data_.is_tree() ? 0 : kMaxInline - data_.inline_size();
1004 }
1005
1006
1007 absl::Nullable<absl::cord_internal::CordzInfo*> cordz_info() const {
1008 return data_.cordz_info();
1009 }
1010
1011
1012 void set_cordz_info(absl::Nonnull<cord_internal::CordzInfo*> cordz_info) {
1013 assert(cordz_info != nullptr);
1014 data_.set_cordz_info(cordz_info);
1015 }
1016
1017
1018 void clear_cordz_info() { data_.clear_cordz_info(); }
1019
1020 private:
1021 friend class Cord;
1022
1023 void AssignSlow(const InlineRep& src);
1024
1025 void UnrefTree();
1026
1027 void ResetToEmpty() { data_ = {}; }
1028
1029 void set_inline_size(size_t size) { data_.set_inline_size(size); }
1030 size_t inline_size() const { return data_.inline_size(); }
1031
1032
1033
1034
1035
1036
1037 void MaybeRemoveEmptyCrcNode();
1038
1039 cord_internal::InlineData data_;
1040 };
1041 InlineRep contents_;
1042
1043
1044 static bool GetFlatAux(absl::Nonnull<absl::cord_internal::CordRep*> rep,
1045 absl::Nonnull<absl::string_view*> fragment);
1046
1047
1048 static void ForEachChunkAux(
1049 absl::Nonnull<absl::cord_internal::CordRep*> rep,
1050 absl::FunctionRef<void(absl::string_view)> callback);
1051
1052
1053 void DestroyCordSlow();
1054
1055
1056 void CopyToArraySlowPath(absl::Nonnull<char*> dst) const;
1057 int CompareSlowPath(absl::string_view rhs, size_t compared_size,
1058 size_t size_to_compare) const;
1059 int CompareSlowPath(const Cord& rhs, size_t compared_size,
1060 size_t size_to_compare) const;
1061 bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const;
1062 bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const;
1063 int CompareImpl(const Cord& rhs) const;
1064
1065 template <typename ResultType, typename RHS>
1066 friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs,
1067 size_t size_to_compare);
1068 static absl::string_view GetFirstChunk(const Cord& c);
1069 static absl::string_view GetFirstChunk(absl::string_view sv);
1070
1071
1072
1073 absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() const&;
1074 absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() &&;
1075
1076
1077 template <typename C>
1078 void AppendImpl(C&& src);
1079
1080
1081
1082
1083
1084 void AppendPrecise(absl::string_view src, MethodIdentifier method);
1085 void PrependPrecise(absl::string_view src, MethodIdentifier method);
1086
1087 CordBuffer GetAppendBufferSlowPath(size_t block_size, size_t capacity,
1088 size_t min_capacity);
1089
1090
1091
1092 void PrependArray(absl::string_view src, MethodIdentifier method);
1093
1094
1095
1096 Cord& AssignLargeString(std::string&& src);
1097
1098
1099 template <typename H>
1100 H HashFragmented(H hash_state) const {
1101 typename H::AbslInternalPiecewiseCombiner combiner;
1102 ForEachChunk([&combiner, &hash_state](absl::string_view chunk) {
1103 hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(),
1104 chunk.size());
1105 });
1106 return H::combine(combiner.finalize(std::move(hash_state)), size());
1107 }
1108
1109 friend class CrcCord;
1110 void SetCrcCordState(crc_internal::CrcCordState state);
1111 absl::Nullable<const crc_internal::CrcCordState*> MaybeGetCrcCordState()
1112 const;
1113
1114 CharIterator FindImpl(CharIterator it, absl::string_view needle) const;
1115
1116 void CopyToArrayImpl(absl::Nonnull<char*> dst) const;
1117 };
1118
1119 ABSL_NAMESPACE_END
1120 }
1121
1122 namespace absl {
1123 ABSL_NAMESPACE_BEGIN
1124
1125
1126 extern std::ostream& operator<<(std::ostream& out, const Cord& cord);
1127
1128
1129
1130
1131 namespace cord_internal {
1132
1133
1134
1135 void InitializeCordRepExternal(absl::string_view data,
1136 absl::Nonnull<CordRepExternal*> rep);
1137
1138
1139
1140 template <typename Releaser>
1141
1142 absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data,
1143 Releaser&& releaser) {
1144 assert(!data.empty());
1145 using ReleaserType = absl::decay_t<Releaser>;
1146 CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>(
1147 std::forward<Releaser>(releaser), 0);
1148 InitializeCordRepExternal(data, rep);
1149 return rep;
1150 }
1151
1152
1153
1154
1155 inline absl::Nonnull<CordRep*> NewExternalRep(
1156 absl::string_view data, void (&releaser)(absl::string_view)) {
1157 return NewExternalRep(data, &releaser);
1158 }
1159
1160 }
1161
1162 template <typename Releaser>
1163 Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
1164 Cord cord;
1165 if (ABSL_PREDICT_TRUE(!data.empty())) {
1166 cord.contents_.EmplaceTree(::absl::cord_internal::NewExternalRep(
1167 data, std::forward<Releaser>(releaser)),
1168 Cord::MethodIdentifier::kMakeCordFromExternal);
1169 } else {
1170 using ReleaserType = absl::decay_t<Releaser>;
1171 cord_internal::InvokeReleaser(
1172 cord_internal::Rank1{}, ReleaserType(std::forward<Releaser>(releaser)),
1173 data);
1174 }
1175 return cord;
1176 }
1177
1178 constexpr Cord::InlineRep::InlineRep(absl::string_view sv,
1179 absl::Nullable<CordRep*> rep)
1180 : data_(sv, rep) {}
1181
1182 inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src)
1183 : data_(InlineData::kDefaultInit) {
1184 if (CordRep* tree = src.tree()) {
1185 EmplaceTree(CordRep::Ref(tree), src.data_,
1186 CordzUpdateTracker::kConstructorCord);
1187 } else {
1188 data_ = src.data_;
1189 }
1190 }
1191
1192 inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) : data_(src.data_) {
1193 src.ResetToEmpty();
1194 }
1195
1196 inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) {
1197 if (this == &src) {
1198 return *this;
1199 }
1200 if (!is_tree() && !src.is_tree()) {
1201 data_ = src.data_;
1202 return *this;
1203 }
1204 AssignSlow(src);
1205 return *this;
1206 }
1207
1208 inline Cord::InlineRep& Cord::InlineRep::operator=(
1209 Cord::InlineRep&& src) noexcept {
1210 if (is_tree()) {
1211 UnrefTree();
1212 }
1213 data_ = src.data_;
1214 src.ResetToEmpty();
1215 return *this;
1216 }
1217
1218 inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) {
1219 if (rhs == this) {
1220 return;
1221 }
1222 using std::swap;
1223 swap(data_, rhs->data_);
1224 }
1225
1226 inline absl::Nullable<const char*> Cord::InlineRep::data() const {
1227 return is_tree() ? nullptr : data_.as_chars();
1228 }
1229
1230 inline absl::Nonnull<const char*> Cord::InlineRep::as_chars() const {
1231 assert(!data_.is_tree());
1232 return data_.as_chars();
1233 }
1234
1235 inline absl::Nonnull<absl::cord_internal::CordRep*> Cord::InlineRep::as_tree()
1236 const {
1237 assert(data_.is_tree());
1238 return data_.as_tree();
1239 }
1240
1241 inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::tree()
1242 const {
1243 if (is_tree()) {
1244 return as_tree();
1245 } else {
1246 return nullptr;
1247 }
1248 }
1249
1250 inline size_t Cord::InlineRep::size() const {
1251 return is_tree() ? as_tree()->length : inline_size();
1252 }
1253
1254 inline absl::Nonnull<cord_internal::CordRepFlat*>
1255 Cord::InlineRep::MakeFlatWithExtraCapacity(size_t extra) {
1256 static_assert(cord_internal::kMinFlatLength >= sizeof(data_), "");
1257 size_t len = data_.inline_size();
1258 auto* result = CordRepFlat::New(len + extra);
1259 result->length = len;
1260 data_.copy_max_inline_to(result->Data());
1261 return result;
1262 }
1263
1264 inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep,
1265 MethodIdentifier method) {
1266 assert(rep);
1267 data_.make_tree(rep);
1268 CordzInfo::MaybeTrackCord(data_, method);
1269 }
1270
1271 inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep,
1272 const InlineData& parent,
1273 MethodIdentifier method) {
1274 data_.make_tree(rep);
1275 CordzInfo::MaybeTrackCord(data_, parent, method);
1276 }
1277
1278 inline void Cord::InlineRep::SetTree(absl::Nonnull<CordRep*> rep,
1279 const CordzUpdateScope& scope) {
1280 assert(rep);
1281 assert(data_.is_tree());
1282 data_.set_tree(rep);
1283 scope.SetCordRep(rep);
1284 }
1285
1286 inline void Cord::InlineRep::SetTreeOrEmpty(absl::Nullable<CordRep*> rep,
1287 const CordzUpdateScope& scope) {
1288 assert(data_.is_tree());
1289 if (rep) {
1290 data_.set_tree(rep);
1291 } else {
1292 data_ = {};
1293 }
1294 scope.SetCordRep(rep);
1295 }
1296
1297 inline void Cord::InlineRep::CommitTree(absl::Nullable<const CordRep*> old_rep,
1298 absl::Nonnull<CordRep*> rep,
1299 const CordzUpdateScope& scope,
1300 MethodIdentifier method) {
1301 if (old_rep) {
1302 SetTree(rep, scope);
1303 } else {
1304 EmplaceTree(rep, method);
1305 }
1306 }
1307
1308 inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::clear() {
1309 if (is_tree()) {
1310 CordzInfo::MaybeUntrackCord(cordz_info());
1311 }
1312 absl::cord_internal::CordRep* result = tree();
1313 ResetToEmpty();
1314 return result;
1315 }
1316
1317 inline void Cord::InlineRep::CopyToArray(absl::Nonnull<char*> dst) const {
1318 assert(!is_tree());
1319 size_t n = inline_size();
1320 assert(n != 0);
1321 cord_internal::SmallMemmove(dst, data_.as_chars(), n);
1322 }
1323
1324 inline void Cord::InlineRep::MaybeRemoveEmptyCrcNode() {
1325 CordRep* rep = tree();
1326 if (rep == nullptr || ABSL_PREDICT_TRUE(rep->length > 0)) {
1327 return;
1328 }
1329 assert(rep->IsCrc());
1330 assert(rep->crc()->child == nullptr);
1331 CordzInfo::MaybeUntrackCord(cordz_info());
1332 CordRep::Unref(rep);
1333 ResetToEmpty();
1334 }
1335
1336 constexpr inline Cord::Cord() noexcept {}
1337
1338 inline Cord::Cord(absl::string_view src)
1339 : Cord(src, CordzUpdateTracker::kConstructorString) {}
1340
1341 template <typename T>
1342 constexpr Cord::Cord(strings_internal::StringConstant<T>)
1343 : contents_(strings_internal::StringConstant<T>::value,
1344 strings_internal::StringConstant<T>::value.size() <=
1345 cord_internal::kMaxInline
1346 ? nullptr
1347 : &cord_internal::ConstInitExternalStorage<
1348 strings_internal::StringConstant<T>>::value) {}
1349
1350 inline Cord& Cord::operator=(const Cord& x) {
1351 contents_ = x.contents_;
1352 return *this;
1353 }
1354
1355 template <typename T, Cord::EnableIfString<T>>
1356 Cord& Cord::operator=(T&& src) {
1357 if (src.size() <= cord_internal::kMaxBytesToCopy) {
1358 return operator=(absl::string_view(src));
1359 } else {
1360 return AssignLargeString(std::forward<T>(src));
1361 }
1362 }
1363
1364 inline Cord::Cord(const Cord& src) : contents_(src.contents_) {}
1365
1366 inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {}
1367
1368 inline void Cord::swap(Cord& other) noexcept {
1369 contents_.Swap(&other.contents_);
1370 }
1371
1372 inline Cord& Cord::operator=(Cord&& x) noexcept {
1373 contents_ = std::move(x.contents_);
1374 return *this;
1375 }
1376
1377 extern template Cord::Cord(std::string&& src);
1378
1379 inline size_t Cord::size() const {
1380
1381 return contents_.size();
1382 }
1383
1384 inline bool Cord::empty() const { return size() == 0; }
1385
1386 inline size_t Cord::EstimatedMemoryUsage(
1387 CordMemoryAccounting accounting_method) const {
1388 size_t result = sizeof(Cord);
1389 if (const absl::cord_internal::CordRep* rep = contents_.tree()) {
1390 switch (accounting_method) {
1391 case CordMemoryAccounting::kFairShare:
1392 result += cord_internal::GetEstimatedFairShareMemoryUsage(rep);
1393 break;
1394 case CordMemoryAccounting::kTotalMorePrecise:
1395 result += cord_internal::GetMorePreciseMemoryUsage(rep);
1396 break;
1397 case CordMemoryAccounting::kTotal:
1398 result += cord_internal::GetEstimatedMemoryUsage(rep);
1399 break;
1400 }
1401 }
1402 return result;
1403 }
1404
1405 inline absl::optional<absl::string_view> Cord::TryFlat() const
1406 ABSL_ATTRIBUTE_LIFETIME_BOUND {
1407 absl::cord_internal::CordRep* rep = contents_.tree();
1408 if (rep == nullptr) {
1409 return absl::string_view(contents_.data(), contents_.size());
1410 }
1411 absl::string_view fragment;
1412 if (GetFlatAux(rep, &fragment)) {
1413 return fragment;
1414 }
1415 return absl::nullopt;
1416 }
1417
1418 inline absl::string_view Cord::Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND {
1419 absl::cord_internal::CordRep* rep = contents_.tree();
1420 if (rep == nullptr) {
1421 return absl::string_view(contents_.data(), contents_.size());
1422 } else {
1423 absl::string_view already_flat_contents;
1424 if (GetFlatAux(rep, &already_flat_contents)) {
1425 return already_flat_contents;
1426 }
1427 }
1428 return FlattenSlowPath();
1429 }
1430
1431 inline void Cord::Append(absl::string_view src) {
1432 contents_.AppendArray(src, CordzUpdateTracker::kAppendString);
1433 }
1434
1435 inline void Cord::Prepend(absl::string_view src) {
1436 PrependArray(src, CordzUpdateTracker::kPrependString);
1437 }
1438
1439 inline void Cord::Append(CordBuffer buffer) {
1440 if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return;
1441 contents_.MaybeRemoveEmptyCrcNode();
1442 absl::string_view short_value;
1443 if (CordRep* rep = buffer.ConsumeValue(short_value)) {
1444 contents_.AppendTree(rep, CordzUpdateTracker::kAppendCordBuffer);
1445 } else {
1446 AppendPrecise(short_value, CordzUpdateTracker::kAppendCordBuffer);
1447 }
1448 }
1449
1450 inline void Cord::Prepend(CordBuffer buffer) {
1451 if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return;
1452 contents_.MaybeRemoveEmptyCrcNode();
1453 absl::string_view short_value;
1454 if (CordRep* rep = buffer.ConsumeValue(short_value)) {
1455 contents_.PrependTree(rep, CordzUpdateTracker::kPrependCordBuffer);
1456 } else {
1457 PrependPrecise(short_value, CordzUpdateTracker::kPrependCordBuffer);
1458 }
1459 }
1460
1461 inline CordBuffer Cord::GetAppendBuffer(size_t capacity, size_t min_capacity) {
1462 if (empty()) return CordBuffer::CreateWithDefaultLimit(capacity);
1463 return GetAppendBufferSlowPath(0, capacity, min_capacity);
1464 }
1465
1466 inline CordBuffer Cord::GetCustomAppendBuffer(size_t block_size,
1467 size_t capacity,
1468 size_t min_capacity) {
1469 if (empty()) {
1470 return block_size ? CordBuffer::CreateWithCustomLimit(block_size, capacity)
1471 : CordBuffer::CreateWithDefaultLimit(capacity);
1472 }
1473 return GetAppendBufferSlowPath(block_size, capacity, min_capacity);
1474 }
1475
1476 extern template void Cord::Append(std::string&& src);
1477 extern template void Cord::Prepend(std::string&& src);
1478
1479 inline int Cord::Compare(const Cord& rhs) const {
1480 if (!contents_.is_tree() && !rhs.contents_.is_tree()) {
1481 return contents_.data_.Compare(rhs.contents_.data_);
1482 }
1483
1484 return CompareImpl(rhs);
1485 }
1486
1487
1488 inline bool Cord::StartsWith(const Cord& rhs) const {
1489 if (contents_.IsSame(rhs.contents_)) return true;
1490 size_t rhs_size = rhs.size();
1491 if (size() < rhs_size) return false;
1492 return EqualsImpl(rhs, rhs_size);
1493 }
1494
1495 inline bool Cord::StartsWith(absl::string_view rhs) const {
1496 size_t rhs_size = rhs.size();
1497 if (size() < rhs_size) return false;
1498 return EqualsImpl(rhs, rhs_size);
1499 }
1500
1501 inline void Cord::CopyToArrayImpl(absl::Nonnull<char*> dst) const {
1502 if (!contents_.is_tree()) {
1503 if (!empty()) contents_.CopyToArray(dst);
1504 } else {
1505 CopyToArraySlowPath(dst);
1506 }
1507 }
1508
1509 inline void Cord::ChunkIterator::InitTree(
1510 absl::Nonnull<cord_internal::CordRep*> tree) {
1511 tree = cord_internal::SkipCrcNode(tree);
1512 if (tree->tag == cord_internal::BTREE) {
1513 current_chunk_ = btree_reader_.Init(tree->btree());
1514 } else {
1515 current_leaf_ = tree;
1516 current_chunk_ = cord_internal::EdgeData(tree);
1517 }
1518 }
1519
1520 inline Cord::ChunkIterator::ChunkIterator(
1521 absl::Nonnull<cord_internal::CordRep*> tree) {
1522 bytes_remaining_ = tree->length;
1523 InitTree(tree);
1524 }
1525
1526 inline Cord::ChunkIterator::ChunkIterator(absl::Nonnull<const Cord*> cord) {
1527 if (CordRep* tree = cord->contents_.tree()) {
1528 bytes_remaining_ = tree->length;
1529 if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) {
1530 InitTree(tree);
1531 } else {
1532 current_chunk_ = {};
1533 }
1534 } else {
1535 bytes_remaining_ = cord->contents_.inline_size();
1536 current_chunk_ = {cord->contents_.data(), bytes_remaining_};
1537 }
1538 }
1539
1540 inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceBtree() {
1541 current_chunk_ = btree_reader_.Next();
1542 return *this;
1543 }
1544
1545 inline void Cord::ChunkIterator::AdvanceBytesBtree(size_t n) {
1546 assert(n >= current_chunk_.size());
1547 bytes_remaining_ -= n;
1548 if (bytes_remaining_) {
1549 if (n == current_chunk_.size()) {
1550 current_chunk_ = btree_reader_.Next();
1551 } else {
1552 size_t offset = btree_reader_.length() - bytes_remaining_;
1553 current_chunk_ = btree_reader_.Seek(offset);
1554 }
1555 } else {
1556 current_chunk_ = {};
1557 }
1558 }
1559
1560 inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() {
1561 ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 &&
1562 "Attempted to iterate past `end()`");
1563 assert(bytes_remaining_ >= current_chunk_.size());
1564 bytes_remaining_ -= current_chunk_.size();
1565 if (bytes_remaining_ > 0) {
1566 if (btree_reader_) {
1567 return AdvanceBtree();
1568 } else {
1569 assert(!current_chunk_.empty());
1570 }
1571 current_chunk_ = {};
1572 }
1573 return *this;
1574 }
1575
1576 inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) {
1577 ChunkIterator tmp(*this);
1578 operator++();
1579 return tmp;
1580 }
1581
1582 inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const {
1583 return bytes_remaining_ == other.bytes_remaining_;
1584 }
1585
1586 inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const {
1587 return !(*this == other);
1588 }
1589
1590 inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const {
1591 ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
1592 return current_chunk_;
1593 }
1594
1595 inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const {
1596 ABSL_HARDENING_ASSERT(bytes_remaining_ != 0);
1597 return ¤t_chunk_;
1598 }
1599
1600 inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) {
1601 assert(n < current_chunk_.size());
1602 current_chunk_.remove_prefix(n);
1603 bytes_remaining_ -= n;
1604 }
1605
1606 inline void Cord::ChunkIterator::AdvanceBytes(size_t n) {
1607 assert(bytes_remaining_ >= n);
1608 if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) {
1609 RemoveChunkPrefix(n);
1610 } else if (n != 0) {
1611 if (btree_reader_) {
1612 AdvanceBytesBtree(n);
1613 } else {
1614 bytes_remaining_ = 0;
1615 }
1616 }
1617 }
1618
1619 inline Cord::ChunkIterator Cord::chunk_begin() const {
1620 return ChunkIterator(this);
1621 }
1622
1623 inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); }
1624
1625 inline Cord::ChunkIterator Cord::ChunkRange::begin() const {
1626 return cord_->chunk_begin();
1627 }
1628
1629 inline Cord::ChunkIterator Cord::ChunkRange::end() const {
1630 return cord_->chunk_end();
1631 }
1632
1633 inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); }
1634
1635 inline Cord::CharIterator& Cord::CharIterator::operator++() {
1636 if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) {
1637 chunk_iterator_.RemoveChunkPrefix(1);
1638 } else {
1639 ++chunk_iterator_;
1640 }
1641 return *this;
1642 }
1643
1644 inline Cord::CharIterator Cord::CharIterator::operator++(int) {
1645 CharIterator tmp(*this);
1646 operator++();
1647 return tmp;
1648 }
1649
1650 inline bool Cord::CharIterator::operator==(const CharIterator& other) const {
1651 return chunk_iterator_ == other.chunk_iterator_;
1652 }
1653
1654 inline bool Cord::CharIterator::operator!=(const CharIterator& other) const {
1655 return !(*this == other);
1656 }
1657
1658 inline Cord::CharIterator::reference Cord::CharIterator::operator*() const {
1659 return *chunk_iterator_->data();
1660 }
1661
1662 inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const {
1663 return chunk_iterator_->data();
1664 }
1665
1666 inline Cord Cord::AdvanceAndRead(absl::Nonnull<CharIterator*> it,
1667 size_t n_bytes) {
1668 assert(it != nullptr);
1669 return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes);
1670 }
1671
1672 inline void Cord::Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes) {
1673 assert(it != nullptr);
1674 it->chunk_iterator_.AdvanceBytes(n_bytes);
1675 }
1676
1677 inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) {
1678 return *it.chunk_iterator_;
1679 }
1680
1681 inline Cord::CharIterator Cord::char_begin() const {
1682 return CharIterator(this);
1683 }
1684
1685 inline Cord::CharIterator Cord::char_end() const { return CharIterator(); }
1686
1687 inline Cord::CharIterator Cord::CharRange::begin() const {
1688 return cord_->char_begin();
1689 }
1690
1691 inline Cord::CharIterator Cord::CharRange::end() const {
1692 return cord_->char_end();
1693 }
1694
1695 inline Cord::CharRange Cord::Chars() const { return CharRange(this); }
1696
1697 inline void Cord::ForEachChunk(
1698 absl::FunctionRef<void(absl::string_view)> callback) const {
1699 absl::cord_internal::CordRep* rep = contents_.tree();
1700 if (rep == nullptr) {
1701 callback(absl::string_view(contents_.data(), contents_.size()));
1702 } else {
1703 ForEachChunkAux(rep, callback);
1704 }
1705 }
1706
1707
1708 inline bool operator==(const Cord& lhs, const Cord& rhs) {
1709 if (lhs.contents_.IsSame(rhs.contents_)) return true;
1710 size_t rhs_size = rhs.size();
1711 if (lhs.size() != rhs_size) return false;
1712 return lhs.EqualsImpl(rhs, rhs_size);
1713 }
1714
1715 inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); }
1716 inline bool operator<(const Cord& x, const Cord& y) { return x.Compare(y) < 0; }
1717 inline bool operator>(const Cord& x, const Cord& y) { return x.Compare(y) > 0; }
1718 inline bool operator<=(const Cord& x, const Cord& y) {
1719 return x.Compare(y) <= 0;
1720 }
1721 inline bool operator>=(const Cord& x, const Cord& y) {
1722 return x.Compare(y) >= 0;
1723 }
1724
1725
1726
1727
1728
1729 inline bool operator==(const Cord& lhs, absl::string_view rhs) {
1730 size_t lhs_size = lhs.size();
1731 size_t rhs_size = rhs.size();
1732 if (lhs_size != rhs_size) return false;
1733 return lhs.EqualsImpl(rhs, rhs_size);
1734 }
1735
1736 inline bool operator==(absl::string_view x, const Cord& y) { return y == x; }
1737 inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); }
1738 inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); }
1739 inline bool operator<(const Cord& x, absl::string_view y) {
1740 return x.Compare(y) < 0;
1741 }
1742 inline bool operator<(absl::string_view x, const Cord& y) {
1743 return y.Compare(x) > 0;
1744 }
1745 inline bool operator>(const Cord& x, absl::string_view y) { return y < x; }
1746 inline bool operator>(absl::string_view x, const Cord& y) { return y < x; }
1747 inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); }
1748 inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); }
1749 inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); }
1750 inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); }
1751
1752
1753 namespace strings_internal {
1754 class CordTestAccess {
1755 public:
1756 static size_t FlatOverhead();
1757 static size_t MaxFlatLength();
1758 static size_t SizeofCordRepExternal();
1759 static size_t SizeofCordRepSubstring();
1760 static size_t FlatTagToLength(uint8_t tag);
1761 static uint8_t LengthToTag(size_t s);
1762 };
1763 }
1764 ABSL_NAMESPACE_END
1765 }
1766
1767 #endif