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