diff options
Diffstat (limited to 'absl/strings/cord.h')
-rw-r--r-- | absl/strings/cord.h | 177 |
1 files changed, 101 insertions, 76 deletions
diff --git a/absl/strings/cord.h b/absl/strings/cord.h index e4d5f7f7..b3e556b6 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h @@ -74,6 +74,7 @@ #include "absl/base/internal/endian.h" #include "absl/base/internal/per_thread_tls.h" #include "absl/base/macros.h" +#include "absl/base/nullability.h" #include "absl/base/port.h" #include "absl/container/inlined_vector.h" #include "absl/crc/internal/crc_cord_state.h" @@ -102,7 +103,7 @@ class Cord; class CordTestPeer; template <typename Releaser> Cord MakeCordFromExternal(absl::string_view, Releaser&&); -void CopyCordToString(const Cord& src, std::string* dst); +void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst); // Cord memory accounting modes enum class CordMemoryAccounting { @@ -416,7 +417,8 @@ class Cord { // guarantee that pointers previously returned by `dst->data()` remain valid // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new // object, prefer to simply use the conversion operator to `std::string`. - friend void CopyCordToString(const Cord& src, std::string* dst); + friend void CopyCordToString(const Cord& src, + absl::Nonnull<std::string*> dst); class CharIterator; @@ -453,7 +455,7 @@ class Cord { using iterator_category = std::input_iterator_tag; using value_type = absl::string_view; using difference_type = ptrdiff_t; - using pointer = const value_type*; + using pointer = absl::Nonnull<const value_type*>; using reference = value_type; ChunkIterator() = default; @@ -473,14 +475,14 @@ class Cord { using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; - // Constructs a `begin()` iterator from `tree`. `tree` must not be null. - explicit ChunkIterator(cord_internal::CordRep* tree); + // Constructs a `begin()` iterator from `tree`. + explicit ChunkIterator(absl::Nonnull<cord_internal::CordRep*> tree); // Constructs a `begin()` iterator from `cord`. - explicit ChunkIterator(const Cord* cord); + explicit ChunkIterator(absl::Nonnull<const Cord*> cord); // Initializes this instance from a tree. Invoked by constructors. - void InitTree(cord_internal::CordRep* tree); + void InitTree(absl::Nonnull<cord_internal::CordRep*> tree); // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than // `current_chunk_.size()`. @@ -498,7 +500,7 @@ class Cord { // The current leaf, or `nullptr` if the iterator points to short data. // If the current chunk is a substring node, current_leaf_ points to the // underlying flat or external node. - absl::cord_internal::CordRep* current_leaf_ = nullptr; + absl::Nullable<absl::cord_internal::CordRep*> current_leaf_ = nullptr; // The number of bytes left in the `Cord` over which we are iterating. size_t bytes_remaining_ = 0; @@ -555,13 +557,13 @@ class Cord { using iterator = ChunkIterator; using const_iterator = ChunkIterator; - explicit ChunkRange(const Cord* cord) : cord_(cord) {} + explicit ChunkRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {} ChunkIterator begin() const; ChunkIterator end() const; private: - const Cord* cord_; + absl::Nonnull<const Cord*> cord_; }; // Cord::Chunks() @@ -614,7 +616,7 @@ class Cord { using iterator_category = std::input_iterator_tag; using value_type = char; using difference_type = ptrdiff_t; - using pointer = const char*; + using pointer = absl::Nonnull<const char*>; using reference = const char&; CharIterator() = default; @@ -629,7 +631,8 @@ class Cord { friend Cord; private: - explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {} + explicit CharIterator(absl::Nonnull<const Cord*> cord) + : chunk_iterator_(cord) {} ChunkIterator chunk_iterator_; }; @@ -640,14 +643,14 @@ class Cord { // advanced as a separate `Cord`. `n_bytes` must be less than or equal to the // number of bytes within the Cord; otherwise, behavior is undefined. It is // valid to pass `char_end()` and `0`. - static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes); + static Cord AdvanceAndRead(absl::Nonnull<CharIterator*> it, size_t n_bytes); // Cord::Advance() // // Advances the `Cord::CharIterator` by `n_bytes`. `n_bytes` must be less than // or equal to the number of bytes remaining within the Cord; otherwise, // behavior is undefined. It is valid to pass `char_end()` and `0`. - static void Advance(CharIterator* it, size_t n_bytes); + static void Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes); // Cord::ChunkRemaining() // @@ -696,13 +699,13 @@ class Cord { using iterator = CharIterator; using const_iterator = CharIterator; - explicit CharRange(const Cord* cord) : cord_(cord) {} + explicit CharRange(absl::Nonnull<const Cord*> cord) : cord_(cord) {} CharIterator begin() const; CharIterator end() const; private: - const Cord* cord_; + absl::Nonnull<const Cord*> cord_; }; // Cord::Chars() @@ -761,7 +764,8 @@ class Cord { CharIterator Find(const absl::Cord& needle) const; // Supports absl::Cord as a sink object for absl::Format(). - friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { + friend void AbslFormatFlush(absl::Nonnull<absl::Cord*> cord, + absl::string_view part) { cord->Append(part); } @@ -831,7 +835,8 @@ class Cord { friend bool operator==(const Cord& lhs, const Cord& rhs); friend bool operator==(const Cord& lhs, absl::string_view rhs); - friend const CordzInfo* GetCordzInfoForTesting(const Cord& cord); + friend absl::Nullable<const CordzInfo*> GetCordzInfoForTesting( + const Cord& cord); // Calls the provided function once for each cord chunk, in order. Unlike // Chunks(), this API will not allocate memory. @@ -858,19 +863,22 @@ class Cord { InlineRep& operator=(const InlineRep& src); InlineRep& operator=(InlineRep&& src) noexcept; - explicit constexpr InlineRep(absl::string_view sv, CordRep* rep); + explicit constexpr InlineRep(absl::string_view sv, + absl::Nullable<CordRep*> rep); - void Swap(InlineRep* rhs); + void Swap(absl::Nonnull<InlineRep*> rhs); size_t size() const; - const char* data() const; // Returns nullptr if holding pointer - void set_data(const char* data, size_t n); // Discards pointer, if any - char* set_data(size_t n); // Write data to the result + // Returns nullptr if holding pointer + absl::Nullable<const char*> data() const; + // Discards pointer, if any + void set_data(absl::Nonnull<const char*> data, size_t n); + absl::Nonnull<char*> set_data(size_t n); // Write data to the result // Returns nullptr if holding bytes - absl::cord_internal::CordRep* tree() const; - absl::cord_internal::CordRep* as_tree() const; - const char* as_chars() const; + absl::Nullable<absl::cord_internal::CordRep*> tree() const; + absl::Nonnull<absl::cord_internal::CordRep*> as_tree() const; + absl::Nonnull<const char*> as_chars() const; // Returns non-null iff was holding a pointer - absl::cord_internal::CordRep* clear(); + absl::Nullable<absl::cord_internal::CordRep*> clear(); // Converts to pointer if necessary. void reduce_size(size_t n); // REQUIRES: holding data void remove_prefix(size_t n); // REQUIRES: holding data @@ -879,46 +887,52 @@ class Cord { // Creates a CordRepFlat instance from the current inlined data with `extra' // bytes of desired additional capacity. - CordRepFlat* MakeFlatWithExtraCapacity(size_t extra); + absl::Nonnull<CordRepFlat*> MakeFlatWithExtraCapacity(size_t extra); // Sets the tree value for this instance. `rep` must not be null. // Requires the current instance to hold a tree, and a lock to be held on // any CordzInfo referenced by this instance. The latter is enforced through // the CordzUpdateScope argument. If the current instance is sampled, then // the CordzInfo instance is updated to reference the new `rep` value. - void SetTree(CordRep* rep, const CordzUpdateScope& scope); + void SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope); // Identical to SetTree(), except that `rep` is allowed to be null, in // which case the current instance is reset to an empty value. - void SetTreeOrEmpty(CordRep* rep, const CordzUpdateScope& scope); + void SetTreeOrEmpty(absl::Nullable<CordRep*> rep, + const CordzUpdateScope& scope); // Sets the tree value for this instance, and randomly samples this cord. // This function disregards existing contents in `data_`, and should be // called when a Cord is 'promoted' from an 'uninitialized' or 'inlined' // value to a non-inlined (tree / ring) value. - void EmplaceTree(CordRep* rep, MethodIdentifier method); + void EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method); // Identical to EmplaceTree, except that it copies the parent stack from // the provided `parent` data if the parent is sampled. - void EmplaceTree(CordRep* rep, const InlineData& parent, + void EmplaceTree(absl::Nonnull<CordRep*> rep, const InlineData& parent, MethodIdentifier method); // Commits the change of a newly created, or updated `rep` root value into // this cord. `old_rep` indicates the old (inlined or tree) value of the // cord, and determines if the commit invokes SetTree() or EmplaceTree(). - void CommitTree(const CordRep* old_rep, CordRep* rep, - const CordzUpdateScope& scope, MethodIdentifier method); - - void AppendTreeToInlined(CordRep* tree, MethodIdentifier method); - void AppendTreeToTree(CordRep* tree, MethodIdentifier method); - void AppendTree(CordRep* tree, MethodIdentifier method); - void PrependTreeToInlined(CordRep* tree, MethodIdentifier method); - void PrependTreeToTree(CordRep* tree, MethodIdentifier method); - void PrependTree(CordRep* tree, MethodIdentifier method); + void CommitTree(absl::Nullable<const CordRep*> old_rep, + absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope, + MethodIdentifier method); + + void AppendTreeToInlined(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void AppendTreeToTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void AppendTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method); + void PrependTreeToInlined(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void PrependTreeToTree(absl::Nonnull<CordRep*> tree, + MethodIdentifier method); + void PrependTree(absl::Nonnull<CordRep*> tree, MethodIdentifier method); bool IsSame(const InlineRep& other) const { return data_ == other.data_; } - void CopyTo(std::string* dst) const { + void CopyTo(absl::Nonnull<std::string*> dst) const { // memcpy is much faster when operating on a known size. On most supported // platforms, the small string optimization is large enough that resizing // to 15 bytes does not cause a memory allocation. @@ -930,7 +944,7 @@ class Cord { } // Copies the inline contents into `dst`. Assumes the cord is not empty. - void CopyToArray(char* dst) const; + void CopyToArray(absl::Nonnull<char*> dst) const; bool is_tree() const { return data_.is_tree(); } @@ -943,12 +957,12 @@ class Cord { } // Returns the profiled CordzInfo, or nullptr if not sampled. - absl::cord_internal::CordzInfo* cordz_info() const { + absl::Nullable<absl::cord_internal::CordzInfo*> cordz_info() const { return data_.cordz_info(); } - // Sets the profiled CordzInfo. `cordz_info` must not be null. - void set_cordz_info(cord_internal::CordzInfo* cordz_info) { + // Sets the profiled CordzInfo. + void set_cordz_info(absl::Nonnull<cord_internal::CordzInfo*> cordz_info) { assert(cordz_info != nullptr); data_.set_cordz_info(cordz_info); } @@ -980,19 +994,19 @@ class Cord { InlineRep contents_; // Helper for GetFlat() and TryFlat(). - static bool GetFlatAux(absl::cord_internal::CordRep* rep, - absl::string_view* fragment); + static bool GetFlatAux(absl::Nonnull<absl::cord_internal::CordRep*> rep, + absl::Nonnull<absl::string_view*> fragment); // Helper for ForEachChunk(). static void ForEachChunkAux( - absl::cord_internal::CordRep* rep, + absl::Nonnull<absl::cord_internal::CordRep*> rep, absl::FunctionRef<void(absl::string_view)> callback); // The destructor for non-empty Cords. void DestroyCordSlow(); // Out-of-line implementation of slower parts of logic. - void CopyToArraySlowPath(char* dst) const; + void CopyToArraySlowPath(absl::Nonnull<char*> dst) const; int CompareSlowPath(absl::string_view rhs, size_t compared_size, size_t size_to_compare) const; int CompareSlowPath(const Cord& rhs, size_t compared_size, @@ -1009,8 +1023,8 @@ class Cord { // Returns a new reference to contents_.tree(), or steals an existing // reference if called on an rvalue. - absl::cord_internal::CordRep* TakeRep() const&; - absl::cord_internal::CordRep* TakeRep() &&; + absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() const&; + absl::Nonnull<absl::cord_internal::CordRep*> TakeRep() &&; // Helper for Append(). template <typename C> @@ -1047,7 +1061,8 @@ class Cord { friend class CrcCord; void SetCrcCordState(crc_internal::CrcCordState state); - const crc_internal::CrcCordState* MaybeGetCrcCordState() const; + absl::Nullable<const crc_internal::CrcCordState*> MaybeGetCrcCordState() + const; CharIterator FindImpl(CharIterator it, absl::string_view needle) const; }; @@ -1068,13 +1083,15 @@ namespace cord_internal { // Does non-template-specific `CordRepExternal` initialization. // Requires `data` to be non-empty. -void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep); +void InitializeCordRepExternal(absl::string_view data, + absl::Nonnull<CordRepExternal*> rep); // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer // to it. Requires `data` to be non-empty. template <typename Releaser> // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { +absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data, + Releaser&& releaser) { assert(!data.empty()); using ReleaserType = absl::decay_t<Releaser>; CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>( @@ -1086,7 +1103,7 @@ CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { // Overload for function reference types that dispatches using a function // pointer because there are no `alignof()` or `sizeof()` a function reference. // NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -inline CordRep* NewExternalRep(absl::string_view data, +inline absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data, void (&releaser)(absl::string_view)) { return NewExternalRep(data, &releaser); } @@ -1109,7 +1126,8 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { return cord; } -constexpr Cord::InlineRep::InlineRep(absl::string_view sv, CordRep* rep) +constexpr Cord::InlineRep::InlineRep(absl::string_view sv, + absl::Nullable<CordRep*> rep) : data_(sv, rep) {} inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) @@ -1148,28 +1166,30 @@ inline Cord::InlineRep& Cord::InlineRep::operator=( return *this; } -inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { +inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) { if (rhs == this) { return; } std::swap(data_, rhs->data_); } -inline const char* Cord::InlineRep::data() const { +inline absl::Nullable<const char*> Cord::InlineRep::data() const { return is_tree() ? nullptr : data_.as_chars(); } -inline const char* Cord::InlineRep::as_chars() const { +inline absl::Nonnull<const char*> Cord::InlineRep::as_chars() const { assert(!data_.is_tree()); return data_.as_chars(); } -inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { +inline absl::Nonnull<absl::cord_internal::CordRep*> Cord::InlineRep::as_tree() + const { assert(data_.is_tree()); return data_.as_tree(); } -inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { +inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::tree() + const { if (is_tree()) { return as_tree(); } else { @@ -1181,8 +1201,8 @@ inline size_t Cord::InlineRep::size() const { return is_tree() ? as_tree()->length : inline_size(); } -inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( - size_t extra) { +inline absl::Nonnull<cord_internal::CordRepFlat*> +Cord::InlineRep::MakeFlatWithExtraCapacity(size_t extra) { static_assert(cord_internal::kMinFlatLength >= sizeof(data_), ""); size_t len = data_.inline_size(); auto* result = CordRepFlat::New(len + extra); @@ -1191,20 +1211,21 @@ inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( return result; } -inline void Cord::InlineRep::EmplaceTree(CordRep* rep, +inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep, MethodIdentifier method) { assert(rep); data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, method); } -inline void Cord::InlineRep::EmplaceTree(CordRep* rep, const InlineData& parent, +inline void Cord::InlineRep::EmplaceTree(absl::Nonnull<CordRep*> rep, + const InlineData& parent, MethodIdentifier method) { data_.make_tree(rep); CordzInfo::MaybeTrackCord(data_, parent, method); } -inline void Cord::InlineRep::SetTree(CordRep* rep, +inline void Cord::InlineRep::SetTree(absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope) { assert(rep); assert(data_.is_tree()); @@ -1212,7 +1233,7 @@ inline void Cord::InlineRep::SetTree(CordRep* rep, scope.SetCordRep(rep); } -inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, +inline void Cord::InlineRep::SetTreeOrEmpty(absl::Nullable<CordRep*> rep, const CordzUpdateScope& scope) { assert(data_.is_tree()); if (rep) { @@ -1223,7 +1244,8 @@ inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, scope.SetCordRep(rep); } -inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, +inline void Cord::InlineRep::CommitTree(absl::Nullable<const CordRep*> old_rep, + absl::Nonnull<CordRep*> rep, const CordzUpdateScope& scope, MethodIdentifier method) { if (old_rep) { @@ -1233,7 +1255,7 @@ inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, } } -inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { +inline absl::Nullable<absl::cord_internal::CordRep*> Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); } @@ -1242,7 +1264,7 @@ inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { return result; } -inline void Cord::InlineRep::CopyToArray(char* dst) const { +inline void Cord::InlineRep::CopyToArray(absl::Nonnull<char*> dst) const { assert(!is_tree()); size_t n = inline_size(); assert(n != 0); @@ -1423,7 +1445,8 @@ inline bool Cord::StartsWith(absl::string_view rhs) const { return EqualsImpl(rhs, rhs_size); } -inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { +inline void Cord::ChunkIterator::InitTree( + absl::Nonnull<cord_internal::CordRep*> tree) { tree = cord_internal::SkipCrcNode(tree); if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); @@ -1433,12 +1456,13 @@ inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { } } -inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) { +inline Cord::ChunkIterator::ChunkIterator( + absl::Nonnull<cord_internal::CordRep*> tree) { bytes_remaining_ = tree->length; InitTree(tree); } -inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) { +inline Cord::ChunkIterator::ChunkIterator(absl::Nonnull<const Cord*> cord) { if (CordRep* tree = cord->contents_.tree()) { bytes_remaining_ = tree->length; if (ABSL_PREDICT_TRUE(bytes_remaining_ != 0)) { @@ -1578,12 +1602,13 @@ inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const { return chunk_iterator_->data(); } -inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) { +inline Cord Cord::AdvanceAndRead(absl::Nonnull<CharIterator*> it, + size_t n_bytes) { assert(it != nullptr); return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); } -inline void Cord::Advance(CharIterator* it, size_t n_bytes) { +inline void Cord::Advance(absl::Nonnull<CharIterator*> it, size_t n_bytes) { assert(it != nullptr); it->chunk_iterator_.AdvanceBytes(n_bytes); } |