diff options
author | heretic <heretic@yandex-team.ru> | 2022-02-10 16:45:43 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:43 +0300 |
commit | 397cbe258b9e064f49c4ca575279f02f39fef76e (patch) | |
tree | a0b0eb3cca6a14e4e8ea715393637672fa651284 /contrib/restricted/abseil-cpp-tstring/y_absl/strings | |
parent | 43f5a35593ebc9f6bcea619bb170394ea7ae468e (diff) | |
download | ydb-397cbe258b9e064f49c4ca575279f02f39fef76e.tar.gz |
Restoring authorship annotation for <heretic@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp-tstring/y_absl/strings')
52 files changed, 5329 insertions, 5329 deletions
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/.yandex_meta/licenses.list.txt b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/.yandex_meta/licenses.list.txt index 9d8552c68c..bd499f8070 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/.yandex_meta/licenses.list.txt +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/.yandex_meta/licenses.list.txt @@ -1,46 +1,46 @@ -====================Apache-2.0==================== -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -====================Apache-2.0==================== -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -====================COPYRIGHT==================== -// Copyright 2017 The Abseil Authors. - - -====================COPYRIGHT==================== -// Copyright 2018 The Abseil Authors. - - -====================COPYRIGHT==================== +====================Apache-2.0==================== +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +====================Apache-2.0==================== +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +====================COPYRIGHT==================== +// Copyright 2017 The Abseil Authors. + + +====================COPYRIGHT==================== +// Copyright 2018 The Abseil Authors. + + +====================COPYRIGHT==================== // Copyright 2019 The Abseil Authors. ====================COPYRIGHT==================== -// Copyright 2020 The Abseil Authors. - - -====================COPYRIGHT==================== -// Copyright 2021 The Abseil Authors. +// Copyright 2020 The Abseil Authors. + + +====================COPYRIGHT==================== +// Copyright 2021 The Abseil Authors. diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc index 9515ca24dd..865ed0dfeb 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/charconv.cc @@ -20,7 +20,7 @@ #include <cstring> #include "y_absl/base/casts.h" -#include "y_absl/numeric/bits.h" +#include "y_absl/numeric/bits.h" #include "y_absl/numeric/int128.h" #include "y_absl/strings/internal/charconv_bigint.h" #include "y_absl/strings/internal/charconv_parse.h" @@ -242,11 +242,11 @@ struct CalculatedFloat { // Returns the bit width of the given uint128. (Equivalently, returns 128 // minus the number of leading zero bits.) -unsigned BitWidth(uint128 value) { +unsigned BitWidth(uint128 value) { if (Uint128High64(value) == 0) { - return static_cast<unsigned>(bit_width(Uint128Low64(value))); + return static_cast<unsigned>(bit_width(Uint128Low64(value))); } - return 128 - countl_zero(Uint128High64(value)); + return 128 - countl_zero(Uint128High64(value)); } // Calculates how far to the right a mantissa needs to be shifted to create a @@ -519,7 +519,7 @@ CalculatedFloat CalculateFromParsedHexadecimal( const strings_internal::ParsedFloat& parsed_hex) { uint64_t mantissa = parsed_hex.mantissa; int exponent = parsed_hex.exponent; - auto mantissa_width = static_cast<unsigned>(bit_width(mantissa)); + auto mantissa_width = static_cast<unsigned>(bit_width(mantissa)); const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent); bool result_exact; exponent += shift; @@ -619,10 +619,10 @@ from_chars_result FromCharsImpl(const char* first, const char* last, // Either we failed to parse a hex float after the "0x", or we read // "0xinf" or "0xnan" which we don't want to match. // - // However, a string that begins with "0x" also begins with "0", which + // However, a string that begins with "0x" also begins with "0", which // is normally a valid match for the number zero. So we want these // strings to match zero unless fmt_flags is `scientific`. (This flag - // means an exponent is required, which the string "0" does not have.) + // means an exponent is required, which the string "0" does not have.) if (fmt_flags == chars_format::scientific) { result.ec = std::errc::invalid_argument; } else { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.cc index 0de4ea1b3c..c37f2c3400 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.cc @@ -15,12 +15,12 @@ #include "y_absl/strings/cord.h" #include <algorithm> -#include <atomic> +#include <atomic> #include <cstddef> #include <cstdio> #include <cstdlib> #include <iomanip> -#include <iostream> +#include <iostream> #include <limits> #include <ostream> #include <sstream> @@ -30,14 +30,14 @@ #include "y_absl/base/casts.h" #include "y_absl/base/internal/raw_logging.h" -#include "y_absl/base/macros.h" +#include "y_absl/base/macros.h" #include "y_absl/base/port.h" #include "y_absl/container/fixed_array.h" #include "y_absl/container/inlined_vector.h" #include "y_absl/strings/escaping.h" #include "y_absl/strings/internal/cord_internal.h" #include "y_absl/strings/internal/cord_rep_btree.h" -#include "y_absl/strings/internal/cord_rep_flat.h" +#include "y_absl/strings/internal/cord_rep_flat.h" #include "y_absl/strings/internal/cordz_statistics.h" #include "y_absl/strings/internal/cordz_update_scope.h" #include "y_absl/strings/internal/cordz_update_tracker.h" @@ -54,15 +54,15 @@ using ::y_absl::cord_internal::CordRep; using ::y_absl::cord_internal::CordRepBtree; using ::y_absl::cord_internal::CordRepConcat; using ::y_absl::cord_internal::CordRepExternal; -using ::y_absl::cord_internal::CordRepFlat; +using ::y_absl::cord_internal::CordRepFlat; using ::y_absl::cord_internal::CordRepSubstring; using ::y_absl::cord_internal::CordzUpdateTracker; using ::y_absl::cord_internal::InlineData; using ::y_absl::cord_internal::kMaxFlatLength; -using ::y_absl::cord_internal::kMinFlatLength; +using ::y_absl::cord_internal::kMinFlatLength; -using ::y_absl::cord_internal::kInlinedVectorSize; -using ::y_absl::cord_internal::kMaxBytesToCopy; +using ::y_absl::cord_internal::kInlinedVectorSize; +using ::y_absl::cord_internal::kMaxBytesToCopy; constexpr uint64_t Fibonacci(unsigned char n, uint64_t a = 0, uint64_t b = 1) { return n == 0 ? a : Fibonacci(n - 1, b, a + b); @@ -77,18 +77,18 @@ static_assert(Fibonacci(63) == 6557470319842, // The root node depth is allowed to become twice as large to reduce rebalancing // for larger strings (see IsRootBalanced). static constexpr uint64_t min_length[] = { - Fibonacci(2), Fibonacci(3), Fibonacci(4), Fibonacci(5), - Fibonacci(6), Fibonacci(7), Fibonacci(8), Fibonacci(9), - Fibonacci(10), Fibonacci(11), Fibonacci(12), Fibonacci(13), - Fibonacci(14), Fibonacci(15), Fibonacci(16), Fibonacci(17), - Fibonacci(18), Fibonacci(19), Fibonacci(20), Fibonacci(21), - Fibonacci(22), Fibonacci(23), Fibonacci(24), Fibonacci(25), - Fibonacci(26), Fibonacci(27), Fibonacci(28), Fibonacci(29), - Fibonacci(30), Fibonacci(31), Fibonacci(32), Fibonacci(33), - Fibonacci(34), Fibonacci(35), Fibonacci(36), Fibonacci(37), - Fibonacci(38), Fibonacci(39), Fibonacci(40), Fibonacci(41), - Fibonacci(42), Fibonacci(43), Fibonacci(44), Fibonacci(45), - Fibonacci(46), Fibonacci(47), + Fibonacci(2), Fibonacci(3), Fibonacci(4), Fibonacci(5), + Fibonacci(6), Fibonacci(7), Fibonacci(8), Fibonacci(9), + Fibonacci(10), Fibonacci(11), Fibonacci(12), Fibonacci(13), + Fibonacci(14), Fibonacci(15), Fibonacci(16), Fibonacci(17), + Fibonacci(18), Fibonacci(19), Fibonacci(20), Fibonacci(21), + Fibonacci(22), Fibonacci(23), Fibonacci(24), Fibonacci(25), + Fibonacci(26), Fibonacci(27), Fibonacci(28), Fibonacci(29), + Fibonacci(30), Fibonacci(31), Fibonacci(32), Fibonacci(33), + Fibonacci(34), Fibonacci(35), Fibonacci(36), Fibonacci(37), + Fibonacci(38), Fibonacci(39), Fibonacci(40), Fibonacci(41), + Fibonacci(42), Fibonacci(43), Fibonacci(44), Fibonacci(45), + Fibonacci(46), Fibonacci(47), 0xffffffffffffffffull, // Avoid overflow }; @@ -96,8 +96,8 @@ static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length); static inline bool btree_enabled() { return cord_internal::cord_btree_enabled.load( - std::memory_order_relaxed); -} + std::memory_order_relaxed); +} static inline bool IsRootBalanced(CordRep* node) { if (!node->IsConcat()) { @@ -114,8 +114,8 @@ static inline bool IsRootBalanced(CordRep* node) { } static CordRep* Rebalance(CordRep* node); -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, - int indent = 0); +static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, + int indent = 0); static bool VerifyNode(CordRep* root, CordRep* start_node, bool full_validation); @@ -158,14 +158,14 @@ static void SetConcatChildren(CordRepConcat* concat, CordRep* left, // The returned node has a refcount of 1. static CordRep* RawConcat(CordRep* left, CordRep* right) { // Avoid making degenerate concat nodes (one child is empty) - if (left == nullptr) return right; - if (right == nullptr) return left; - if (left->length == 0) { - CordRep::Unref(left); + if (left == nullptr) return right; + if (right == nullptr) return left; + if (left->length == 0) { + CordRep::Unref(left); return right; } - if (right->length == 0) { - CordRep::Unref(right); + if (right->length == 0) { + CordRep::Unref(right); return left; } @@ -204,23 +204,23 @@ static CordRep* MakeBalancedTree(CordRep** reps, size_t n) { return reps[0]; } -static CordRepFlat* CreateFlat(const char* data, size_t length, +static CordRepFlat* CreateFlat(const char* data, size_t length, size_t alloc_hint) { - CordRepFlat* flat = CordRepFlat::New(length + alloc_hint); - flat->length = length; - memcpy(flat->Data(), data, length); - return flat; -} - + CordRepFlat* flat = CordRepFlat::New(length + alloc_hint); + flat->length = length; + memcpy(flat->Data(), data, length); + return flat; +} + // Creates a new flat or Btree out of the specified array. -// The returned node has a refcount of 1. +// The returned node has a refcount of 1. static CordRep* NewBtree(const char* data, size_t length, size_t alloc_hint) { - if (length <= kMaxFlatLength) { - return CreateFlat(data, length, alloc_hint); + if (length <= kMaxFlatLength) { + return CreateFlat(data, length, alloc_hint); } - CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0); - data += kMaxFlatLength; - length -= kMaxFlatLength; + CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0); + data += kMaxFlatLength; + length -= kMaxFlatLength; auto* root = CordRepBtree::Create(flat); return CordRepBtree::Append(root, {data, length}, alloc_hint); } @@ -231,14 +231,14 @@ static CordRep* NewTree(const char* data, size_t length, size_t alloc_hint) { if (length == 0) return nullptr; if (btree_enabled()) { return NewBtree(data, length, alloc_hint); - } + } y_absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1); size_t n = 0; do { const size_t len = std::min(length, kMaxFlatLength); - CordRepFlat* rep = CordRepFlat::New(len + alloc_hint); + CordRepFlat* rep = CordRepFlat::New(len + alloc_hint); rep->length = len; - memcpy(rep->Data(), data, len); + memcpy(rep->Data(), data, len); reps[n++] = VerifyTree(rep); data += len; length -= len; @@ -248,12 +248,12 @@ static CordRep* NewTree(const char* data, size_t length, size_t alloc_hint) { namespace cord_internal { -void InitializeCordRepExternal(y_absl::string_view data, CordRepExternal* rep) { +void InitializeCordRepExternal(y_absl::string_view data, CordRepExternal* rep) { assert(!data.empty()); rep->length = data.size(); rep->tag = EXTERNAL; rep->base = data.data(); - VerifyTree(rep); + VerifyTree(rep); } } // namespace cord_internal @@ -261,7 +261,7 @@ void InitializeCordRepExternal(y_absl::string_view data, CordRepExternal* rep) { static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) { // Never create empty substring nodes if (length == 0) { - CordRep::Unref(child); + CordRep::Unref(child); return nullptr; } else { CordRepSubstring* rep = new CordRepSubstring(); @@ -306,35 +306,35 @@ static CordRep* CordRepFromString(TString&& src) { // -------------------------------------------------------------------- // Cord::InlineRep functions -constexpr unsigned char Cord::InlineRep::kMaxInline; +constexpr unsigned char Cord::InlineRep::kMaxInline; inline void Cord::InlineRep::set_data(const char* data, size_t n, bool nullify_tail) { static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15"); - cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail); - set_inline_size(n); + cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail); + set_inline_size(n); } inline char* Cord::InlineRep::set_data(size_t n) { assert(n <= kMaxInline); - ResetToEmpty(); - set_inline_size(n); - return data_.as_chars(); + ResetToEmpty(); + set_inline_size(n); + return data_.as_chars(); } inline void Cord::InlineRep::reduce_size(size_t n) { - size_t tag = inline_size(); + size_t tag = inline_size(); assert(tag <= kMaxInline); assert(tag >= n); tag -= n; - memset(data_.as_chars() + tag, 0, n); - set_inline_size(static_cast<char>(tag)); + memset(data_.as_chars() + tag, 0, n); + set_inline_size(static_cast<char>(tag)); } inline void Cord::InlineRep::remove_prefix(size_t n) { - cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n, - inline_size() - n); + cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n, + inline_size() - n); reduce_size(n); } @@ -342,8 +342,8 @@ inline void Cord::InlineRep::remove_prefix(size_t n) { // Directly returns `rep` if `rep` is already a CordRepBtree. static CordRepBtree* ForceBtree(CordRep* rep) { return rep->IsBtree() ? rep->btree() : CordRepBtree::Create(rep); -} - +} + void Cord::InlineRep::AppendTreeToInlined(CordRep* tree, MethodIdentifier method) { assert(!is_tree()); @@ -405,7 +405,7 @@ void Cord::InlineRep::PrependTreeToTree(CordRep* tree, } void Cord::InlineRep::PrependTree(CordRep* tree, MethodIdentifier method) { - assert(tree != nullptr); + assert(tree != nullptr); if (data_.is_tree()) { PrependTreeToTree(tree, method); } else { @@ -421,13 +421,13 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region, size_t* size, size_t max_length) { if (root->IsBtree() && root->refcount.IsMutable()) { Span<char> span = root->btree()->GetAppendBuffer(max_length); - if (!span.empty()) { - *region = span.data(); - *size = span.size(); - return true; - } - } - + if (!span.empty()) { + *region = span.data(); + *size = span.size(); + return true; + } + } + // Search down the right-hand path for a non-full FLAT node. CordRep* dst = root; while (dst->IsConcat() && dst->refcount.IsMutable()) { @@ -441,7 +441,7 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region, } const size_t in_use = dst->length; - const size_t capacity = dst->flat()->Capacity(); + const size_t capacity = dst->flat()->Capacity(); if (in_use == capacity) { *region = nullptr; *size = 0; @@ -456,7 +456,7 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region, } dst->length += size_increase; - *region = dst->flat()->Data() + in_use; + *region = dst->flat()->Data() + in_use; *size = size_increase; return true; } @@ -474,8 +474,8 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, *region = data_.as_chars() + sz; *size = has_length ? length : available; set_inline_size(has_length ? sz + length : kMaxInline); - return; - } + return; + } } size_t extra = has_length ? length : (std::max)(sz, kMinFlatLength); @@ -489,14 +489,14 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, // Allocate new node. CordRepFlat* new_node = CordRepFlat::New(extra); new_node->length = std::min(new_node->Capacity(), length); - *region = new_node->Data(); + *region = new_node->Data(); *size = new_node->length; - + if (btree_enabled()) { rep = CordRepBtree::Append(ForceBtree(rep), new_node); } else { rep = Concat(rep, new_node); - } + } CommitTree(root, rep, scope, method); } @@ -522,7 +522,7 @@ static bool RepMemoryUsageDataEdge(const CordRep* rep, sizeof(cord_internal::CordRepExternalImpl<intptr_t>) + rep->length; return true; - } + } return false; } @@ -530,7 +530,7 @@ static bool RepMemoryUsageDataEdge(const CordRep* rep, // will return true. static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) { if (rep->IsFlat()) { - *total_mem_usage += rep->flat()->AllocatedSize(); + *total_mem_usage += rep->flat()->AllocatedSize(); return true; } if (rep->IsExternal()) { @@ -570,7 +570,7 @@ void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { void Cord::InlineRep::UnrefTree() { if (is_tree()) { CordzInfo::MaybeUntrackCord(data_.cordz_info()); - CordRep::Unref(tree()); + CordRep::Unref(tree()); } } @@ -588,18 +588,18 @@ Cord::Cord(y_absl::string_view src, MethodIdentifier method) } } -template <typename T, Cord::EnableIfString<T>> +template <typename T, Cord::EnableIfString<T>> Cord::Cord(T&& src) : contents_(InlineData::kDefaultInit) { if (src.size() <= InlineRep::kMaxInline) { contents_.set_data(src.data(), src.size(), true); - } else { + } else { CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.EmplaceTree(rep, CordzUpdateTracker::kConstructorString); - } -} - -template Cord::Cord(TString&& src); - + } +} + +template Cord::Cord(TString&& src); + // The destruction code is separate so that the compiler can determine // that it does not need to call the destructor on a moved-from Cord. void Cord::DestroyCordSlow() { @@ -612,9 +612,9 @@ void Cord::DestroyCordSlow() { // Mutators void Cord::Clear() { - if (CordRep* tree = contents_.clear()) { - CordRep::Unref(tree); - } + if (CordRep* tree = contents_.clear()) { + CordRep::Unref(tree); + } } Cord& Cord::AssignLargeString(TString&& src) { @@ -658,12 +658,12 @@ Cord& Cord::operator=(y_absl::string_view src) { } contents_.SetTree(NewTree(data, length, 0), scope); CordRep::Unref(tree); - } else { + } else { contents_.EmplaceTree(NewTree(data, length, 0), method); - } - return *this; -} - + } + return *this; +} + // TODO(sanjay): Move to Cord::InlineRep section of file. For now, // we keep it here to make diffs easier. void Cord::InlineRep::AppendArray(y_absl::string_view src, @@ -680,15 +680,15 @@ void Cord::InlineRep::AppendArray(y_absl::string_view src, memcpy(region, src.data(), appended); } } else { - // Try to fit in the inline buffer if possible. - size_t inline_length = inline_size(); + // Try to fit in the inline buffer if possible. + size_t inline_length = inline_size(); if (src.size() <= kMaxInline - inline_length) { - // Append new data to embedded array + // Append new data to embedded array memcpy(data_.as_chars() + inline_length, src.data(), src.size()); set_inline_size(inline_length + src.size()); - return; - } - + return; + } + // Allocate flat to be a perfect fit on first append exceeding inlined size. // Subsequent growth will use amortized growth until we reach maximum flat // size. @@ -725,12 +725,12 @@ void Cord::InlineRep::AppendArray(y_absl::string_view src, length = std::max<size_t>(rep->length / 10, src.size()); } rep = Concat(rep, NewTree(src.data(), src.size(), length - src.size())); - } + } CommitTree(root, rep, scope, method); } inline CordRep* Cord::TakeRep() const& { - return CordRep::Ref(contents_.tree()); + return CordRep::Ref(contents_.tree()); } inline CordRep* Cord::TakeRep() && { @@ -781,7 +781,7 @@ inline void Cord::AppendImpl(C&& src) { return; } - // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize) + // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize) CordRep* rep = std::forward<C>(src).TakeRep(); contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord); } @@ -794,22 +794,22 @@ void Cord::Append(Cord&& src) { AppendImpl(std::move(src)); } -template <typename T, Cord::EnableIfString<T>> -void Cord::Append(T&& src) { - if (src.size() <= kMaxBytesToCopy) { - Append(y_absl::string_view(src)); - } else { +template <typename T, Cord::EnableIfString<T>> +void Cord::Append(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Append(y_absl::string_view(src)); + } else { CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.AppendTree(rep, CordzUpdateTracker::kAppendString); - } -} - -template void Cord::Append(TString&& src); - + } +} + +template void Cord::Append(TString&& src); + void Cord::Prepend(const Cord& src) { CordRep* src_tree = src.contents_.tree(); if (src_tree != nullptr) { - CordRep::Ref(src_tree); + CordRep::Ref(src_tree); contents_.PrependTree(src_tree, CordzUpdateTracker::kPrependCord); return; } @@ -821,37 +821,37 @@ void Cord::Prepend(const Cord& src) { void Cord::PrependArray(y_absl::string_view src, MethodIdentifier method) { if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. - if (!contents_.is_tree()) { - size_t cur_size = contents_.inline_size(); - if (cur_size + src.size() <= InlineRep::kMaxInline) { - // Use embedded storage. - char data[InlineRep::kMaxInline + 1] = {0}; - memcpy(data, src.data(), src.size()); - memcpy(data + src.size(), contents_.data(), cur_size); - memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1); - contents_.set_inline_size(cur_size + src.size()); - return; - } - } + if (!contents_.is_tree()) { + size_t cur_size = contents_.inline_size(); + if (cur_size + src.size() <= InlineRep::kMaxInline) { + // Use embedded storage. + char data[InlineRep::kMaxInline + 1] = {0}; + memcpy(data, src.data(), src.size()); + memcpy(data + src.size(), contents_.data(), cur_size); + memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1); + contents_.set_inline_size(cur_size + src.size()); + return; + } + } CordRep* rep = NewTree(src.data(), src.size(), 0); contents_.PrependTree(rep, method); -} - -template <typename T, Cord::EnableIfString<T>> -inline void Cord::Prepend(T&& src) { - if (src.size() <= kMaxBytesToCopy) { - Prepend(y_absl::string_view(src)); +} + +template <typename T, Cord::EnableIfString<T>> +inline void Cord::Prepend(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Prepend(y_absl::string_view(src)); } else { CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.PrependTree(rep, CordzUpdateTracker::kPrependString); } } -template void Cord::Prepend(TString&& src); - +template void Cord::Prepend(TString&& src); + static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { if (n >= node->length) return nullptr; - if (n == 0) return CordRep::Ref(node); + if (n == 0) return CordRep::Ref(node); y_absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack; while (node->IsConcat()) { @@ -869,7 +869,7 @@ static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { assert(n <= node->length); if (n == 0) { - CordRep::Ref(node); + CordRep::Ref(node); } else { size_t start = n; size_t len = node->length - n; @@ -878,10 +878,10 @@ static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { start += node->substring()->start; node = node->substring()->child; } - node = NewSubstring(CordRep::Ref(node), start, len); + node = NewSubstring(CordRep::Ref(node), start, len); } while (!rhs_stack.empty()) { - node = Concat(node, CordRep::Ref(rhs_stack.back())); + node = Concat(node, CordRep::Ref(rhs_stack.back())); rhs_stack.pop_back(); } return node; @@ -892,7 +892,7 @@ static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { // edited in place iff that node and all its ancestors have a refcount of 1. static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) { if (n >= node->length) return nullptr; - if (n == 0) return CordRep::Ref(node); + if (n == 0) return CordRep::Ref(node); y_absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack; bool inplace_ok = node->refcount.IsMutable(); @@ -912,11 +912,11 @@ static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) { assert(n <= node->length); if (n == 0) { - CordRep::Ref(node); + CordRep::Ref(node); } else if (inplace_ok && !node->IsExternal()) { // Consider making a new buffer if the current node capacity is much // larger than the new length. - CordRep::Ref(node); + CordRep::Ref(node); node->length -= n; } else { size_t start = 0; @@ -925,10 +925,10 @@ static CordRep* RemoveSuffixFrom(CordRep* node, size_t n) { start = node->substring()->start; node = node->substring()->child; } - node = NewSubstring(CordRep::Ref(node), start, len); + node = NewSubstring(CordRep::Ref(node), start, len); } while (!lhs_stack.empty()) { - node = Concat(CordRep::Ref(lhs_stack.back()), node); + node = Concat(CordRep::Ref(lhs_stack.back()), node); lhs_stack.pop_back(); } return node; @@ -1006,13 +1006,13 @@ static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) { results.pop_back(); results.push_back(Concat(left, right)); } else if (pos == 0 && n == node->length) { - results.push_back(CordRep::Ref(node)); + results.push_back(CordRep::Ref(node)); } else if (!node->IsConcat()) { if (node->IsSubstring()) { pos += node->substring()->start; node = node->substring()->child; } - results.push_back(NewSubstring(CordRep::Ref(node), pos, n)); + results.push_back(NewSubstring(CordRep::Ref(node), pos, n)); } else if (pos + n <= node->concat()->left->length) { todo.push_back(SubRange(node->concat()->left, pos, n)); } else if (pos >= node->concat()->left->length) { @@ -1056,7 +1056,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const { ++it; } cord_internal::SmallMemmove(dest, it->data(), remaining_size); - sub_cord.contents_.set_inline_size(new_size); + sub_cord.contents_.set_inline_size(new_size); return sub_cord; } @@ -1100,9 +1100,9 @@ class CordForest { concat_node->left = concat_freelist_; concat_freelist_ = concat_node; } else { - CordRep::Ref(concat_node->right); - CordRep::Ref(concat_node->left); - CordRep::Unref(concat_node); + CordRep::Ref(concat_node->right); + CordRep::Ref(concat_node->left); + CordRep::Unref(concat_node); } } else { AddNode(node); @@ -1135,7 +1135,7 @@ class CordForest { void AddNode(CordRep* node) { CordRep* sum = nullptr; - // Collect together everything with which we will merge with node + // Collect together everything with which we will merge with node int i = 0; for (; node->length > min_length[i + 1]; ++i) { auto& tree_at_i = trees_[i]; @@ -1252,13 +1252,13 @@ bool ComputeCompareResult<bool>(int memcmp_res) { // Helper routine. Locates the first flat or external chunk of the Cord without // initializing the iterator, and returns a string_view referencing the data. inline y_absl::string_view Cord::InlineRep::FindFlatStartPiece() const { - if (!is_tree()) { - return y_absl::string_view(data_.as_chars(), data_.inline_size()); + if (!is_tree()) { + return y_absl::string_view(data_.as_chars(), data_.inline_size()); } CordRep* node = tree(); if (node->IsFlat()) { - return y_absl::string_view(node->flat()->Data(), node->length); + return y_absl::string_view(node->flat()->Data(), node->length); } if (node->IsExternal()) { @@ -1272,8 +1272,8 @@ inline y_absl::string_view Cord::InlineRep::FindFlatStartPiece() const { tree = tree->Edge(CordRepBtree::kFront)->btree(); } return tree->Data(tree->begin()); - } - + } + // Walk down the left branches until we hit a non-CONCAT node. while (node->IsConcat()) { node = node->concat()->left; @@ -1290,7 +1290,7 @@ inline y_absl::string_view Cord::InlineRep::FindFlatStartPiece() const { } if (node->IsFlat()) { - return y_absl::string_view(node->flat()->Data() + offset, length); + return y_absl::string_view(node->flat()->Data() + offset, length); } assert(node->IsExternal() && "Expect FLAT or EXTERNAL node here"); @@ -1473,22 +1473,22 @@ void Cord::CopyToArraySlowPath(char* dst) const { } } -Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() { - auto& stack_of_right_children = stack_of_right_children_; - if (stack_of_right_children.empty()) { +Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() { + auto& stack_of_right_children = stack_of_right_children_; + if (stack_of_right_children.empty()) { assert(!current_chunk_.empty()); // Called on invalid iterator. // We have reached the end of the Cord. return *this; } // Process the next node on the stack. - CordRep* node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); + CordRep* node = stack_of_right_children.back(); + stack_of_right_children.pop_back(); // Walk down the left branches until we hit a non-CONCAT node. Save the // right children to the stack for subsequent traversal. while (node->IsConcat()) { - stack_of_right_children.push_back(node->concat()->right); + stack_of_right_children.push_back(node->concat()->right); node = node->concat()->left; } @@ -1510,8 +1510,8 @@ Cord::ChunkIterator& Cord::ChunkIterator::AdvanceStack() { } Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { - ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && - "Attempted to iterate past `end()`"); + ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && + "Attempted to iterate past `end()`"); Cord subcord; auto constexpr method = CordzUpdateTracker::kCordReader; @@ -1532,30 +1532,30 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { } return subcord; } - + if (btree_reader_) { - size_t chunk_size = current_chunk_.size(); - if (n <= chunk_size && n <= kMaxBytesToCopy) { + size_t chunk_size = current_chunk_.size(); + if (n <= chunk_size && n <= kMaxBytesToCopy) { subcord = Cord(current_chunk_.substr(0, n), method); if (n < chunk_size) { current_chunk_.remove_prefix(n); } else { current_chunk_ = btree_reader_.Next(); } - } else { + } else { CordRep* rep; current_chunk_ = btree_reader_.Read(n, chunk_size, rep); subcord.contents_.EmplaceTree(rep, method); - } + } bytes_remaining_ -= n; - return subcord; - } - - auto& stack_of_right_children = stack_of_right_children_; + return subcord; + } + + auto& stack_of_right_children = stack_of_right_children_; if (n < current_chunk_.size()) { // Range to read is a proper subrange of the current chunk. assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); + CordRep* subnode = CordRep::Ref(current_leaf_); const char* data = subnode->IsExternal() ? subnode->external()->base : subnode->flat()->Data(); subnode = NewSubstring(subnode, current_chunk_.data() - data, n); @@ -1567,7 +1567,7 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { // Range to read begins with a proper subrange of the current chunk. assert(!current_chunk_.empty()); assert(current_leaf_ != nullptr); - CordRep* subnode = CordRep::Ref(current_leaf_); + CordRep* subnode = CordRep::Ref(current_leaf_); if (current_chunk_.size() < subnode->length) { const char* data = subnode->IsExternal() ? subnode->external()->base : subnode->flat()->Data(); @@ -1580,20 +1580,20 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { // Process the next node(s) on the stack, reading whole subtrees depending on // their length and how many bytes we are advancing. CordRep* node = nullptr; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); + while (!stack_of_right_children.empty()) { + node = stack_of_right_children.back(); + stack_of_right_children.pop_back(); if (node->length > n) break; // TODO(qrczak): This might unnecessarily recreate existing concat nodes. // Avoiding that would need pretty complicated logic (instead of - // current_leaf, keep current_subtree_ which points to the highest node + // current_leaf, keep current_subtree_ which points to the highest node // such that the current leaf can be found on the path of left children // starting from current_subtree_; delay creating subnode while node is // below current_subtree_; find the proper node along the path of left // children starting from current_subtree_ if this loop exits while staying // below current_subtree_; etc.; alternatively, push parents instead of // right children on the stack). - subnode = Concat(subnode, CordRep::Ref(node)); + subnode = Concat(subnode, CordRep::Ref(node)); n -= node->length; bytes_remaining_ -= node->length; node = nullptr; @@ -1611,11 +1611,11 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { while (node->IsConcat()) { if (node->concat()->left->length > n) { // Push right, descend left. - stack_of_right_children.push_back(node->concat()->right); + stack_of_right_children.push_back(node->concat()->right); node = node->concat()->left; } else { // Read left, descend right. - subnode = Concat(subnode, CordRep::Ref(node->concat()->left)); + subnode = Concat(subnode, CordRep::Ref(node->concat()->left)); n -= node->concat()->left->length; bytes_remaining_ -= node->concat()->left->length; node = node->concat()->right; @@ -1634,9 +1634,9 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { // chunk. assert(node->IsExternal() || node->IsFlat()); assert(length > n); - if (n > 0) { - subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n)); - } + if (n > 0) { + subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n)); + } const char* data = node->IsExternal() ? node->external()->base : node->flat()->Data(); current_chunk_ = y_absl::string_view(data + offset + n, length - n); @@ -1654,19 +1654,19 @@ void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { n -= current_chunk_.size(); bytes_remaining_ -= current_chunk_.size(); - if (stack_of_right_children_.empty()) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } - + if (stack_of_right_children_.empty()) { + // We have reached the end of the Cord. + assert(bytes_remaining_ == 0); + return; + } + // Process the next node(s) on the stack, skipping whole subtrees depending on // their length and how many bytes we are advancing. CordRep* node = nullptr; - auto& stack_of_right_children = stack_of_right_children_; - while (!stack_of_right_children.empty()) { - node = stack_of_right_children.back(); - stack_of_right_children.pop_back(); + auto& stack_of_right_children = stack_of_right_children_; + while (!stack_of_right_children.empty()) { + node = stack_of_right_children.back(); + stack_of_right_children.pop_back(); if (node->length > n) break; n -= node->length; bytes_remaining_ -= node->length; @@ -1684,7 +1684,7 @@ void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { while (node->IsConcat()) { if (node->concat()->left->length > n) { // Push right, descend left. - stack_of_right_children.push_back(node->concat()->right); + stack_of_right_children.push_back(node->concat()->right); node = node->concat()->left; } else { // Skip left, descend right. @@ -1712,7 +1712,7 @@ void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { } char Cord::operator[](size_t i) const { - ABSL_HARDENING_ASSERT(i < size()); + ABSL_HARDENING_ASSERT(i < size()); size_t offset = i; const CordRep* rep = contents_.tree(); if (rep == nullptr) { @@ -1723,7 +1723,7 @@ char Cord::operator[](size_t i) const { assert(offset < rep->length); if (rep->IsFlat()) { // Get the "i"th character directly from the flat array. - return rep->flat()->Data()[offset]; + return rep->flat()->Data()[offset]; } else if (rep->IsBtree()) { return rep->btree()->GetCharacter(offset); } else if (rep->IsExternal()) { @@ -1757,9 +1757,9 @@ y_absl::string_view Cord::FlattenSlowPath() { // Try to put the contents into a new flat rep. If they won't fit in the // biggest possible flat node, use an external rep instead. if (total_size <= kMaxFlatLength) { - new_rep = CordRepFlat::New(total_size); + new_rep = CordRepFlat::New(total_size); new_rep->length = total_size; - new_buffer = new_rep->flat()->Data(); + new_buffer = new_rep->flat()->Data(); CopyToArraySlowPath(new_buffer); } else { new_buffer = std::allocator<char>().allocate(total_size); @@ -1779,7 +1779,7 @@ y_absl::string_view Cord::FlattenSlowPath() { /* static */ bool Cord::GetFlatAux(CordRep* rep, y_absl::string_view* fragment) { assert(rep != nullptr); if (rep->IsFlat()) { - *fragment = y_absl::string_view(rep->flat()->Data(), rep->length); + *fragment = y_absl::string_view(rep->flat()->Data(), rep->length); return true; } else if (rep->IsExternal()) { *fragment = y_absl::string_view(rep->external()->base, rep->length); @@ -1789,8 +1789,8 @@ y_absl::string_view Cord::FlattenSlowPath() { } else if (rep->IsSubstring()) { CordRep* child = rep->substring()->child; if (child->IsFlat()) { - *fragment = y_absl::string_view( - child->flat()->Data() + rep->substring()->start, rep->length); + *fragment = y_absl::string_view( + child->flat()->Data() + rep->substring()->start, rep->length); return true; } else if (child->IsExternal()) { *fragment = y_absl::string_view( @@ -1808,14 +1808,14 @@ y_absl::string_view Cord::FlattenSlowPath() { y_absl::cord_internal::CordRep* rep, y_absl::FunctionRef<void(y_absl::string_view)> callback) { if (rep->IsBtree()) { - ChunkIterator it(rep), end; - while (it != end) { - callback(*it); - ++it; - } - return; - } - + ChunkIterator it(rep), end; + while (it != end) { + callback(*it); + ++it; + } + return; + } + assert(rep != nullptr); int stack_pos = 0; constexpr int stack_max = 128; @@ -1857,8 +1857,8 @@ y_absl::string_view Cord::FlattenSlowPath() { } } -static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, - int indent) { +static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, + int indent) { const int kIndentStep = 1; y_absl::InlinedVector<CordRep*, kInlinedVectorSize> stack; y_absl::InlinedVector<int, kInlinedVectorSize> indents; @@ -1880,7 +1880,7 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, *os << "SUBSTRING @ " << rep->substring()->start << "\n"; indent += kIndentStep; rep = rep->substring()->child; - } else { // Leaf or ring + } else { // Leaf or ring if (rep->IsExternal()) { *os << "EXTERNAL ["; if (include_data) @@ -1889,9 +1889,9 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, } else if (rep->IsFlat()) { *os << "FLAT cap=" << rep->flat()->Capacity() << " ["; if (include_data) - *os << y_absl::CEscape(TString(rep->flat()->Data(), rep->length)); + *os << y_absl::CEscape(TString(rep->flat()->Data(), rep->length)); *os << "]\n"; - } else { + } else { CordRepBtree::Dump(rep, /*label=*/ "", include_data, *os); } if (stack.empty()) break; @@ -2026,14 +2026,14 @@ std::ostream& operator<<(std::ostream& out, const Cord& cord) { } namespace strings_internal { -size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; } -size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; } +size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; } +size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; } size_t CordTestAccess::FlatTagToLength(uint8_t tag) { - return cord_internal::TagToLength(tag); + return cord_internal::TagToLength(tag); } uint8_t CordTestAccess::LengthToTag(size_t s) { ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, y_absl::StrCat("Invalid length ", s)); - return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead); + return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead); } size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); } size_t CordTestAccess::SizeofCordRepExternal() { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.h index 62359e0cf8..2bce9ffccf 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord.h @@ -12,51 +12,51 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// ----------------------------------------------------------------------------- -// File: cord.h -// ----------------------------------------------------------------------------- -// -// This file defines the `y_absl::Cord` data structure and operations on that data -// structure. A Cord is a string-like sequence of characters optimized for -// specific use cases. Unlike a `TString`, which stores an array of -// contiguous characters, Cord data is stored in a structure consisting of -// separate, reference-counted "chunks." (Currently, this implementation is a -// tree structure, though that implementation may change.) -// -// Because a Cord consists of these chunks, data can be added to or removed from -// a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a -// `TString`, a Cord can therefore accommodate data that changes over its -// lifetime, though it's not quite "mutable"; it can change only in the -// attachment, detachment, or rearrangement of chunks of its constituent data. -// -// A Cord provides some benefit over `TString` under the following (albeit -// narrow) circumstances: -// -// * Cord data is designed to grow and shrink over a Cord's lifetime. Cord -// provides efficient insertions and deletions at the start and end of the -// character sequences, avoiding copies in those cases. Static data should -// generally be stored as strings. -// * External memory consisting of string-like data can be directly added to -// a Cord without requiring copies or allocations. -// * Cord data may be shared and copied cheaply. Cord provides a copy-on-write -// implementation and cheap sub-Cord operations. Copying a Cord is an O(1) -// operation. -// -// As a consequence to the above, Cord data is generally large. Small data -// should generally use strings, as construction of a Cord requires some -// overhead. Small Cords (<= 15 bytes) are represented inline, but most small -// Cords are expected to grow over their lifetimes. -// -// Note that because a Cord is made up of separate chunked data, random access -// to character data within a Cord is slower than within a `TString`. -// -// Thread Safety -// +// ----------------------------------------------------------------------------- +// File: cord.h +// ----------------------------------------------------------------------------- +// +// This file defines the `y_absl::Cord` data structure and operations on that data +// structure. A Cord is a string-like sequence of characters optimized for +// specific use cases. Unlike a `TString`, which stores an array of +// contiguous characters, Cord data is stored in a structure consisting of +// separate, reference-counted "chunks." (Currently, this implementation is a +// tree structure, though that implementation may change.) +// +// Because a Cord consists of these chunks, data can be added to or removed from +// a Cord during its lifetime. Chunks may also be shared between Cords. Unlike a +// `TString`, a Cord can therefore accommodate data that changes over its +// lifetime, though it's not quite "mutable"; it can change only in the +// attachment, detachment, or rearrangement of chunks of its constituent data. +// +// A Cord provides some benefit over `TString` under the following (albeit +// narrow) circumstances: +// +// * Cord data is designed to grow and shrink over a Cord's lifetime. Cord +// provides efficient insertions and deletions at the start and end of the +// character sequences, avoiding copies in those cases. Static data should +// generally be stored as strings. +// * External memory consisting of string-like data can be directly added to +// a Cord without requiring copies or allocations. +// * Cord data may be shared and copied cheaply. Cord provides a copy-on-write +// implementation and cheap sub-Cord operations. Copying a Cord is an O(1) +// operation. +// +// As a consequence to the above, Cord data is generally large. Small data +// should generally use strings, as construction of a Cord requires some +// overhead. Small Cords (<= 15 bytes) are represented inline, but most small +// Cords are expected to grow over their lifetimes. +// +// Note that because a Cord is made up of separate chunked data, random access +// to character data within a Cord is slower than within a `TString`. +// +// Thread Safety +// // Cord has the same thread-safety properties as many other types like // TString, std::vector<>, int, etc -- it is thread-compatible. In -// particular, if threads do not call non-const methods, then it is safe to call -// const methods without synchronization. Copying a Cord produces a new instance -// that can be used concurrently with the original in arbitrary ways. +// particular, if threads do not call non-const methods, then it is safe to call +// const methods without synchronization. Copying a Cord produces a new instance +// that can be used concurrently with the original in arbitrary ways. #ifndef ABSL_STRINGS_CORD_H_ #define ABSL_STRINGS_CORD_H_ @@ -65,10 +65,10 @@ #include <cstddef> #include <cstdint> #include <cstring> -#include <iosfwd> +#include <iosfwd> #include <iterator> #include <util/generic/string.h> -#include <type_traits> +#include <type_traits> #include "y_absl/base/config.h" #include "y_absl/base/internal/endian.h" @@ -81,16 +81,16 @@ #include "y_absl/strings/internal/cord_internal.h" #include "y_absl/strings/internal/cord_rep_btree.h" #include "y_absl/strings/internal/cord_rep_btree_reader.h" -#include "y_absl/strings/internal/cord_rep_ring.h" +#include "y_absl/strings/internal/cord_rep_ring.h" #include "y_absl/strings/internal/cordz_functions.h" #include "y_absl/strings/internal/cordz_info.h" #include "y_absl/strings/internal/cordz_statistics.h" #include "y_absl/strings/internal/cordz_update_scope.h" #include "y_absl/strings/internal/cordz_update_tracker.h" #include "y_absl/strings/internal/resize_uninitialized.h" -#include "y_absl/strings/internal/string_constant.h" +#include "y_absl/strings/internal/string_constant.h" #include "y_absl/strings/string_view.h" -#include "y_absl/types/optional.h" +#include "y_absl/types/optional.h" namespace y_absl { ABSL_NAMESPACE_BEGIN @@ -100,34 +100,34 @@ template <typename Releaser> Cord MakeCordFromExternal(y_absl::string_view, Releaser&&); void CopyCordToString(const Cord& src, TString* dst); -// Cord -// -// A Cord is a sequence of characters, designed to be more efficient than a -// `TString` in certain circumstances: namely, large string data that needs -// to change over its lifetime or shared, especially when such data is shared -// across API boundaries. -// -// A Cord stores its character data in a structure that allows efficient prepend -// and append operations. This makes a Cord useful for large string data sent -// over in a wire format that may need to be prepended or appended at some point -// during the data exchange (e.g. HTTP, protocol buffers). For example, a -// Cord is useful for storing an HTTP request, and prepending an HTTP header to -// such a request. -// -// Cords should not be used for storing general string data, however. They -// require overhead to construct and are slower than strings for random access. -// -// The Cord API provides the following common API operations: -// -// * Create or assign Cords out of existing string data, memory, or other Cords -// * Append and prepend data to an existing Cord -// * Create new Sub-Cords from existing Cord data -// * Swap Cord data and compare Cord equality -// * Write out Cord data by constructing a `TString` -// -// Additionally, the API provides iterator utilities to iterate through Cord -// data via chunks or character bytes. -// +// Cord +// +// A Cord is a sequence of characters, designed to be more efficient than a +// `TString` in certain circumstances: namely, large string data that needs +// to change over its lifetime or shared, especially when such data is shared +// across API boundaries. +// +// A Cord stores its character data in a structure that allows efficient prepend +// and append operations. This makes a Cord useful for large string data sent +// over in a wire format that may need to be prepended or appended at some point +// during the data exchange (e.g. HTTP, protocol buffers). For example, a +// Cord is useful for storing an HTTP request, and prepending an HTTP header to +// such a request. +// +// Cords should not be used for storing general string data, however. They +// require overhead to construct and are slower than strings for random access. +// +// The Cord API provides the following common API operations: +// +// * Create or assign Cords out of existing string data, memory, or other Cords +// * Append and prepend data to an existing Cord +// * Create new Sub-Cords from existing Cord data +// * Swap Cord data and compare Cord equality +// * Write out Cord data by constructing a `TString` +// +// Additionally, the API provides iterator utilities to iterate through Cord +// data via chunks or character bytes. +// class Cord { private: template <typename T> @@ -135,54 +135,54 @@ class Cord { y_absl::enable_if_t<std::is_same<T, TString>::value, int>; public: - // Cord::Cord() Constructors. + // Cord::Cord() Constructors. - // Creates an empty Cord. + // Creates an empty Cord. constexpr Cord() noexcept; - // Creates a Cord from an existing Cord. Cord is copyable and efficiently - // movable. The moved-from state is valid but unspecified. + // Creates a Cord from an existing Cord. Cord is copyable and efficiently + // movable. The moved-from state is valid but unspecified. Cord(const Cord& src); Cord(Cord&& src) noexcept; Cord& operator=(const Cord& x); Cord& operator=(Cord&& x) noexcept; - // Creates a Cord from a `src` string. This constructor is marked explicit to - // prevent implicit Cord constructions from arguments convertible to an - // `y_absl::string_view`. + // Creates a Cord from a `src` string. This constructor is marked explicit to + // prevent implicit Cord constructions from arguments convertible to an + // `y_absl::string_view`. explicit Cord(y_absl::string_view src); Cord& operator=(y_absl::string_view src); - // Creates a Cord from a `TString&&` rvalue. These constructors are - // templated to avoid ambiguities for types that are convertible to both - // `y_absl::string_view` and `TString`, such as `const char*`. + // Creates a Cord from a `TString&&` rvalue. These constructors are + // templated to avoid ambiguities for types that are convertible to both + // `y_absl::string_view` and `TString`, such as `const char*`. template <typename T, EnableIfString<T> = 0> - explicit Cord(T&& src); + explicit Cord(T&& src); template <typename T, EnableIfString<T> = 0> Cord& operator=(T&& src); - // Cord::~Cord() - // - // Destructs the Cord. + // Cord::~Cord() + // + // Destructs the Cord. ~Cord() { if (contents_.is_tree()) DestroyCordSlow(); } - // MakeCordFromExternal() - // - // Creates a Cord that takes ownership of external string memory. The - // contents of `data` are not copied to the Cord; instead, the external - // memory is added to the Cord and reference-counted. This data may not be - // changed for the life of the Cord, though it may be prepended or appended - // to. - // - // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when - // the reference count for `data` reaches zero. As noted above, this data must - // remain live until the releaser is invoked. The callable releaser also must: - // - // * be move constructible - // * support `void operator()(y_absl::string_view) const` or `void operator()` - // + // MakeCordFromExternal() + // + // Creates a Cord that takes ownership of external string memory. The + // contents of `data` are not copied to the Cord; instead, the external + // memory is added to the Cord and reference-counted. This data may not be + // changed for the life of the Cord, though it may be prepended or appended + // to. + // + // `MakeCordFromExternal()` takes a callable "releaser" that is invoked when + // the reference count for `data` reaches zero. As noted above, this data must + // remain live until the releaser is invoked. The callable releaser also must: + // + // * be move constructible + // * support `void operator()(y_absl::string_view) const` or `void operator()` + // // Example: // // Cord MakeCord(BlockPool* pool) { @@ -190,13 +190,13 @@ class Cord { // FillBlock(block); // return y_absl::MakeCordFromExternal( // block->ToStringView(), - // [pool, block](y_absl::string_view v) { - // pool->FreeBlock(block, v); + // [pool, block](y_absl::string_view v) { + // pool->FreeBlock(block, v); // }); // } // - // WARNING: Because a Cord can be reference-counted, it's likely a bug if your - // releaser doesn't do anything. For example, consider the following: + // WARNING: Because a Cord can be reference-counted, it's likely a bug if your + // releaser doesn't do anything. For example, consider the following: // // void Foo(const char* buffer, int len) { // auto c = y_absl::MakeCordFromExternal(y_absl::string_view(buffer, len), @@ -210,107 +210,107 @@ class Cord { template <typename Releaser> friend Cord MakeCordFromExternal(y_absl::string_view data, Releaser&& releaser); - // Cord::Clear() - // - // Releases the Cord data. Any nodes that share data with other Cords, if - // applicable, will have their reference counts reduced by 1. + // Cord::Clear() + // + // Releases the Cord data. Any nodes that share data with other Cords, if + // applicable, will have their reference counts reduced by 1. void Clear(); - // Cord::Append() - // - // Appends data to the Cord, which may come from another Cord or other string - // data. + // Cord::Append() + // + // Appends data to the Cord, which may come from another Cord or other string + // data. void Append(const Cord& src); void Append(Cord&& src); void Append(y_absl::string_view src); template <typename T, EnableIfString<T> = 0> void Append(T&& src); - // Cord::Prepend() - // - // Prepends data to the Cord, which may come from another Cord or other string - // data. + // Cord::Prepend() + // + // Prepends data to the Cord, which may come from another Cord or other string + // data. void Prepend(const Cord& src); void Prepend(y_absl::string_view src); template <typename T, EnableIfString<T> = 0> void Prepend(T&& src); - // Cord::RemovePrefix() - // - // Removes the first `n` bytes of a Cord. + // Cord::RemovePrefix() + // + // Removes the first `n` bytes of a Cord. void RemovePrefix(size_t n); void RemoveSuffix(size_t n); - // Cord::Subcord() - // - // Returns a new Cord representing the subrange [pos, pos + new_size) of + // Cord::Subcord() + // + // Returns a new Cord representing the subrange [pos, pos + new_size) of // *this. If pos >= size(), the result is empty(). If // (pos + new_size) >= size(), the result is the subrange [pos, size()). Cord Subcord(size_t pos, size_t new_size) const; - // Cord::swap() - // - // Swaps the contents of the Cord with `other`. - void swap(Cord& other) noexcept; + // Cord::swap() + // + // Swaps the contents of the Cord with `other`. + void swap(Cord& other) noexcept; - // swap() - // - // Swaps the contents of two Cords. + // swap() + // + // Swaps the contents of two Cords. friend void swap(Cord& x, Cord& y) noexcept { x.swap(y); } - // Cord::size() - // - // Returns the size of the Cord. + // Cord::size() + // + // Returns the size of the Cord. size_t size() const; - - // Cord::empty() - // - // Determines whether the given Cord is empty, returning `true` is so. + + // Cord::empty() + // + // Determines whether the given Cord is empty, returning `true` is so. bool empty() const; - // Cord::EstimatedMemoryUsage() - // - // Returns the *approximate* number of bytes held in full or in part by this - // Cord (which may not remain the same between invocations). Note that Cords - // that share memory could each be "charged" independently for the same shared - // memory. + // Cord::EstimatedMemoryUsage() + // + // Returns the *approximate* number of bytes held in full or in part by this + // Cord (which may not remain the same between invocations). Note that Cords + // that share memory could each be "charged" independently for the same shared + // memory. size_t EstimatedMemoryUsage() const; - // Cord::Compare() - // - // Compares 'this' Cord with rhs. This function and its relatives treat Cords - // as sequences of unsigned bytes. The comparison is a straightforward - // lexicographic comparison. `Cord::Compare()` returns values as follows: - // + // Cord::Compare() + // + // Compares 'this' Cord with rhs. This function and its relatives treat Cords + // as sequences of unsigned bytes. The comparison is a straightforward + // lexicographic comparison. `Cord::Compare()` returns values as follows: + // // -1 'this' Cord is smaller // 0 two Cords are equal // 1 'this' Cord is larger int Compare(y_absl::string_view rhs) const; int Compare(const Cord& rhs) const; - // Cord::StartsWith() - // - // Determines whether the Cord starts with the passed string data `rhs`. + // Cord::StartsWith() + // + // Determines whether the Cord starts with the passed string data `rhs`. bool StartsWith(const Cord& rhs) const; bool StartsWith(y_absl::string_view rhs) const; - - // Cord::EndsWith() - // - // Determines whether the Cord ends with the passed string data `rhs`. + + // Cord::EndsWith() + // + // Determines whether the Cord ends with the passed string data `rhs`. bool EndsWith(y_absl::string_view rhs) const; bool EndsWith(const Cord& rhs) const; - // Cord::operator TString() - // - // Converts a Cord into a `TString()`. This operator is marked explicit to - // prevent unintended Cord usage in functions that take a string. + // Cord::operator TString() + // + // Converts a Cord into a `TString()`. This operator is marked explicit to + // prevent unintended Cord usage in functions that take a string. explicit operator TString() const; - // CopyCordToString() + // CopyCordToString() // - // Copies the contents of a `src` Cord into a `*dst` string. - // - // This function optimizes the case of reusing the destination string since it + // Copies the contents of a `src` Cord into a `*dst` string. + // + // This function optimizes the case of reusing the destination string since it // can reuse previously allocated capacity. However, this function does not // guarantee that pointers previously returned by `dst->data()` remain valid // even if `*dst` had enough capacity to hold `src`. If `*dst` is a new @@ -319,32 +319,32 @@ class Cord { class CharIterator; - //---------------------------------------------------------------------------- - // Cord::ChunkIterator - //---------------------------------------------------------------------------- - // - // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its - // Cord. Such iteration allows you to perform non-const operatons on the data - // of a Cord without modifying it. - // - // Generally, you do not instantiate a `Cord::ChunkIterator` directly; - // instead, you create one implicitly through use of the `Cord::Chunks()` - // member function. - // - // The `Cord::ChunkIterator` has the following properties: - // - // * The iterator is invalidated after any non-const operation on the - // Cord object over which it iterates. + //---------------------------------------------------------------------------- + // Cord::ChunkIterator + //---------------------------------------------------------------------------- + // + // A `Cord::ChunkIterator` allows iteration over the constituent chunks of its + // Cord. Such iteration allows you to perform non-const operatons on the data + // of a Cord without modifying it. + // + // Generally, you do not instantiate a `Cord::ChunkIterator` directly; + // instead, you create one implicitly through use of the `Cord::Chunks()` + // member function. + // + // The `Cord::ChunkIterator` has the following properties: + // + // * The iterator is invalidated after any non-const operation on the + // Cord object over which it iterates. // * The `string_view` returned by dereferencing a valid, non-`end()` // iterator is guaranteed to be non-empty. - // * Two `ChunkIterator` objects can be compared equal if and only if they - // remain valid and iterate over the same Cord. - // * The iterator in this case is a proxy iterator; the `string_view` - // returned by the iterator does not live inside the Cord, and its - // lifetime is limited to the lifetime of the iterator itself. To help - // prevent lifetime issues, `ChunkIterator::reference` is not a true - // reference type and is equivalent to `value_type`. - // * The iterator keeps state that can grow for Cords that contain many + // * Two `ChunkIterator` objects can be compared equal if and only if they + // remain valid and iterate over the same Cord. + // * The iterator in this case is a proxy iterator; the `string_view` + // returned by the iterator does not live inside the Cord, and its + // lifetime is limited to the lifetime of the iterator itself. To help + // prevent lifetime issues, `ChunkIterator::reference` is not a true + // reference type and is equivalent to `value_type`. + // * The iterator keeps state that can grow for Cords that contain many // nodes and are imbalanced due to sharing. Prefer to pass this type by // const reference instead of by value. class ChunkIterator { @@ -368,38 +368,38 @@ class Cord { friend class CharIterator; private: - using CordRep = y_absl::cord_internal::CordRep; + using CordRep = y_absl::cord_internal::CordRep; using CordRepBtree = y_absl::cord_internal::CordRepBtree; using CordRepBtreeReader = y_absl::cord_internal::CordRepBtreeReader; - - // Stack of right children of concat nodes that we have to visit. - // Keep this at the end of the structure to avoid cache-thrashing. - // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for - // the inlined vector size (47 exists for backward compatibility). - using Stack = y_absl::InlinedVector<y_absl::cord_internal::CordRep*, 47>; - - // Constructs a `begin()` iterator from `tree`. `tree` must not be null. - explicit ChunkIterator(cord_internal::CordRep* tree); - + + // Stack of right children of concat nodes that we have to visit. + // Keep this at the end of the structure to avoid cache-thrashing. + // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for + // the inlined vector size (47 exists for backward compatibility). + using Stack = y_absl::InlinedVector<y_absl::cord_internal::CordRep*, 47>; + + // Constructs a `begin()` iterator from `tree`. `tree` must not be null. + explicit ChunkIterator(cord_internal::CordRep* tree); + // Constructs a `begin()` iterator from `cord`. explicit ChunkIterator(const Cord* cord); - // Initializes this instance from a tree. Invoked by constructors. - void InitTree(cord_internal::CordRep* tree); - + // Initializes this instance from a tree. Invoked by constructors. + void InitTree(cord_internal::CordRep* tree); + // Removes `n` bytes from `current_chunk_`. Expects `n` to be smaller than // `current_chunk_.size()`. void RemoveChunkPrefix(size_t n); Cord AdvanceAndReadBytes(size_t n); void AdvanceBytes(size_t n); - - // Stack specific operator++ - ChunkIterator& AdvanceStack(); - + + // Stack specific operator++ + ChunkIterator& AdvanceStack(); + // Btree specific operator++ ChunkIterator& AdvanceBtree(); void AdvanceBytesBtree(size_t n); - + // Iterates `n` bytes, where `n` is expected to be greater than or equal to // `current_chunk_.size()`. void AdvanceBytesSlowPath(size_t n); @@ -413,21 +413,21 @@ class Cord { y_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; - + // Cord reader for cord btrees. Empty if not traversing a btree. CordRepBtreeReader btree_reader_; - - // See 'Stack' alias definition. - Stack stack_of_right_children_; + + // See 'Stack' alias definition. + Stack stack_of_right_children_; }; - // Cord::ChunkIterator::chunk_begin() - // + // Cord::ChunkIterator::chunk_begin() + // // Returns an iterator to the first chunk of the `Cord`. // - // Generally, prefer using `Cord::Chunks()` within a range-based for loop for - // iterating over the chunks of a Cord. This method may be useful for getting - // a `ChunkIterator` where range-based for-loops are not useful. + // Generally, prefer using `Cord::Chunks()` within a range-based for loop for + // iterating over the chunks of a Cord. This method may be useful for getting + // a `ChunkIterator` where range-based for-loops are not useful. // // Example: // @@ -436,28 +436,28 @@ class Cord { // return std::find(c.chunk_begin(), c.chunk_end(), s); // } ChunkIterator chunk_begin() const; - - // Cord::ChunkItertator::chunk_end() - // + + // Cord::ChunkItertator::chunk_end() + // // Returns an iterator one increment past the last chunk of the `Cord`. - // - // Generally, prefer using `Cord::Chunks()` within a range-based for loop for - // iterating over the chunks of a Cord. This method may be useful for getting - // a `ChunkIterator` where range-based for-loops may not be available. + // + // Generally, prefer using `Cord::Chunks()` within a range-based for loop for + // iterating over the chunks of a Cord. This method may be useful for getting + // a `ChunkIterator` where range-based for-loops may not be available. ChunkIterator chunk_end() const; - //---------------------------------------------------------------------------- - // Cord::ChunkIterator::ChunkRange - //---------------------------------------------------------------------------- - // - // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`, - // producing an iterator which can be used within a range-based for loop. - // Construction of a `ChunkRange` will return an iterator pointing to the - // first chunk of the Cord. Generally, do not construct a `ChunkRange` - // directly; instead, prefer to use the `Cord::Chunks()` method. - // - // Implementation note: `ChunkRange` is simply a convenience wrapper over - // `Cord::chunk_begin()` and `Cord::chunk_end()`. + //---------------------------------------------------------------------------- + // Cord::ChunkIterator::ChunkRange + //---------------------------------------------------------------------------- + // + // `ChunkRange` is a helper class for iterating over the chunks of the `Cord`, + // producing an iterator which can be used within a range-based for loop. + // Construction of a `ChunkRange` will return an iterator pointing to the + // first chunk of the Cord. Generally, do not construct a `ChunkRange` + // directly; instead, prefer to use the `Cord::Chunks()` method. + // + // Implementation note: `ChunkRange` is simply a convenience wrapper over + // `Cord::chunk_begin()` and `Cord::chunk_end()`. class ChunkRange { public: // Fulfill minimum c++ container requirements [container.requirements] @@ -479,12 +479,12 @@ class Cord { const Cord* cord_; }; - // Cord::Chunks() - // - // Returns a `Cord::ChunkIterator::ChunkRange` for iterating over the chunks - // of a `Cord` with a range-based for-loop. For most iteration tasks on a - // Cord, use `Cord::Chunks()` to retrieve this iterator. + // Cord::Chunks() // + // Returns a `Cord::ChunkIterator::ChunkRange` for iterating over the chunks + // of a `Cord` with a range-based for-loop. For most iteration tasks on a + // Cord, use `Cord::Chunks()` to retrieve this iterator. + // // Example: // // void ProcessChunks(const Cord& cord) { @@ -500,30 +500,30 @@ class Cord { // } ChunkRange Chunks() const; - //---------------------------------------------------------------------------- - // Cord::CharIterator - //---------------------------------------------------------------------------- - // - // A `Cord::CharIterator` allows iteration over the constituent characters of - // a `Cord`. - // - // Generally, you do not instantiate a `Cord::CharIterator` directly; instead, - // you create one implicitly through use of the `Cord::Chars()` member - // function. - // - // A `Cord::CharIterator` has the following properties: - // - // * The iterator is invalidated after any non-const operation on the - // Cord object over which it iterates. - // * Two `CharIterator` objects can be compared equal if and only if they - // remain valid and iterate over the same Cord. - // * The iterator keeps state that can grow for Cords that contain many + //---------------------------------------------------------------------------- + // Cord::CharIterator + //---------------------------------------------------------------------------- + // + // A `Cord::CharIterator` allows iteration over the constituent characters of + // a `Cord`. + // + // Generally, you do not instantiate a `Cord::CharIterator` directly; instead, + // you create one implicitly through use of the `Cord::Chars()` member + // function. + // + // A `Cord::CharIterator` has the following properties: + // + // * The iterator is invalidated after any non-const operation on the + // Cord object over which it iterates. + // * Two `CharIterator` objects can be compared equal if and only if they + // remain valid and iterate over the same Cord. + // * The iterator keeps state that can grow for Cords that contain many // nodes and are imbalanced due to sharing. Prefer to pass this type by // const reference instead of by value. - // * This type cannot act as a forward iterator because a `Cord` can reuse - // sections of memory. This fact violates the requirement for forward - // iterators to compare equal if dereferencing them returns the same - // object. + // * This type cannot act as a forward iterator because a `Cord` can reuse + // sections of memory. This fact violates the requirement for forward + // iterators to compare equal if dereferencing them returns the same + // object. class CharIterator { public: using iterator_category = std::input_iterator_tag; @@ -549,56 +549,56 @@ class Cord { ChunkIterator chunk_iterator_; }; - // Cord::CharIterator::AdvanceAndRead() + // Cord::CharIterator::AdvanceAndRead() // - // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes - // 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`. + // Advances the `Cord::CharIterator` by `n_bytes` and returns the bytes + // 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); - // Cord::CharIterator::Advance() + // Cord::CharIterator::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`. + // 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); - // Cord::CharIterator::ChunkRemaining() - // + // Cord::CharIterator::ChunkRemaining() + // // Returns the longest contiguous view starting at the iterator's position. // // `it` must be dereferenceable. static y_absl::string_view ChunkRemaining(const CharIterator& it); - // Cord::CharIterator::char_begin() - // + // Cord::CharIterator::char_begin() + // // Returns an iterator to the first character of the `Cord`. - // - // Generally, prefer using `Cord::Chars()` within a range-based for loop for - // iterating over the chunks of a Cord. This method may be useful for getting - // a `CharIterator` where range-based for-loops may not be available. + // + // Generally, prefer using `Cord::Chars()` within a range-based for loop for + // iterating over the chunks of a Cord. This method may be useful for getting + // a `CharIterator` where range-based for-loops may not be available. CharIterator char_begin() const; - - // Cord::CharIterator::char_end() - // + + // Cord::CharIterator::char_end() + // // Returns an iterator to one past the last character of the `Cord`. - // - // Generally, prefer using `Cord::Chars()` within a range-based for loop for - // iterating over the chunks of a Cord. This method may be useful for getting - // a `CharIterator` where range-based for-loops are not useful. + // + // Generally, prefer using `Cord::Chars()` within a range-based for loop for + // iterating over the chunks of a Cord. This method may be useful for getting + // a `CharIterator` where range-based for-loops are not useful. CharIterator char_end() const; - // Cord::CharIterator::CharRange - // - // `CharRange` is a helper class for iterating over the characters of a - // producing an iterator which can be used within a range-based for loop. - // Construction of a `CharRange` will return an iterator pointing to the first - // character of the Cord. Generally, do not construct a `CharRange` directly; - // instead, prefer to use the `Cord::Chars()` method show below. + // Cord::CharIterator::CharRange // - // Implementation note: `CharRange` is simply a convenience wrapper over - // `Cord::char_begin()` and `Cord::char_end()`. + // `CharRange` is a helper class for iterating over the characters of a + // producing an iterator which can be used within a range-based for loop. + // Construction of a `CharRange` will return an iterator pointing to the first + // character of the Cord. Generally, do not construct a `CharRange` directly; + // instead, prefer to use the `Cord::Chars()` method show below. + // + // Implementation note: `CharRange` is simply a convenience wrapper over + // `Cord::char_begin()` and `Cord::char_end()`. class CharRange { public: // Fulfill minimum c++ container requirements [container.requirements] @@ -620,12 +620,12 @@ class Cord { const Cord* cord_; }; - // Cord::CharIterator::Chars() - // - // Returns a `Cord::CharIterator` for iterating over the characters of a - // `Cord` with a range-based for-loop. For most character-based iteration - // tasks on a Cord, use `Cord::Chars()` to retrieve this iterator. + // Cord::CharIterator::Chars() // + // Returns a `Cord::CharIterator` for iterating over the characters of a + // `Cord` with a range-based for-loop. For most character-based iteration + // tasks on a Cord, use `Cord::Chars()` to retrieve this iterator. + // // Example: // // void ProcessCord(const Cord& cord) { @@ -641,53 +641,53 @@ class Cord { // } CharRange Chars() const; - // Cord::operator[] - // - // Gets the "i"th character of the Cord and returns it, provided that - // 0 <= i < Cord.size(). - // - // NOTE: This routine is reasonably efficient. It is roughly - // logarithmic based on the number of chunks that make up the cord. Still, + // Cord::operator[] + // + // Gets the "i"th character of the Cord and returns it, provided that + // 0 <= i < Cord.size(). + // + // NOTE: This routine is reasonably efficient. It is roughly + // logarithmic based on the number of chunks that make up the cord. Still, // if you need to iterate over the contents of a cord, you should - // use a CharIterator/ChunkIterator rather than call operator[] or Get() - // repeatedly in a loop. + // use a CharIterator/ChunkIterator rather than call operator[] or Get() + // repeatedly in a loop. char operator[](size_t i) const; - // Cord::TryFlat() - // - // If this cord's representation is a single flat array, returns a - // string_view referencing that array. Otherwise returns nullopt. - y_absl::optional<y_absl::string_view> TryFlat() const; - - // Cord::Flatten() - // + // Cord::TryFlat() + // + // If this cord's representation is a single flat array, returns a + // string_view referencing that array. Otherwise returns nullopt. + y_absl::optional<y_absl::string_view> TryFlat() const; + + // Cord::Flatten() + // // Flattens the cord into a single array and returns a view of the data. // // If the cord was already flat, the contents are not modified. y_absl::string_view Flatten(); - // Supports y_absl::Cord as a sink object for y_absl::Format(). - friend void AbslFormatFlush(y_absl::Cord* cord, y_absl::string_view part) { - cord->Append(part); - } - - template <typename H> - friend H AbslHashValue(H hash_state, const y_absl::Cord& c) { - y_absl::optional<y_absl::string_view> maybe_flat = c.TryFlat(); - if (maybe_flat.has_value()) { - return H::combine(std::move(hash_state), *maybe_flat); - } - return c.HashFragmented(std::move(hash_state)); - } - - // Create a Cord with the contents of StringConstant<T>::value. - // No allocations will be done and no data will be copied. - // This is an INTERNAL API and subject to change or removal. This API can only - // be used by spelling y_absl::strings_internal::MakeStringConstant, which is - // also an internal API. - template <typename T> - explicit constexpr Cord(strings_internal::StringConstant<T>); - + // Supports y_absl::Cord as a sink object for y_absl::Format(). + friend void AbslFormatFlush(y_absl::Cord* cord, y_absl::string_view part) { + cord->Append(part); + } + + template <typename H> + friend H AbslHashValue(H hash_state, const y_absl::Cord& c) { + y_absl::optional<y_absl::string_view> maybe_flat = c.TryFlat(); + if (maybe_flat.has_value()) { + return H::combine(std::move(hash_state), *maybe_flat); + } + return c.HashFragmented(std::move(hash_state)); + } + + // Create a Cord with the contents of StringConstant<T>::value. + // No allocations will be done and no data will be copied. + // This is an INTERNAL API and subject to change or removal. This API can only + // be used by spelling y_absl::strings_internal::MakeStringConstant, which is + // also an internal API. + template <typename T> + explicit constexpr Cord(strings_internal::StringConstant<T>); + private: using CordRep = y_absl::cord_internal::CordRep; using CordRepFlat = y_absl::cord_internal::CordRepFlat; @@ -707,7 +707,7 @@ class Cord { friend const CordzInfo* GetCordzInfoForTesting(const Cord& cord); - // Calls the provided function once for each cord chunk, in order. Unlike + // Calls the provided function once for each cord chunk, in order. Unlike // Chunks(), this API will not allocate memory. void ForEachChunk(y_absl::FunctionRef<void(y_absl::string_view)>) const; @@ -719,21 +719,21 @@ class Cord { // class so that we can isolate the bulk of cord.cc from changes // to the representation. // - // InlineRep holds either a tree pointer, or an array of kMaxInline bytes. + // InlineRep holds either a tree pointer, or an array of kMaxInline bytes. class InlineRep { public: - static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; + static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; static_assert(kMaxInline >= sizeof(y_absl::cord_internal::CordRep*), ""); - constexpr InlineRep() : data_() {} + constexpr InlineRep() : data_() {} explicit InlineRep(InlineData::DefaultInitType init) : data_(init) {} InlineRep(const InlineRep& src); InlineRep(InlineRep&& src); InlineRep& operator=(const InlineRep& src); InlineRep& operator=(InlineRep&& src) noexcept; - explicit constexpr InlineRep(cord_internal::InlineData data); - + explicit constexpr InlineRep(cord_internal::InlineData data); + void Swap(InlineRep* rhs); bool empty() const; size_t size() const; @@ -743,10 +743,10 @@ class Cord { char* set_data(size_t n); // Write data to the result // Returns nullptr if holding bytes y_absl::cord_internal::CordRep* tree() const; - y_absl::cord_internal::CordRep* as_tree() const; + y_absl::cord_internal::CordRep* as_tree() const; // Returns non-null iff was holding a pointer y_absl::cord_internal::CordRep* clear(); - // Converts to pointer if necessary. + // Converts to pointer if necessary. void reduce_size(size_t n); // REQUIRES: holding data void remove_prefix(size_t n); // REQUIRES: holding data void AppendArray(y_absl::string_view src, MethodIdentifier method); @@ -795,16 +795,16 @@ class Cord { void GetAppendRegion(char** region, size_t* size, size_t length); bool IsSame(const InlineRep& other) const { - return memcmp(&data_, &other.data_, sizeof(data_)) == 0; + return memcmp(&data_, &other.data_, sizeof(data_)) == 0; } int BitwiseCompare(const InlineRep& other) const { uint64_t x, y; - // Use memcpy to avoid aliasing issues. - memcpy(&x, &data_, sizeof(x)); - memcpy(&y, &other.data_, sizeof(y)); + // Use memcpy to avoid aliasing issues. + memcpy(&x, &data_, sizeof(x)); + memcpy(&y, &other.data_, sizeof(y)); if (x == y) { - memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x)); - memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y)); + memcpy(&x, reinterpret_cast<const char*>(&data_) + 8, sizeof(x)); + memcpy(&y, reinterpret_cast<const char*>(&other.data_) + 8, sizeof(y)); if (x == y) return 0; } return y_absl::big_endian::FromHost64(x) < y_absl::big_endian::FromHost64(y) @@ -813,38 +813,38 @@ class Cord { } void CopyTo(TString* 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 + // platforms, the small string optimization is large enough that resizing // to 15 bytes does not cause a memory allocation. y_absl::strings_internal::STLStringResizeUninitialized(dst, sizeof(data_) - 1); - memcpy(&(*dst)[0], &data_, sizeof(data_) - 1); + memcpy(&(*dst)[0], &data_, sizeof(data_) - 1); // erase is faster than resize because the logic for memory allocation is // not needed. - dst->erase(inline_size()); + dst->erase(inline_size()); } // Copies the inline contents into `dst`. Assumes the cord is not empty. void CopyToArray(char* dst) const; - bool is_tree() const { return data_.is_tree(); } - - // Returns true if the Cord is being profiled by cordz. - bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } - - // Returns the profiled CordzInfo, or nullptr if not sampled. - y_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) { - assert(cordz_info != nullptr); - data_.set_cordz_info(cordz_info); - } - - // Resets the current cordz_info to null / empty. - void clear_cordz_info() { data_.clear_cordz_info(); } - + bool is_tree() const { return data_.is_tree(); } + + // Returns true if the Cord is being profiled by cordz. + bool is_profiled() const { return data_.is_tree() && data_.is_profiled(); } + + // Returns the profiled CordzInfo, or nullptr if not sampled. + y_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) { + assert(cordz_info != nullptr); + data_.set_cordz_info(cordz_info); + } + + // Resets the current cordz_info to null / empty. + void clear_cordz_info() { data_.clear_cordz_info(); } + private: friend class Cord; @@ -852,23 +852,23 @@ class Cord { // Unrefs the tree and stops profiling. void UnrefTree(); - void ResetToEmpty() { data_ = {}; } - - void set_inline_size(size_t size) { data_.set_inline_size(size); } - size_t inline_size() const { return data_.inline_size(); } - - cord_internal::InlineData data_; + void ResetToEmpty() { data_ = {}; } + + void set_inline_size(size_t size) { data_.set_inline_size(size); } + size_t inline_size() const { return data_.inline_size(); } + + cord_internal::InlineData data_; }; InlineRep contents_; - // Helper for MemoryUsage(). + // Helper for MemoryUsage(). static size_t MemoryUsageAux(const y_absl::cord_internal::CordRep* rep); - // Helper for GetFlat() and TryFlat(). + // Helper for GetFlat() and TryFlat(). static bool GetFlatAux(y_absl::cord_internal::CordRep* rep, y_absl::string_view* fragment); - // Helper for ForEachChunk(). + // Helper for ForEachChunk(). static void ForEachChunkAux( y_absl::cord_internal::CordRep* rep, y_absl::FunctionRef<void(y_absl::string_view)> callback); @@ -897,10 +897,10 @@ class Cord { y_absl::cord_internal::CordRep* TakeRep() const&; y_absl::cord_internal::CordRep* TakeRep() &&; - // Helper for Append(). + // Helper for Append(). template <typename C> void AppendImpl(C&& src); - + // Prepends the provided data to this instance. `method` contains the public // API method for this action which is tracked for Cordz sampling purposes. void PrependArray(y_absl::string_view src, MethodIdentifier method); @@ -909,16 +909,16 @@ class Cord { // Requires src.length() > kMaxBytesToCopy. Cord& AssignLargeString(TString&& src); - // Helper for AbslHashValue(). - template <typename H> - H HashFragmented(H hash_state) const { - typename H::AbslInternalPiecewiseCombiner combiner; - ForEachChunk([&combiner, &hash_state](y_absl::string_view chunk) { - hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(), - chunk.size()); - }); - return H::combine(combiner.finalize(std::move(hash_state)), size()); - } + // Helper for AbslHashValue(). + template <typename H> + H HashFragmented(H hash_state) const { + typename H::AbslInternalPiecewiseCombiner combiner; + ForEachChunk([&combiner, &hash_state](y_absl::string_view chunk) { + hash_state = combiner.add_buffer(std::move(hash_state), chunk.data(), + chunk.size()); + }); + return H::combine(combiner.finalize(std::move(hash_state)), size()); + } }; ABSL_NAMESPACE_END @@ -975,9 +975,9 @@ inline void SmallMemmove(char* dst, const char* src, size_t n, } } -// Does non-template-specific `CordRepExternal` initialization. +// Does non-template-specific `CordRepExternal` initialization. // Expects `data` to be non-empty. -void InitializeCordRepExternal(y_absl::string_view data, CordRepExternal* rep); +void InitializeCordRepExternal(y_absl::string_view data, CordRepExternal* rep); // Creates a new `CordRep` that owns `data` and `releaser` and returns a pointer // to it, or `nullptr` if `data` was empty. @@ -987,15 +987,15 @@ CordRep* NewExternalRep(y_absl::string_view data, Releaser&& releaser) { using ReleaserType = y_absl::decay_t<Releaser>; if (data.empty()) { // Never create empty external nodes. - InvokeReleaser(Rank0{}, ReleaserType(std::forward<Releaser>(releaser)), - data); + InvokeReleaser(Rank0{}, ReleaserType(std::forward<Releaser>(releaser)), + data); return nullptr; } - CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>( - std::forward<Releaser>(releaser), 0); - InitializeCordRepExternal(data, rep); - return rep; + CordRepExternal* rep = new CordRepExternalImpl<ReleaserType>( + std::forward<Releaser>(releaser), 0); + InitializeCordRepExternal(data, rep); + return rep; } // Overload for function reference types that dispatches using a function @@ -1019,21 +1019,21 @@ Cord MakeCordFromExternal(y_absl::string_view data, Releaser&& releaser) { return cord; } -constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data) - : data_(data) {} - -inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) +constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data) + : data_(data) {} + +inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) : data_(InlineData::kDefaultInit) { if (CordRep* tree = src.tree()) { EmplaceTree(CordRep::Ref(tree), src.data_, CordzUpdateTracker::kConstructorCord); } else { data_ = src.data_; - } + } } inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) : data_(src.data_) { - src.ResetToEmpty(); + src.ResetToEmpty(); } inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { @@ -1041,7 +1041,7 @@ inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { return *this; } if (!is_tree() && !src.is_tree()) { - data_ = src.data_; + data_ = src.data_; return *this; } AssignSlow(src); @@ -1053,8 +1053,8 @@ inline Cord::InlineRep& Cord::InlineRep::operator=( if (is_tree()) { UnrefTree(); } - data_ = src.data_; - src.ResetToEmpty(); + data_ = src.data_; + src.ResetToEmpty(); return *this; } @@ -1062,30 +1062,30 @@ inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { if (rhs == this) { return; } - std::swap(data_, rhs->data_); + std::swap(data_, rhs->data_); } inline const char* Cord::InlineRep::data() const { - return is_tree() ? nullptr : data_.as_chars(); -} - -inline y_absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { - assert(data_.is_tree()); - return data_.as_tree(); + return is_tree() ? nullptr : data_.as_chars(); } +inline y_absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { + assert(data_.is_tree()); + return data_.as_tree(); +} + inline y_absl::cord_internal::CordRep* Cord::InlineRep::tree() const { if (is_tree()) { - return as_tree(); + return as_tree(); } else { return nullptr; } } -inline bool Cord::InlineRep::empty() const { return data_.is_empty(); } +inline bool Cord::InlineRep::empty() const { return data_.is_empty(); } inline size_t Cord::InlineRep::size() const { - return is_tree() ? as_tree()->length : inline_size(); + return is_tree() ? as_tree()->length : inline_size(); } inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( @@ -1144,16 +1144,16 @@ inline y_absl::cord_internal::CordRep* Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); } - y_absl::cord_internal::CordRep* result = tree(); - ResetToEmpty(); + y_absl::cord_internal::CordRep* result = tree(); + ResetToEmpty(); return result; } inline void Cord::InlineRep::CopyToArray(char* dst) const { assert(!is_tree()); - size_t n = inline_size(); + size_t n = inline_size(); assert(n != 0); - cord_internal::SmallMemmove(dst, data_.as_chars(), n); + cord_internal::SmallMemmove(dst, data_.as_chars(), n); } constexpr inline Cord::Cord() noexcept {} @@ -1161,16 +1161,16 @@ constexpr inline Cord::Cord() noexcept {} inline Cord::Cord(y_absl::string_view src) : Cord(src, CordzUpdateTracker::kConstructorString) {} -template <typename T> -constexpr Cord::Cord(strings_internal::StringConstant<T>) - : contents_(strings_internal::StringConstant<T>::value.size() <= - cord_internal::kMaxInline - ? cord_internal::InlineData( - strings_internal::StringConstant<T>::value) - : cord_internal::InlineData( - &cord_internal::ConstInitExternalStorage< - strings_internal::StringConstant<T>>::value)) {} - +template <typename T> +constexpr Cord::Cord(strings_internal::StringConstant<T>) + : contents_(strings_internal::StringConstant<T>::value.size() <= + cord_internal::kMaxInline + ? cord_internal::InlineData( + strings_internal::StringConstant<T>::value) + : cord_internal::InlineData( + &cord_internal::ConstInitExternalStorage< + strings_internal::StringConstant<T>>::value)) {} + inline Cord& Cord::operator=(const Cord& x) { contents_ = x.contents_; return *this; @@ -1185,20 +1185,20 @@ Cord& Cord::operator=(T&& src) { } } -inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} - +inline Cord::Cord(const Cord& src) : contents_(src.contents_) {} + inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.contents_)) {} -inline void Cord::swap(Cord& other) noexcept { - contents_.Swap(&other.contents_); -} - +inline void Cord::swap(Cord& other) noexcept { + contents_.Swap(&other.contents_); +} + inline Cord& Cord::operator=(Cord&& x) noexcept { contents_ = std::move(x.contents_); return *this; } -extern template Cord::Cord(TString&& src); +extern template Cord::Cord(TString&& src); inline size_t Cord::size() const { // Length is 1st field in str.rep_ @@ -1215,18 +1215,18 @@ inline size_t Cord::EstimatedMemoryUsage() const { return result; } -inline y_absl::optional<y_absl::string_view> Cord::TryFlat() const { - y_absl::cord_internal::CordRep* rep = contents_.tree(); - if (rep == nullptr) { - return y_absl::string_view(contents_.data(), contents_.size()); - } - y_absl::string_view fragment; - if (GetFlatAux(rep, &fragment)) { - return fragment; - } - return y_absl::nullopt; -} - +inline y_absl::optional<y_absl::string_view> Cord::TryFlat() const { + y_absl::cord_internal::CordRep* rep = contents_.tree(); + if (rep == nullptr) { + return y_absl::string_view(contents_.data(), contents_.size()); + } + y_absl::string_view fragment; + if (GetFlatAux(rep, &fragment)) { + return fragment; + } + return y_absl::nullopt; +} + inline y_absl::string_view Cord::Flatten() { y_absl::cord_internal::CordRep* rep = contents_.tree(); if (rep == nullptr) { @@ -1248,8 +1248,8 @@ inline void Cord::Prepend(y_absl::string_view src) { PrependArray(src, CordzUpdateTracker::kPrependString); } -extern template void Cord::Append(TString&& src); -extern template void Cord::Prepend(TString&& src); +extern template void Cord::Append(TString&& src); +extern template void Cord::Prepend(TString&& src); inline int Cord::Compare(const Cord& rhs) const { if (!contents_.is_tree() && !rhs.contents_.is_tree()) { @@ -1273,64 +1273,64 @@ inline bool Cord::StartsWith(y_absl::string_view rhs) const { return EqualsImpl(rhs, rhs_size); } -inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { +inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); - return; - } - - stack_of_right_children_.push_back(tree); - operator++(); -} - -inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) - : bytes_remaining_(tree->length) { - InitTree(tree); -} - + return; + } + + stack_of_right_children_.push_back(tree); + operator++(); +} + +inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) + : bytes_remaining_(tree->length) { + InitTree(tree); +} + inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) : bytes_remaining_(cord->size()) { if (cord->contents_.is_tree()) { - InitTree(cord->contents_.as_tree()); + InitTree(cord->contents_.as_tree()); } else { - current_chunk_ = - y_absl::string_view(cord->contents_.data(), bytes_remaining_); + current_chunk_ = + y_absl::string_view(cord->contents_.data(), bytes_remaining_); } } inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceBtree() { current_chunk_ = btree_reader_.Next(); - return *this; -} - + return *this; +} + inline void Cord::ChunkIterator::AdvanceBytesBtree(size_t n) { - assert(n >= current_chunk_.size()); - bytes_remaining_ -= n; - if (bytes_remaining_) { - if (n == current_chunk_.size()) { + assert(n >= current_chunk_.size()); + bytes_remaining_ -= n; + if (bytes_remaining_) { + if (n == current_chunk_.size()) { current_chunk_ = btree_reader_.Next(); - } else { + } else { size_t offset = btree_reader_.length() - bytes_remaining_; current_chunk_ = btree_reader_.Seek(offset); - } - } else { - current_chunk_ = {}; - } -} - -inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { - ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 && - "Attempted to iterate past `end()`"); - assert(bytes_remaining_ >= current_chunk_.size()); - bytes_remaining_ -= current_chunk_.size(); - if (bytes_remaining_ > 0) { + } + } else { + current_chunk_ = {}; + } +} + +inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { + ABSL_HARDENING_ASSERT(bytes_remaining_ > 0 && + "Attempted to iterate past `end()`"); + assert(bytes_remaining_ >= current_chunk_.size()); + bytes_remaining_ -= current_chunk_.size(); + if (bytes_remaining_ > 0) { return btree_reader_ ? AdvanceBtree() : AdvanceStack(); - } else { - current_chunk_ = {}; - } - return *this; -} - + } else { + current_chunk_ = {}; + } + return *this; +} + inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) { ChunkIterator tmp(*this); operator++(); @@ -1346,12 +1346,12 @@ inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const { } inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const { - ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); + ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); return current_chunk_; } inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const { - ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); + ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); return ¤t_chunk_; } @@ -1362,7 +1362,7 @@ inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) { } inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { - assert(bytes_remaining_ >= n); + assert(bytes_remaining_ >= n); if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { RemoveChunkPrefix(n); } else if (n != 0) { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord/ya.make index 8f3ec1f20f..eae61fde3f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/cord/ya.make @@ -1,30 +1,30 @@ -# Generated by devtools/yamaker. - -LIBRARY() - -WITHOUT_LICENSE_TEXTS() - -OWNER( - somov - g:cpp-contrib -) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp-tstring/y_absl/base +# Generated by devtools/yamaker. + +LIBRARY() + +WITHOUT_LICENSE_TEXTS() + +OWNER( + somov + g:cpp-contrib +) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/low_level_alloc - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity contrib/restricted/abseil-cpp-tstring/y_absl/debugging contrib/restricted/abseil-cpp-tstring/y_absl/debugging/stacktrace contrib/restricted/abseil-cpp-tstring/y_absl/debugging/symbolize contrib/restricted/abseil-cpp-tstring/y_absl/demangle - contrib/restricted/abseil-cpp-tstring/y_absl/numeric + contrib/restricted/abseil-cpp-tstring/y_absl/numeric contrib/restricted/abseil-cpp-tstring/y_absl/profiling/internal/exponential_biased - contrib/restricted/abseil-cpp-tstring/y_absl/strings + contrib/restricted/abseil-cpp-tstring/y_absl/strings contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions @@ -35,24 +35,24 @@ PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/time contrib/restricted/abseil-cpp-tstring/y_absl/time/civil_time contrib/restricted/abseil-cpp-tstring/y_absl/time/time_zone - contrib/restricted/abseil-cpp-tstring/y_absl/types/bad_optional_access - contrib/restricted/abseil-cpp-tstring/y_absl/algorithm - contrib/restricted/abseil-cpp-tstring/y_absl/container - contrib/restricted/abseil-cpp-tstring/y_absl/functional - contrib/restricted/abseil-cpp-tstring/y_absl/types - contrib/restricted/abseil-cpp-tstring/y_absl/utility -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp-tstring -) - -NO_COMPILER_WARNINGS() - -SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings) - -SRCS( - cord.cc -) - -END() + contrib/restricted/abseil-cpp-tstring/y_absl/types/bad_optional_access + contrib/restricted/abseil-cpp-tstring/y_absl/algorithm + contrib/restricted/abseil-cpp-tstring/y_absl/container + contrib/restricted/abseil-cpp-tstring/y_absl/functional + contrib/restricted/abseil-cpp-tstring/y_absl/types + contrib/restricted/abseil-cpp-tstring/y_absl/utility +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp-tstring +) + +NO_COMPILER_WARNINGS() + +SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings) + +SRCS( + cord.cc +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc index 8c82740608..b347786a02 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/escaping.cc @@ -137,7 +137,7 @@ bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, // Copy the escape sequence for the null character const ptrdiff_t octal_size = p + 1 - octal_start; *d++ = '\\'; - memmove(d, octal_start, octal_size); + memmove(d, octal_start, octal_size); d += octal_size; break; } @@ -170,7 +170,7 @@ bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, // Copy the escape sequence for the null character const ptrdiff_t hex_size = p + 1 - hex_start; *d++ = '\\'; - memmove(d, hex_start, hex_size); + memmove(d, hex_start, hex_size); d += hex_size; break; } @@ -203,7 +203,7 @@ bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, if ((rune == 0) && leave_nulls_escaped) { // Copy the escape sequence for the null character *d++ = '\\'; - memmove(d, hex_start, 5); // u0000 + memmove(d, hex_start, 5); // u0000 d += 5; break; } @@ -251,7 +251,7 @@ bool CUnescapeInternal(y_absl::string_view source, bool leave_nulls_escaped, if ((rune == 0) && leave_nulls_escaped) { // Copy the escape sequence for the null character *d++ = '\\'; - memmove(d, hex_start, 9); // U00000000 + memmove(d, hex_start, 9); // U00000000 d += 9; break; } @@ -450,7 +450,7 @@ bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, // The GET_INPUT macro gets the next input character, skipping // over any whitespace, and stopping when we reach the end of the - // string or when we read any non-data character. The arguments are + // string or when we read any non-data character. The arguments are // an arbitrary identifier (used as a label for goto) and the number // of data bytes that must remain in the input to avoid aborting the // loop. @@ -473,18 +473,18 @@ bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, if (dest) { // This loop consumes 4 input bytes and produces 3 output bytes // per iteration. We can't know at the start that there is enough - // data left in the string for a full iteration, so the loop may + // data left in the string for a full iteration, so the loop may // break out in the middle; if so 'state' will be set to the // number of input bytes read. while (szsrc >= 4) { // We'll start by optimistically assuming that the next four - // bytes of the string (src[0..3]) are four good data bytes + // bytes of the string (src[0..3]) are four good data bytes // (that is, no nulls, whitespace, padding chars, or illegal // chars). We need to test src[0..2] for nulls individually // before constructing temp to preserve the property that we - // never read past a null in the string (no matter how long - // szsrc claims the string is). + // never read past a null in the string (no matter how long + // szsrc claims the string is). if (!src[0] || !src[1] || !src[2] || ((temp = ((unsigned(unbase64[src[0]]) << 18) | @@ -509,7 +509,7 @@ bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, temp = (temp << 6) | decode; } else { // We really did have four good data bytes, so advance four - // characters in the string. + // characters in the string. szsrc -= 4; src += 4; @@ -644,7 +644,7 @@ bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, state); } - // The remainder of the string should be all whitespace, mixed with + // The remainder of the string should be all whitespace, mixed with // exactly 0 equals signs, or exactly 'expected_equals' equals // signs. (Always accepting 0 equals signs is an Abseil extension // not covered in the RFC, as is accepting dot as the pad character.) @@ -771,7 +771,7 @@ constexpr char kWebSafeBase64Chars[] = template <typename String> bool Base64UnescapeInternal(const char* src, size_t slen, String* dest, const signed char* unbase64) { - // Determine the size of the output string. Base64 encodes every 3 bytes into + // Determine the size of the output string. Base64 encodes every 3 bytes into // 4 characters. any leftover chars are added directly for good measure. // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548 const size_t dest_len = 3 * (slen / 4) + (slen % 4); @@ -779,7 +779,7 @@ bool Base64UnescapeInternal(const char* src, size_t slen, String* dest, strings_internal::STLStringResizeUninitialized(dest, dest_len); // We are getting the destination buffer by getting the beginning of the - // string and converting it into a char *. + // string and converting it into a char *. size_t len; const bool ok = Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len); diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make index 42b7b6cd5e..5b0a4c0695 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make @@ -1,42 +1,42 @@ -# Generated by devtools/yamaker. - -LIBRARY() - -WITHOUT_LICENSE_TEXTS() - -OWNER( - somov - g:cpp-contrib -) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp-tstring/y_absl/base - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity - contrib/restricted/abseil-cpp-tstring/y_absl/numeric - contrib/restricted/abseil-cpp-tstring/y_absl/strings +# Generated by devtools/yamaker. + +LIBRARY() + +WITHOUT_LICENSE_TEXTS() + +OWNER( + somov + g:cpp-contrib +) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp-tstring/y_absl/base + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity + contrib/restricted/abseil-cpp-tstring/y_absl/numeric + contrib/restricted/abseil-cpp-tstring/y_absl/strings contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp-tstring -) - -NO_COMPILER_WARNINGS() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp-tstring +) + +NO_COMPILER_WARNINGS() + SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal) - -SRCS( + +SRCS( cord_internal.cc cord_rep_btree.cc cord_rep_btree_navigator.cc cord_rep_btree_reader.cc cord_rep_consume.cc cord_rep_ring.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make index 4e57fc75f6..f1c30b2590 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make @@ -4,17 +4,17 @@ LIBRARY() WITHOUT_LICENSE_TEXTS() -OWNER( - somov - g:cpp-contrib -) +OWNER( + somov + g:cpp-contrib +) LICENSE(Apache-2.0) PEERDIR( - contrib/restricted/abseil-cpp-tstring/y_absl/base + contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity ) diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h index 25428e304c..873125a571 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h @@ -72,7 +72,7 @@ class Charmap { CharMaskForWord(x, 2), CharMaskForWord(x, 3)); } - // Containing all the chars in the C-string 's'. + // Containing all the chars in the C-string 's'. // Note that this is expensively recursive because of the C++11 constexpr // formulation. Use only in constexpr initializers. static constexpr Charmap FromString(const char* s) { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc index 72a4fa188b..2b6742a64e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc @@ -208,7 +208,7 @@ int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end, ++dropped_digits; } if (begin < end && *std::prev(end) == '.') { - // If the string ends in '.', either before or after dropping zeroes, then + // If the string ends in '.', either before or after dropping zeroes, then // drop the decimal point and look for more digits to drop. dropped_digits = 0; --end; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h index a77aab14dd..75df41a2e1 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h @@ -66,7 +66,7 @@ class BigUnsigned { static_cast<uint32_t>(v >> 32)} {} // Constructs a BigUnsigned from the given string_view containing a decimal - // value. If the input string is not a decimal integer, constructs a 0 + // value. If the input string is not a decimal integer, constructs a 0 // instead. explicit BigUnsigned(y_absl::string_view sv) : size_(0), words_{} { // Check for valid input, returning a 0 otherwise. This is reasonable @@ -210,7 +210,7 @@ class BigUnsigned { return words_[index]; } - // Returns this integer as a decimal string. This is not used in the decimal- + // Returns this integer as a decimal string. This is not used in the decimal- // to-binary conversion; it is intended to aid in testing. TString ToString() const; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc index f0f78eb68c..cf92a22d56 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc @@ -246,8 +246,8 @@ constexpr int DigitMagnitude<16>() { // ConsumeDigits does not protect against overflow on *out; max_digits must // be chosen with respect to type T to avoid the possibility of overflow. template <int base, typename T> -int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out, - bool* dropped_nonzero_digit) { +int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out, + bool* dropped_nonzero_digit) { if (base == 10) { assert(max_digits <= std::numeric_limits<T>::digits10); } else if (base == 16) { @@ -282,7 +282,7 @@ int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out, *dropped_nonzero_digit = true; } *out = accumulator; - return static_cast<int>(begin - original_begin); + return static_cast<int>(begin - original_begin); } // Returns true if `v` is one of the chars allowed inside parentheses following @@ -302,7 +302,7 @@ bool ParseInfinityOrNan(const char* begin, const char* end, switch (*begin) { case 'i': case 'I': { - // An infinity string consists of the characters "inf" or "infinity", + // An infinity string consists of the characters "inf" or "infinity", // case insensitive. if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) { return false; @@ -326,7 +326,7 @@ bool ParseInfinityOrNan(const char* begin, const char* end, } out->type = strings_internal::FloatType::kNan; out->end = begin + 3; - // NaN is allowed to be followed by a parenthesized string, consisting of + // NaN is allowed to be followed by a parenthesized string, consisting of // only the characters [a-zA-Z0-9_]. Match that if it's present. begin += 3; if (begin < end && *begin == '(') { @@ -372,7 +372,7 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end, int exponent_adjustment = 0; bool mantissa_is_inexact = false; - int pre_decimal_digits = ConsumeDigits<base>( + int pre_decimal_digits = ConsumeDigits<base>( begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact); begin += pre_decimal_digits; int digits_left; @@ -398,14 +398,14 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end, while (begin < end && *begin == '0') { ++begin; } - int zeros_skipped = static_cast<int>(begin - begin_zeros); + int zeros_skipped = static_cast<int>(begin - begin_zeros); if (zeros_skipped >= DigitLimit<base>()) { // refuse to parse pathological inputs return result; } exponent_adjustment -= static_cast<int>(zeros_skipped); } - int post_decimal_digits = ConsumeDigits<base>( + int post_decimal_digits = ConsumeDigits<base>( begin, end, digits_left, &mantissa, &mantissa_is_inexact); begin += post_decimal_digits; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc index 6fc39985d8..d32e638883 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc @@ -1,89 +1,89 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "y_absl/strings/internal/cord_internal.h" - -#include <atomic> -#include <cassert> -#include <memory> - -#include "y_absl/container/inlined_vector.h" +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "y_absl/strings/internal/cord_internal.h" + +#include <atomic> +#include <cassert> +#include <memory> + +#include "y_absl/container/inlined_vector.h" #include "y_absl/strings/internal/cord_rep_btree.h" -#include "y_absl/strings/internal/cord_rep_flat.h" -#include "y_absl/strings/internal/cord_rep_ring.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - +#include "y_absl/strings/internal/cord_rep_flat.h" +#include "y_absl/strings/internal/cord_rep_ring.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + ABSL_CONST_INIT std::atomic<bool> cord_btree_enabled(kCordEnableBtreeDefault); -ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled( - kCordEnableRingBufferDefault); -ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled( - kCordShallowSubcordsDefault); +ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled( + kCordEnableRingBufferDefault); +ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled( + kCordShallowSubcordsDefault); ABSL_CONST_INIT std::atomic<bool> cord_btree_exhaustive_validation(false); - -void CordRep::Destroy(CordRep* rep) { - assert(rep != nullptr); - - y_absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending; - while (true) { - assert(!rep->refcount.IsImmortal()); - if (rep->tag == CONCAT) { - CordRepConcat* rep_concat = rep->concat(); - CordRep* right = rep_concat->right; - if (!right->refcount.Decrement()) { - pending.push_back(right); - } - CordRep* left = rep_concat->left; - delete rep_concat; - rep = nullptr; - if (!left->refcount.Decrement()) { - rep = left; - continue; - } + +void CordRep::Destroy(CordRep* rep) { + assert(rep != nullptr); + + y_absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending; + while (true) { + assert(!rep->refcount.IsImmortal()); + if (rep->tag == CONCAT) { + CordRepConcat* rep_concat = rep->concat(); + CordRep* right = rep_concat->right; + if (!right->refcount.Decrement()) { + pending.push_back(right); + } + CordRep* left = rep_concat->left; + delete rep_concat; + rep = nullptr; + if (!left->refcount.Decrement()) { + rep = left; + continue; + } } else if (rep->tag == BTREE) { CordRepBtree::Destroy(rep->btree()); rep = nullptr; - } else if (rep->tag == RING) { - CordRepRing::Destroy(rep->ring()); - rep = nullptr; - } else if (rep->tag == EXTERNAL) { - CordRepExternal::Delete(rep); - rep = nullptr; - } else if (rep->tag == SUBSTRING) { - CordRepSubstring* rep_substring = rep->substring(); - CordRep* child = rep_substring->child; - delete rep_substring; - rep = nullptr; - if (!child->refcount.Decrement()) { - rep = child; - continue; - } - } else { - CordRepFlat::Delete(rep); - rep = nullptr; - } - - if (!pending.empty()) { - rep = pending.back(); - pending.pop_back(); - } else { - break; - } - } -} - -} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace y_absl + } else if (rep->tag == RING) { + CordRepRing::Destroy(rep->ring()); + rep = nullptr; + } else if (rep->tag == EXTERNAL) { + CordRepExternal::Delete(rep); + rep = nullptr; + } else if (rep->tag == SUBSTRING) { + CordRepSubstring* rep_substring = rep->substring(); + CordRep* child = rep_substring->child; + delete rep_substring; + rep = nullptr; + if (!child->refcount.Decrement()) { + rep = child; + continue; + } + } else { + CordRepFlat::Delete(rep); + rep = nullptr; + } + + if (!pending.empty()) { + rep = pending.back(); + pending.pop_back(); + } else { + break; + } + } +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h index 82f5ac7b81..02b215f61f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h @@ -1,4 +1,4 @@ -// Copyright 2021 The Abseil Authors. +// Copyright 2021 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,11 +21,11 @@ #include <cstdint> #include <type_traits> -#include "y_absl/base/config.h" -#include "y_absl/base/internal/endian.h" -#include "y_absl/base/internal/invoke.h" -#include "y_absl/base/optimization.h" -#include "y_absl/container/internal/compressed_tuple.h" +#include "y_absl/base/config.h" +#include "y_absl/base/internal/endian.h" +#include "y_absl/base/internal/invoke.h" +#include "y_absl/base/optimization.h" +#include "y_absl/container/internal/compressed_tuple.h" #include "y_absl/meta/type_traits.h" #include "y_absl/strings/string_view.h" @@ -33,19 +33,19 @@ namespace y_absl { ABSL_NAMESPACE_BEGIN namespace cord_internal { -class CordzInfo; - -// Default feature enable states for cord ring buffers -enum CordFeatureDefaults { +class CordzInfo; + +// Default feature enable states for cord ring buffers +enum CordFeatureDefaults { kCordEnableBtreeDefault = true, - kCordEnableRingBufferDefault = false, - kCordShallowSubcordsDefault = false -}; - + kCordEnableRingBufferDefault = false, + kCordShallowSubcordsDefault = false +}; + extern std::atomic<bool> cord_btree_enabled; -extern std::atomic<bool> cord_ring_buffer_enabled; -extern std::atomic<bool> shallow_subcords_enabled; - +extern std::atomic<bool> cord_ring_buffer_enabled; +extern std::atomic<bool> shallow_subcords_enabled; + // `cord_btree_exhaustive_validation` can be set to force exhaustive validation // in debug assertions, and code that calls `IsValid()` explicitly. By default, // assertions should be relatively cheap and AssertValid() can easily lead to @@ -56,48 +56,48 @@ inline void enable_cord_btree(bool enable) { cord_btree_enabled.store(enable, std::memory_order_relaxed); } -inline void enable_cord_ring_buffer(bool enable) { - cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed); -} - -inline void enable_shallow_subcords(bool enable) { - shallow_subcords_enabled.store(enable, std::memory_order_relaxed); -} - -enum Constants { - // The inlined size to use with y_absl::InlinedVector. - // - // Note: The InlinedVectors in this file (and in cord.h) do not need to use - // the same value for their inlined size. The fact that they do is historical. - // It may be desirable for each to use a different inlined size optimized for - // that InlinedVector's usage. - // - // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for - // the inlined vector size (47 exists for backward compatibility). - kInlinedVectorSize = 47, - - // Prefer copying blocks of at most this size, otherwise reference count. - kMaxBytesToCopy = 511 -}; - +inline void enable_cord_ring_buffer(bool enable) { + cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed); +} + +inline void enable_shallow_subcords(bool enable) { + shallow_subcords_enabled.store(enable, std::memory_order_relaxed); +} + +enum Constants { + // The inlined size to use with y_absl::InlinedVector. + // + // Note: The InlinedVectors in this file (and in cord.h) do not need to use + // the same value for their inlined size. The fact that they do is historical. + // It may be desirable for each to use a different inlined size optimized for + // that InlinedVector's usage. + // + // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for + // the inlined vector size (47 exists for backward compatibility). + kInlinedVectorSize = 47, + + // Prefer copying blocks of at most this size, otherwise reference count. + kMaxBytesToCopy = 511 +}; + // Compact class for tracking the reference count and state flags for CordRep // instances. Data is stored in an atomic int32_t for compactness and speed. class RefcountAndFlags { public: constexpr RefcountAndFlags() : count_{kRefIncrement} {} - struct Immortal {}; + struct Immortal {}; explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {} struct WithCrc {}; explicit constexpr RefcountAndFlags(WithCrc) : count_(kCrcFlag | kRefIncrement) {} - // Increments the reference count. Imposes no memory ordering. - inline void Increment() { - count_.fetch_add(kRefIncrement, std::memory_order_relaxed); - } + // Increments the reference count. Imposes no memory ordering. + inline void Increment() { + count_.fetch_add(kRefIncrement, std::memory_order_relaxed); + } // Asserts that the current refcount is greater than 0. If the refcount is - // greater than 1, decrements the reference count. + // greater than 1, decrements the reference count. // // Returns false if there are no references outstanding; true otherwise. // Inserts barriers to ensure that state written before this method returns @@ -106,24 +106,24 @@ class RefcountAndFlags { inline bool Decrement() { int32_t refcount = count_.load(std::memory_order_acquire) & kRefcountMask; assert(refcount > 0 || refcount & kImmortalFlag); - return refcount != kRefIncrement && + return refcount != kRefIncrement && (count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & kRefcountMask) != kRefIncrement; } // Same as Decrement but expect that refcount is greater than 1. inline bool DecrementExpectHighRefcount() { - int32_t refcount = + int32_t refcount = count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & kRefcountMask; assert(refcount > 0 || refcount & kImmortalFlag); - return refcount != kRefIncrement; + return refcount != kRefIncrement; } // Returns the current reference count using acquire semantics. - inline int32_t Get() const { + inline int32_t Get() const { return count_.load(std::memory_order_acquire) >> kNumFlags; - } + } // Returns true if the referenced object carries a CRC value. bool HasCrc() const { @@ -151,22 +151,22 @@ class RefcountAndFlags { // // When this returns true, there are no other references, and data sinks // may safely adopt the children of the CordRep. - inline bool IsOne() { + inline bool IsOne() { return (count_.load(std::memory_order_acquire) & kRefcountMask) == kRefIncrement; - } + } - bool IsImmortal() const { + bool IsImmortal() const { return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0; - } - + } + private: // We reserve the bottom bits for flags. // kImmortalBit indicates that this entity should never be collected; it is // used for the StringConstant constructor to avoid collecting immutable // constant cords. // kReservedFlag is reserved for future use. - enum { + enum { kNumFlags = 2, kImmortalFlag = 0x1, @@ -178,8 +178,8 @@ class RefcountAndFlags { // purposes of equality. (A refcount of 0 or 1 does not count as 0 or 1 // if the immortal bit is set.) kRefcountMask = ~kCrcFlag, - }; - + }; + std::atomic<int32_t> count_; }; @@ -189,30 +189,30 @@ class RefcountAndFlags { // functions in the base class. struct CordRepConcat; -struct CordRepExternal; -struct CordRepFlat; +struct CordRepExternal; +struct CordRepFlat; struct CordRepSubstring; -class CordRepRing; +class CordRepRing; class CordRepBtree; -// Various representations that we allow -enum CordRepKind { - CONCAT = 0, +// Various representations that we allow +enum CordRepKind { + CONCAT = 0, SUBSTRING = 1, BTREE = 2, - RING = 3, + RING = 3, EXTERNAL = 4, - - // We have different tags for different sized flat arrays, + + // We have different tags for different sized flat arrays, // starting with FLAT, and limited to MAX_FLAT_TAG. The 225 value is based on - // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed - // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well - // as the Tag <---> Size logic so that FLAT stil represents the minimum flat - // allocation size. (32 bytes as of now). + // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed + // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well + // as the Tag <---> Size logic so that FLAT stil represents the minimum flat + // allocation size. (32 bytes as of now). FLAT = 5, MAX_FLAT_TAG = 225 -}; - +}; + // There are various locations where we want to check if some rep is a 'plain' // data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we // can perform this check in a single branch as 'tag >= EXTERNAL' @@ -225,13 +225,13 @@ static_assert(EXTERNAL == RING + 1, "BTREE and EXTERNAL not consecutive"); static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive"); struct CordRep { - CordRep() = default; + CordRep() = default; constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l) - : length(l), refcount(immortal), tag(EXTERNAL), storage{} {} - + : length(l), refcount(immortal), tag(EXTERNAL), storage{} {} + // The following three fields have to be less than 32 bytes since // that is the smallest supported flat node size. - size_t length; + size_t length; RefcountAndFlags refcount; // If tag < FLAT, it represents CordRepKind and indicates the type of node. // Otherwise, the node type is CordRepFlat and the tag is the encoded size. @@ -255,32 +255,32 @@ struct CordRep { constexpr bool IsFlat() const { return tag >= FLAT; } constexpr bool IsBtree() const { return tag == BTREE; } - inline CordRepRing* ring(); - inline const CordRepRing* ring() const; + inline CordRepRing* ring(); + inline const CordRepRing* ring() const; inline CordRepConcat* concat(); inline const CordRepConcat* concat() const; inline CordRepSubstring* substring(); inline const CordRepSubstring* substring() const; inline CordRepExternal* external(); inline const CordRepExternal* external() const; - inline CordRepFlat* flat(); - inline const CordRepFlat* flat() const; + inline CordRepFlat* flat(); + inline const CordRepFlat* flat() const; inline CordRepBtree* btree(); inline const CordRepBtree* btree() const; - - // -------------------------------------------------------------------- - // Memory management - - // Destroys the provided `rep`. - static void Destroy(CordRep* rep); - - // Increments the reference count of `rep`. - // Requires `rep` to be a non-null pointer value. - static inline CordRep* Ref(CordRep* rep); - - // Decrements the reference count of `rep`. Destroys rep if count reaches - // zero. Requires `rep` to be a non-null pointer value. - static inline void Unref(CordRep* rep); + + // -------------------------------------------------------------------- + // Memory management + + // Destroys the provided `rep`. + static void Destroy(CordRep* rep); + + // Increments the reference count of `rep`. + // Requires `rep` to be a non-null pointer value. + static inline CordRep* Ref(CordRep* rep); + + // Decrements the reference count of `rep`. Destroys rep if count reaches + // zero. Requires `rep` to be a non-null pointer value. + static inline void Unref(CordRep* rep); }; struct CordRepConcat : public CordRep { @@ -296,151 +296,151 @@ struct CordRepSubstring : public CordRep { CordRep* child; }; -// Type for function pointer that will invoke the releaser function and also -// delete the `CordRepExternalImpl` corresponding to the passed in -// `CordRepExternal`. -using ExternalReleaserInvoker = void (*)(CordRepExternal*); +// Type for function pointer that will invoke the releaser function and also +// delete the `CordRepExternalImpl` corresponding to the passed in +// `CordRepExternal`. +using ExternalReleaserInvoker = void (*)(CordRepExternal*); // External CordReps are allocated together with a type erased releaser. The // releaser is stored in the memory directly following the CordRepExternal. -struct CordRepExternal : public CordRep { - CordRepExternal() = default; - explicit constexpr CordRepExternal(y_absl::string_view str) +struct CordRepExternal : public CordRep { + CordRepExternal() = default; + explicit constexpr CordRepExternal(y_absl::string_view str) : CordRep(RefcountAndFlags::Immortal{}, str.size()), - base(str.data()), - releaser_invoker(nullptr) {} - + base(str.data()), + releaser_invoker(nullptr) {} + const char* base; // Pointer to function that knows how to call and destroy the releaser. ExternalReleaserInvoker releaser_invoker; - - // Deletes (releases) the external rep. + + // Deletes (releases) the external rep. // Requires rep != nullptr and rep->IsExternal() - static void Delete(CordRep* rep); + static void Delete(CordRep* rep); }; -struct Rank1 {}; -struct Rank0 : Rank1 {}; - -template <typename Releaser, typename = ::y_absl::base_internal::invoke_result_t< - Releaser, y_absl::string_view>> -void InvokeReleaser(Rank0, Releaser&& releaser, y_absl::string_view data) { - ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser), data); -} - -template <typename Releaser, - typename = ::y_absl::base_internal::invoke_result_t<Releaser>> -void InvokeReleaser(Rank1, Releaser&& releaser, y_absl::string_view) { - ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser)); -} - -// We use CompressedTuple so that we can benefit from EBCO. -template <typename Releaser> -struct CordRepExternalImpl - : public CordRepExternal, - public ::y_absl::container_internal::CompressedTuple<Releaser> { - // The extra int arg is so that we can avoid interfering with copy/move - // constructors while still benefitting from perfect forwarding. - template <typename T> - CordRepExternalImpl(T&& releaser, int) - : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) { - this->releaser_invoker = &Release; - } - - ~CordRepExternalImpl() { - InvokeReleaser(Rank0{}, std::move(this->template get<0>()), - y_absl::string_view(base, length)); - } - - static void Release(CordRepExternal* rep) { - delete static_cast<CordRepExternalImpl*>(rep); - } -}; - -inline void CordRepExternal::Delete(CordRep* rep) { +struct Rank1 {}; +struct Rank0 : Rank1 {}; + +template <typename Releaser, typename = ::y_absl::base_internal::invoke_result_t< + Releaser, y_absl::string_view>> +void InvokeReleaser(Rank0, Releaser&& releaser, y_absl::string_view data) { + ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser), data); +} + +template <typename Releaser, + typename = ::y_absl::base_internal::invoke_result_t<Releaser>> +void InvokeReleaser(Rank1, Releaser&& releaser, y_absl::string_view) { + ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser)); +} + +// We use CompressedTuple so that we can benefit from EBCO. +template <typename Releaser> +struct CordRepExternalImpl + : public CordRepExternal, + public ::y_absl::container_internal::CompressedTuple<Releaser> { + // The extra int arg is so that we can avoid interfering with copy/move + // constructors while still benefitting from perfect forwarding. + template <typename T> + CordRepExternalImpl(T&& releaser, int) + : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) { + this->releaser_invoker = &Release; + } + + ~CordRepExternalImpl() { + InvokeReleaser(Rank0{}, std::move(this->template get<0>()), + y_absl::string_view(base, length)); + } + + static void Release(CordRepExternal* rep) { + delete static_cast<CordRepExternalImpl*>(rep); + } +}; + +inline void CordRepExternal::Delete(CordRep* rep) { assert(rep != nullptr && rep->IsExternal()); - auto* rep_external = static_cast<CordRepExternal*>(rep); - assert(rep_external->releaser_invoker != nullptr); - rep_external->releaser_invoker(rep_external); -} - -template <typename Str> -struct ConstInitExternalStorage { - ABSL_CONST_INIT static CordRepExternal value; -}; - -template <typename Str> -CordRepExternal ConstInitExternalStorage<Str>::value(Str::value); - -enum { - kMaxInline = 15, -}; - -constexpr char GetOrNull(y_absl::string_view data, size_t pos) { - return pos < data.size() ? data[pos] : '\0'; -} - -// We store cordz_info as 64 bit pointer value in big endian format. This -// guarantees that the least significant byte of cordz_info matches the last -// byte of the inline data representation in as_chars_, which holds the inlined -// size or the 'is_tree' bit. -using cordz_info_t = int64_t; - -// Assert that the `cordz_info` pointer value perfectly overlaps the last half -// of `as_chars_` and can hold a pointer value. -static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, ""); -static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), ""); - -// BigEndianByte() creates a big endian representation of 'value', i.e.: a big -// endian value where the last byte in the host's representation holds 'value`, -// with all other bytes being 0. -static constexpr cordz_info_t BigEndianByte(unsigned char value) { -#if defined(ABSL_IS_BIG_ENDIAN) - return value; -#else - return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8); -#endif -} - -class InlineData { - public: + auto* rep_external = static_cast<CordRepExternal*>(rep); + assert(rep_external->releaser_invoker != nullptr); + rep_external->releaser_invoker(rep_external); +} + +template <typename Str> +struct ConstInitExternalStorage { + ABSL_CONST_INIT static CordRepExternal value; +}; + +template <typename Str> +CordRepExternal ConstInitExternalStorage<Str>::value(Str::value); + +enum { + kMaxInline = 15, +}; + +constexpr char GetOrNull(y_absl::string_view data, size_t pos) { + return pos < data.size() ? data[pos] : '\0'; +} + +// We store cordz_info as 64 bit pointer value in big endian format. This +// guarantees that the least significant byte of cordz_info matches the last +// byte of the inline data representation in as_chars_, which holds the inlined +// size or the 'is_tree' bit. +using cordz_info_t = int64_t; + +// Assert that the `cordz_info` pointer value perfectly overlaps the last half +// of `as_chars_` and can hold a pointer value. +static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, ""); +static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), ""); + +// BigEndianByte() creates a big endian representation of 'value', i.e.: a big +// endian value where the last byte in the host's representation holds 'value`, +// with all other bytes being 0. +static constexpr cordz_info_t BigEndianByte(unsigned char value) { +#if defined(ABSL_IS_BIG_ENDIAN) + return value; +#else + return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8); +#endif +} + +class InlineData { + public: // DefaultInitType forces the use of the default initialization constructor. enum DefaultInitType { kDefaultInit }; - // kNullCordzInfo holds the big endian representation of intptr_t(1) - // This is the 'null' / initial value of 'cordz_info'. The null value - // is specifically big endian 1 as with 64-bit pointers, the last - // byte of cordz_info overlaps with the last byte holding the tag. - static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1); - - constexpr InlineData() : as_chars_{0} {} + // kNullCordzInfo holds the big endian representation of intptr_t(1) + // This is the 'null' / initial value of 'cordz_info'. The null value + // is specifically big endian 1 as with 64-bit pointers, the last + // byte of cordz_info overlaps with the last byte holding the tag. + static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1); + + constexpr InlineData() : as_chars_{0} {} explicit InlineData(DefaultInitType) {} - explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {} - explicit constexpr InlineData(y_absl::string_view chars) - : as_chars_{ - GetOrNull(chars, 0), GetOrNull(chars, 1), - GetOrNull(chars, 2), GetOrNull(chars, 3), - GetOrNull(chars, 4), GetOrNull(chars, 5), - GetOrNull(chars, 6), GetOrNull(chars, 7), - GetOrNull(chars, 8), GetOrNull(chars, 9), - GetOrNull(chars, 10), GetOrNull(chars, 11), - GetOrNull(chars, 12), GetOrNull(chars, 13), - GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {} - - // Returns true if the current instance is empty. - // The 'empty value' is an inlined data value of zero length. - bool is_empty() const { return tag() == 0; } - - // Returns true if the current instance holds a tree value. - bool is_tree() const { return (tag() & 1) != 0; } - - // Returns true if the current instance holds a cordz_info value. - // Requires the current instance to hold a tree value. - bool is_profiled() const { - assert(is_tree()); - return as_tree_.cordz_info != kNullCordzInfo; - } - + explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {} + explicit constexpr InlineData(y_absl::string_view chars) + : as_chars_{ + GetOrNull(chars, 0), GetOrNull(chars, 1), + GetOrNull(chars, 2), GetOrNull(chars, 3), + GetOrNull(chars, 4), GetOrNull(chars, 5), + GetOrNull(chars, 6), GetOrNull(chars, 7), + GetOrNull(chars, 8), GetOrNull(chars, 9), + GetOrNull(chars, 10), GetOrNull(chars, 11), + GetOrNull(chars, 12), GetOrNull(chars, 13), + GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {} + + // Returns true if the current instance is empty. + // The 'empty value' is an inlined data value of zero length. + bool is_empty() const { return tag() == 0; } + + // Returns true if the current instance holds a tree value. + bool is_tree() const { return (tag() & 1) != 0; } + + // Returns true if the current instance holds a cordz_info value. + // Requires the current instance to hold a tree value. + bool is_profiled() const { + assert(is_tree()); + return as_tree_.cordz_info != kNullCordzInfo; + } + // Returns true if either of the provided instances hold a cordz_info value. // This method is more efficient than the equivalent `data1.is_profiled() || // data2.is_profiled()`. Requires both arguments to hold a tree. @@ -451,170 +451,170 @@ class InlineData { kNullCordzInfo; } - // Returns the cordz_info sampling instance for this instance, or nullptr - // if the current instance is not sampled and does not have CordzInfo data. - // Requires the current instance to hold a tree value. - CordzInfo* cordz_info() const { - assert(is_tree()); - intptr_t info = - static_cast<intptr_t>(y_absl::big_endian::ToHost64(as_tree_.cordz_info)); - assert(info & 1); - return reinterpret_cast<CordzInfo*>(info - 1); - } - - // Sets the current cordz_info sampling instance for this instance, or nullptr - // if the current instance is not sampled and does not have CordzInfo data. - // Requires the current instance to hold a tree value. - void set_cordz_info(CordzInfo* cordz_info) { - assert(is_tree()); - intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1; - as_tree_.cordz_info = y_absl::big_endian::FromHost64(info); - } - - // Resets the current cordz_info to null / empty. - void clear_cordz_info() { - assert(is_tree()); - as_tree_.cordz_info = kNullCordzInfo; - } - - // Returns a read only pointer to the character data inside this instance. - // Requires the current instance to hold inline data. - const char* as_chars() const { - assert(!is_tree()); - return as_chars_; - } - - // Returns a mutable pointer to the character data inside this instance. - // Should be used for 'write only' operations setting an inlined value. - // Applications can set the value of inlined data either before or after - // setting the inlined size, i.e., both of the below are valid: - // - // // Set inlined data and inline size - // memcpy(data_.as_chars(), data, size); - // data_.set_inline_size(size); - // - // // Set inlined size and inline data - // data_.set_inline_size(size); - // memcpy(data_.as_chars(), data, size); - // - // It's an error to read from the returned pointer without a preceding write - // if the current instance does not hold inline data, i.e.: is_tree() == true. - char* as_chars() { return as_chars_; } - - // Returns the tree value of this value. - // Requires the current instance to hold a tree value. - CordRep* as_tree() const { - assert(is_tree()); - return as_tree_.rep; - } - - // Initialize this instance to holding the tree value `rep`, - // initializing the cordz_info to null, i.e.: 'not profiled'. - void make_tree(CordRep* rep) { - as_tree_.rep = rep; - as_tree_.cordz_info = kNullCordzInfo; - } - - // Set the tree value of this instance to 'rep`. - // Requires the current instance to already hold a tree value. - // Does not affect the value of cordz_info. - void set_tree(CordRep* rep) { - assert(is_tree()); - as_tree_.rep = rep; - } - - // Returns the size of the inlined character data inside this instance. - // Requires the current instance to hold inline data. - size_t inline_size() const { - assert(!is_tree()); - return tag() >> 1; - } - - // Sets the size of the inlined character data inside this instance. - // Requires `size` to be <= kMaxInline. - // See the documentation on 'as_chars()' for more information and examples. - void set_inline_size(size_t size) { - ABSL_ASSERT(size <= kMaxInline); - tag() = static_cast<char>(size << 1); - } - - private: - // See cordz_info_t for forced alignment and size of `cordz_info` details. - struct AsTree { - explicit constexpr AsTree(y_absl::cord_internal::CordRep* tree) - : rep(tree), cordz_info(kNullCordzInfo) {} - // This union uses up extra space so that whether rep is 32 or 64 bits, - // cordz_info will still start at the eighth byte, and the last - // byte of cordz_info will still be the last byte of InlineData. - union { - y_absl::cord_internal::CordRep* rep; - cordz_info_t unused_aligner; - }; - cordz_info_t cordz_info; - }; - - char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; } - char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; } - - // If the data has length <= kMaxInline, we store it in `as_chars_`, and - // store the size in the last char of `as_chars_` shifted left + 1. - // Else we store it in a tree and store a pointer to that tree in - // `as_tree_.rep` and store a tag in `tagged_size`. + // Returns the cordz_info sampling instance for this instance, or nullptr + // if the current instance is not sampled and does not have CordzInfo data. + // Requires the current instance to hold a tree value. + CordzInfo* cordz_info() const { + assert(is_tree()); + intptr_t info = + static_cast<intptr_t>(y_absl::big_endian::ToHost64(as_tree_.cordz_info)); + assert(info & 1); + return reinterpret_cast<CordzInfo*>(info - 1); + } + + // Sets the current cordz_info sampling instance for this instance, or nullptr + // if the current instance is not sampled and does not have CordzInfo data. + // Requires the current instance to hold a tree value. + void set_cordz_info(CordzInfo* cordz_info) { + assert(is_tree()); + intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1; + as_tree_.cordz_info = y_absl::big_endian::FromHost64(info); + } + + // Resets the current cordz_info to null / empty. + void clear_cordz_info() { + assert(is_tree()); + as_tree_.cordz_info = kNullCordzInfo; + } + + // Returns a read only pointer to the character data inside this instance. + // Requires the current instance to hold inline data. + const char* as_chars() const { + assert(!is_tree()); + return as_chars_; + } + + // Returns a mutable pointer to the character data inside this instance. + // Should be used for 'write only' operations setting an inlined value. + // Applications can set the value of inlined data either before or after + // setting the inlined size, i.e., both of the below are valid: + // + // // Set inlined data and inline size + // memcpy(data_.as_chars(), data, size); + // data_.set_inline_size(size); + // + // // Set inlined size and inline data + // data_.set_inline_size(size); + // memcpy(data_.as_chars(), data, size); + // + // It's an error to read from the returned pointer without a preceding write + // if the current instance does not hold inline data, i.e.: is_tree() == true. + char* as_chars() { return as_chars_; } + + // Returns the tree value of this value. + // Requires the current instance to hold a tree value. + CordRep* as_tree() const { + assert(is_tree()); + return as_tree_.rep; + } + + // Initialize this instance to holding the tree value `rep`, + // initializing the cordz_info to null, i.e.: 'not profiled'. + void make_tree(CordRep* rep) { + as_tree_.rep = rep; + as_tree_.cordz_info = kNullCordzInfo; + } + + // Set the tree value of this instance to 'rep`. + // Requires the current instance to already hold a tree value. + // Does not affect the value of cordz_info. + void set_tree(CordRep* rep) { + assert(is_tree()); + as_tree_.rep = rep; + } + + // Returns the size of the inlined character data inside this instance. + // Requires the current instance to hold inline data. + size_t inline_size() const { + assert(!is_tree()); + return tag() >> 1; + } + + // Sets the size of the inlined character data inside this instance. + // Requires `size` to be <= kMaxInline. + // See the documentation on 'as_chars()' for more information and examples. + void set_inline_size(size_t size) { + ABSL_ASSERT(size <= kMaxInline); + tag() = static_cast<char>(size << 1); + } + + private: + // See cordz_info_t for forced alignment and size of `cordz_info` details. + struct AsTree { + explicit constexpr AsTree(y_absl::cord_internal::CordRep* tree) + : rep(tree), cordz_info(kNullCordzInfo) {} + // This union uses up extra space so that whether rep is 32 or 64 bits, + // cordz_info will still start at the eighth byte, and the last + // byte of cordz_info will still be the last byte of InlineData. + union { + y_absl::cord_internal::CordRep* rep; + cordz_info_t unused_aligner; + }; + cordz_info_t cordz_info; + }; + + char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; } + char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; } + + // If the data has length <= kMaxInline, we store it in `as_chars_`, and + // store the size in the last char of `as_chars_` shifted left + 1. + // Else we store it in a tree and store a pointer to that tree in + // `as_tree_.rep` and store a tag in `tagged_size`. union { - char as_chars_[kMaxInline + 1]; - AsTree as_tree_; - }; -}; - -static_assert(sizeof(InlineData) == kMaxInline + 1, ""); - -inline CordRepConcat* CordRep::concat() { + char as_chars_[kMaxInline + 1]; + AsTree as_tree_; + }; +}; + +static_assert(sizeof(InlineData) == kMaxInline + 1, ""); + +inline CordRepConcat* CordRep::concat() { assert(IsConcat()); - return static_cast<CordRepConcat*>(this); -} - -inline const CordRepConcat* CordRep::concat() const { + return static_cast<CordRepConcat*>(this); +} + +inline const CordRepConcat* CordRep::concat() const { assert(IsConcat()); - return static_cast<const CordRepConcat*>(this); -} - -inline CordRepSubstring* CordRep::substring() { + return static_cast<const CordRepConcat*>(this); +} + +inline CordRepSubstring* CordRep::substring() { assert(IsSubstring()); - return static_cast<CordRepSubstring*>(this); -} - -inline const CordRepSubstring* CordRep::substring() const { + return static_cast<CordRepSubstring*>(this); +} + +inline const CordRepSubstring* CordRep::substring() const { assert(IsSubstring()); - return static_cast<const CordRepSubstring*>(this); -} - -inline CordRepExternal* CordRep::external() { + return static_cast<const CordRepSubstring*>(this); +} + +inline CordRepExternal* CordRep::external() { assert(IsExternal()); - return static_cast<CordRepExternal*>(this); -} - -inline const CordRepExternal* CordRep::external() const { + return static_cast<CordRepExternal*>(this); +} + +inline const CordRepExternal* CordRep::external() const { assert(IsExternal()); - return static_cast<const CordRepExternal*>(this); -} - -inline CordRep* CordRep::Ref(CordRep* rep) { - assert(rep != nullptr); - rep->refcount.Increment(); - return rep; -} - -inline void CordRep::Unref(CordRep* rep) { - assert(rep != nullptr); - // Expect refcount to be 0. Avoiding the cost of an atomic decrement should - // typically outweigh the cost of an extra branch checking for ref == 1. - if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) { - Destroy(rep); - } -} - + return static_cast<const CordRepExternal*>(this); +} + +inline CordRep* CordRep::Ref(CordRep* rep) { + assert(rep != nullptr); + rep->refcount.Increment(); + return rep; +} + +inline void CordRep::Unref(CordRep* rep) { + assert(rep != nullptr); + // Expect refcount to be 0. Avoiding the cost of an atomic decrement should + // typically outweigh the cost of an extra branch checking for ref == 1. + if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) { + Destroy(rep); + } +} + } // namespace cord_internal - + ABSL_NAMESPACE_END } // namespace y_absl #endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h index 976613031c..5557022553 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h @@ -1,146 +1,146 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ -#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ - -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <memory> - -#include "y_absl/strings/internal/cord_internal.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - -// Note: all constants below are never ODR used and internal to cord, we define -// these as static constexpr to avoid 'in struct' definition and usage clutter. - -// Largest and smallest flat node lengths we are willing to allocate -// Flat allocation size is stored in tag, which currently can encode sizes up -// to 4K, encoded as multiple of either 8 or 32 bytes. -// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc. -// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and -// ideally a 'nice' size aligning with allocation and cacheline sizes like 32. -// kMaxFlatSize is bounded by the size resulting in a computed tag no greater -// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values. -static constexpr size_t kFlatOverhead = offsetof(CordRep, storage); -static constexpr size_t kMinFlatSize = 32; -static constexpr size_t kMaxFlatSize = 4096; -static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead; -static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead; - -constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) { +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ +#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> + +#include "y_absl/strings/internal/cord_internal.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// Note: all constants below are never ODR used and internal to cord, we define +// these as static constexpr to avoid 'in struct' definition and usage clutter. + +// Largest and smallest flat node lengths we are willing to allocate +// Flat allocation size is stored in tag, which currently can encode sizes up +// to 4K, encoded as multiple of either 8 or 32 bytes. +// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc. +// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and +// ideally a 'nice' size aligning with allocation and cacheline sizes like 32. +// kMaxFlatSize is bounded by the size resulting in a computed tag no greater +// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values. +static constexpr size_t kFlatOverhead = offsetof(CordRep, storage); +static constexpr size_t kMinFlatSize = 32; +static constexpr size_t kMaxFlatSize = 4096; +static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead; +static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead; + +constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) { return static_cast<uint8_t>((size <= 1024) ? size / 8 + 1 : 129 + size / 32 - 1024 / 32); -} - +} + static_assert(kMinFlatSize / 8 + 1 >= FLAT, ""); -static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, ""); - -// Helper functions for rounded div, and rounding to exact sizes. -constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; } -constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; } - -// Returns the size to the nearest equal or larger value that can be -// expressed exactly as a tag value. -inline size_t RoundUpForTag(size_t size) { - return RoundUp(size, (size <= 1024) ? 8 : 32); -} - -// Converts the allocated size to a tag, rounding down if the size -// does not exactly match a 'tag expressible' size value. The result is -// undefined if the size exceeds the maximum size that can be encoded in -// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>). -inline uint8_t AllocatedSizeToTag(size_t size) { - const uint8_t tag = AllocatedSizeToTagUnchecked(size); - assert(tag <= MAX_FLAT_TAG); - return tag; -} - -// Converts the provided tag to the corresponding allocated size -constexpr size_t TagToAllocatedSize(uint8_t tag) { +static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, ""); + +// Helper functions for rounded div, and rounding to exact sizes. +constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; } +constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; } + +// Returns the size to the nearest equal or larger value that can be +// expressed exactly as a tag value. +inline size_t RoundUpForTag(size_t size) { + return RoundUp(size, (size <= 1024) ? 8 : 32); +} + +// Converts the allocated size to a tag, rounding down if the size +// does not exactly match a 'tag expressible' size value. The result is +// undefined if the size exceeds the maximum size that can be encoded in +// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>). +inline uint8_t AllocatedSizeToTag(size_t size) { + const uint8_t tag = AllocatedSizeToTagUnchecked(size); + assert(tag <= MAX_FLAT_TAG); + return tag; +} + +// Converts the provided tag to the corresponding allocated size +constexpr size_t TagToAllocatedSize(uint8_t tag) { return (tag <= 129) ? ((tag - 1) * 8) : (1024 + (tag - 129) * 32); -} - -// Converts the provided tag to the corresponding available data length -constexpr size_t TagToLength(uint8_t tag) { - return TagToAllocatedSize(tag) - kFlatOverhead; -} - -// Enforce that kMaxFlatSize maps to a well-known exact tag value. +} + +// Converts the provided tag to the corresponding available data length +constexpr size_t TagToLength(uint8_t tag) { + return TagToAllocatedSize(tag) - kFlatOverhead; +} + +// Enforce that kMaxFlatSize maps to a well-known exact tag value. static_assert(TagToAllocatedSize(225) == kMaxFlatSize, "Bad tag logic"); - -struct CordRepFlat : public CordRep { - // Creates a new flat node. - static CordRepFlat* New(size_t len) { - if (len <= kMinFlatLength) { - len = kMinFlatLength; - } else if (len > kMaxFlatLength) { - len = kMaxFlatLength; - } - - // Round size up so it matches a size we can exactly express in a tag. - const size_t size = RoundUpForTag(len + kFlatOverhead); - void* const raw_rep = ::operator new(size); - CordRepFlat* rep = new (raw_rep) CordRepFlat(); - rep->tag = AllocatedSizeToTag(size); - return rep; - } - - // Deletes a CordRepFlat instance created previously through a call to New(). - // Flat CordReps are allocated and constructed with raw ::operator new and - // placement new, and must be destructed and deallocated accordingly. - static void Delete(CordRep*rep) { - assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG); - -#if defined(__cpp_sized_deallocation) - size_t size = TagToAllocatedSize(rep->tag); - rep->~CordRep(); - ::operator delete(rep, size); -#else - rep->~CordRep(); - ::operator delete(rep); -#endif - } - - // Returns a pointer to the data inside this flat rep. + +struct CordRepFlat : public CordRep { + // Creates a new flat node. + static CordRepFlat* New(size_t len) { + if (len <= kMinFlatLength) { + len = kMinFlatLength; + } else if (len > kMaxFlatLength) { + len = kMaxFlatLength; + } + + // Round size up so it matches a size we can exactly express in a tag. + const size_t size = RoundUpForTag(len + kFlatOverhead); + void* const raw_rep = ::operator new(size); + CordRepFlat* rep = new (raw_rep) CordRepFlat(); + rep->tag = AllocatedSizeToTag(size); + return rep; + } + + // Deletes a CordRepFlat instance created previously through a call to New(). + // Flat CordReps are allocated and constructed with raw ::operator new and + // placement new, and must be destructed and deallocated accordingly. + static void Delete(CordRep*rep) { + assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG); + +#if defined(__cpp_sized_deallocation) + size_t size = TagToAllocatedSize(rep->tag); + rep->~CordRep(); + ::operator delete(rep, size); +#else + rep->~CordRep(); + ::operator delete(rep); +#endif + } + + // Returns a pointer to the data inside this flat rep. char* Data() { return reinterpret_cast<char*>(storage); } const char* Data() const { return reinterpret_cast<const char*>(storage); } - - // Returns the maximum capacity (payload size) of this instance. - size_t Capacity() const { return TagToLength(tag); } - - // Returns the allocated size (payload + overhead) of this instance. - size_t AllocatedSize() const { return TagToAllocatedSize(tag); } -}; - -// Now that CordRepFlat is defined, we can define CordRep's helper casts: -inline CordRepFlat* CordRep::flat() { - assert(tag >= FLAT && tag <= MAX_FLAT_TAG); - return reinterpret_cast<CordRepFlat*>(this); -} - -inline const CordRepFlat* CordRep::flat() const { - assert(tag >= FLAT && tag <= MAX_FLAT_TAG); - return reinterpret_cast<const CordRepFlat*>(this); -} - -} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ + + // Returns the maximum capacity (payload size) of this instance. + size_t Capacity() const { return TagToLength(tag); } + + // Returns the allocated size (payload + overhead) of this instance. + size_t AllocatedSize() const { return TagToAllocatedSize(tag); } +}; + +// Now that CordRepFlat is defined, we can define CordRep's helper casts: +inline CordRepFlat* CordRep::flat() { + assert(tag >= FLAT && tag <= MAX_FLAT_TAG); + return reinterpret_cast<CordRepFlat*>(this); +} + +inline const CordRepFlat* CordRep::flat() const { + assert(tag >= FLAT && tag <= MAX_FLAT_TAG); + return reinterpret_cast<const CordRepFlat*>(this); +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace y_absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc index 06c7e75bd8..97dff05363 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc @@ -1,771 +1,771 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "y_absl/strings/internal/cord_rep_ring.h" - -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <iostream> -#include <limits> -#include <memory> -#include <util/generic/string.h> - -#include "y_absl/base/internal/raw_logging.h" -#include "y_absl/base/internal/throw_delegate.h" -#include "y_absl/base/macros.h" -#include "y_absl/container/inlined_vector.h" -#include "y_absl/strings/internal/cord_internal.h" +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "y_absl/strings/internal/cord_rep_ring.h" + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iostream> +#include <limits> +#include <memory> +#include <util/generic/string.h> + +#include "y_absl/base/internal/raw_logging.h" +#include "y_absl/base/internal/throw_delegate.h" +#include "y_absl/base/macros.h" +#include "y_absl/container/inlined_vector.h" +#include "y_absl/strings/internal/cord_internal.h" #include "y_absl/strings/internal/cord_rep_consume.h" -#include "y_absl/strings/internal/cord_rep_flat.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - -namespace { - -using index_type = CordRepRing::index_type; - -enum class Direction { kForward, kReversed }; - -inline bool IsFlatOrExternal(CordRep* rep) { +#include "y_absl/strings/internal/cord_rep_flat.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +namespace { + +using index_type = CordRepRing::index_type; + +enum class Direction { kForward, kReversed }; + +inline bool IsFlatOrExternal(CordRep* rep) { return rep->IsFlat() || rep->IsExternal(); -} - -// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise. -inline void CheckCapacity(size_t n, size_t extra) { - if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) { - base_internal::ThrowStdLengthError("Maximum capacity exceeded"); - } -} - -// Creates a flat from the provided string data, allocating up to `extra` -// capacity in the returned flat depending on kMaxFlatLength limitations. -// Requires `len` to be less or equal to `kMaxFlatLength` -CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) { // NOLINT - assert(n <= kMaxFlatLength); - auto* rep = CordRepFlat::New(n + extra); - rep->length = n; - memcpy(rep->Data(), s, n); - return rep; -} - -// Unrefs the entries in `[head, tail)`. -// Requires all entries to be a FLAT or EXTERNAL node. -void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) { - rep->ForEach(head, tail, [rep](index_type ix) { - CordRep* child = rep->entry_child(ix); - if (!child->refcount.Decrement()) { - if (child->tag >= FLAT) { - CordRepFlat::Delete(child->flat()); - } else { - CordRepExternal::Delete(child->external()); - } - } - }); -} - -} // namespace - -std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) { - // Note: 'pos' values are defined as size_t (for overflow reasons), but that - // prints really awkward for small prepended values such as -5. ssize_t is not - // portable (POSIX), so we use ptrdiff_t instead to cast to signed values. - s << " CordRepRing(" << &rep << ", length = " << rep.length - << ", head = " << rep.head_ << ", tail = " << rep.tail_ - << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get() - << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n"; - CordRepRing::index_type head = rep.head(); - do { - CordRep* child = rep.entry_child(head); - s << " entry[" << head << "] length = " << rep.entry_length(head) - << ", child " << child << ", clen = " << child->length - << ", tag = " << static_cast<int>(child->tag) - << ", rc = " << child->refcount.Get() - << ", offset = " << rep.entry_data_offset(head) - << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head)) - << "\n"; - head = rep.advance(head); - } while (head != rep.tail()); - return s << "}\n"; -} - -void CordRepRing::AddDataOffset(index_type index, size_t n) { - entry_data_offset()[index] += static_cast<offset_type>(n); -} - -void CordRepRing::SubLength(index_type index, size_t n) { - entry_end_pos()[index] -= n; -} - -class CordRepRing::Filler { - public: - Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {} - - index_type head() const { return head_; } - index_type pos() const { return pos_; } - - void Add(CordRep* child, size_t offset, pos_type end_pos) { - rep_->entry_end_pos()[pos_] = end_pos; - rep_->entry_child()[pos_] = child; - rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset); - pos_ = rep_->advance(pos_); - } - - private: - CordRepRing* rep_; - index_type head_; - index_type pos_; -}; - -constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11 - -bool CordRepRing::IsValid(std::ostream& output) const { - if (capacity_ == 0) { - output << "capacity == 0"; - return false; - } - - if (head_ >= capacity_ || tail_ >= capacity_) { - output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity " - << capacity_; - return false; - } - - const index_type back = retreat(tail_); - size_t pos_length = Distance(begin_pos_, entry_end_pos(back)); - if (pos_length != length) { - output << "length " << length << " does not match positional length " - << pos_length << " from begin_pos " << begin_pos_ << " and entry[" - << back << "].end_pos " << entry_end_pos(back); - return false; - } - - index_type head = head_; - pos_type begin_pos = begin_pos_; - do { - pos_type end_pos = entry_end_pos(head); - size_t entry_length = Distance(begin_pos, end_pos); - if (entry_length == 0) { - output << "entry[" << head << "] has an invalid length " << entry_length - << " from begin_pos " << begin_pos << " and end_pos " << end_pos; - return false; - } - - CordRep* child = entry_child(head); - if (child == nullptr) { - output << "entry[" << head << "].child == nullptr"; - return false; - } - if (child->tag < FLAT && child->tag != EXTERNAL) { - output << "entry[" << head << "].child has an invalid tag " - << static_cast<int>(child->tag); - return false; - } - - size_t offset = entry_data_offset(head); - if (offset >= child->length || entry_length > child->length - offset) { - output << "entry[" << head << "] has offset " << offset - << " and entry length " << entry_length +} + +// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise. +inline void CheckCapacity(size_t n, size_t extra) { + if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) { + base_internal::ThrowStdLengthError("Maximum capacity exceeded"); + } +} + +// Creates a flat from the provided string data, allocating up to `extra` +// capacity in the returned flat depending on kMaxFlatLength limitations. +// Requires `len` to be less or equal to `kMaxFlatLength` +CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) { // NOLINT + assert(n <= kMaxFlatLength); + auto* rep = CordRepFlat::New(n + extra); + rep->length = n; + memcpy(rep->Data(), s, n); + return rep; +} + +// Unrefs the entries in `[head, tail)`. +// Requires all entries to be a FLAT or EXTERNAL node. +void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) { + rep->ForEach(head, tail, [rep](index_type ix) { + CordRep* child = rep->entry_child(ix); + if (!child->refcount.Decrement()) { + if (child->tag >= FLAT) { + CordRepFlat::Delete(child->flat()); + } else { + CordRepExternal::Delete(child->external()); + } + } + }); +} + +} // namespace + +std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) { + // Note: 'pos' values are defined as size_t (for overflow reasons), but that + // prints really awkward for small prepended values such as -5. ssize_t is not + // portable (POSIX), so we use ptrdiff_t instead to cast to signed values. + s << " CordRepRing(" << &rep << ", length = " << rep.length + << ", head = " << rep.head_ << ", tail = " << rep.tail_ + << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get() + << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n"; + CordRepRing::index_type head = rep.head(); + do { + CordRep* child = rep.entry_child(head); + s << " entry[" << head << "] length = " << rep.entry_length(head) + << ", child " << child << ", clen = " << child->length + << ", tag = " << static_cast<int>(child->tag) + << ", rc = " << child->refcount.Get() + << ", offset = " << rep.entry_data_offset(head) + << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head)) + << "\n"; + head = rep.advance(head); + } while (head != rep.tail()); + return s << "}\n"; +} + +void CordRepRing::AddDataOffset(index_type index, size_t n) { + entry_data_offset()[index] += static_cast<offset_type>(n); +} + +void CordRepRing::SubLength(index_type index, size_t n) { + entry_end_pos()[index] -= n; +} + +class CordRepRing::Filler { + public: + Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {} + + index_type head() const { return head_; } + index_type pos() const { return pos_; } + + void Add(CordRep* child, size_t offset, pos_type end_pos) { + rep_->entry_end_pos()[pos_] = end_pos; + rep_->entry_child()[pos_] = child; + rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset); + pos_ = rep_->advance(pos_); + } + + private: + CordRepRing* rep_; + index_type head_; + index_type pos_; +}; + +constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11 + +bool CordRepRing::IsValid(std::ostream& output) const { + if (capacity_ == 0) { + output << "capacity == 0"; + return false; + } + + if (head_ >= capacity_ || tail_ >= capacity_) { + output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity " + << capacity_; + return false; + } + + const index_type back = retreat(tail_); + size_t pos_length = Distance(begin_pos_, entry_end_pos(back)); + if (pos_length != length) { + output << "length " << length << " does not match positional length " + << pos_length << " from begin_pos " << begin_pos_ << " and entry[" + << back << "].end_pos " << entry_end_pos(back); + return false; + } + + index_type head = head_; + pos_type begin_pos = begin_pos_; + do { + pos_type end_pos = entry_end_pos(head); + size_t entry_length = Distance(begin_pos, end_pos); + if (entry_length == 0) { + output << "entry[" << head << "] has an invalid length " << entry_length + << " from begin_pos " << begin_pos << " and end_pos " << end_pos; + return false; + } + + CordRep* child = entry_child(head); + if (child == nullptr) { + output << "entry[" << head << "].child == nullptr"; + return false; + } + if (child->tag < FLAT && child->tag != EXTERNAL) { + output << "entry[" << head << "].child has an invalid tag " + << static_cast<int>(child->tag); + return false; + } + + size_t offset = entry_data_offset(head); + if (offset >= child->length || entry_length > child->length - offset) { + output << "entry[" << head << "] has offset " << offset + << " and entry length " << entry_length << " which are outside of the child's length of " << child->length; - return false; - } - - begin_pos = end_pos; - head = advance(head); - } while (head != tail_); - - return true; -} - -#ifdef EXTRA_CORD_RING_VALIDATION -CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file, - int line) { - if (!rep->IsValid(std::cerr)) { - std::cerr << "\nERROR: CordRepRing corrupted"; - if (line) std::cerr << " at line " << line; - if (file) std::cerr << " in file " << file; - std::cerr << "\nContent = " << *rep; - abort(); - } - return rep; -} -#endif // EXTRA_CORD_RING_VALIDATION - -CordRepRing* CordRepRing::New(size_t capacity, size_t extra) { - CheckCapacity(capacity, extra); - - size_t size = AllocSize(capacity += extra); - void* mem = ::operator new(size); - auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity)); - rep->tag = RING; - rep->capacity_ = static_cast<index_type>(capacity); - rep->begin_pos_ = 0; - return rep; -} - -void CordRepRing::SetCapacityForTesting(size_t capacity) { - // Adjust for the changed layout - assert(capacity <= capacity_); - assert(head() == 0 || head() < tail()); - memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(), - Layout::Partial(capacity_).Pointer<1>(data_) + head(), - entries() * sizeof(Layout::ElementType<1>)); - memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(), - Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(), - entries() * sizeof(Layout::ElementType<2>)); - capacity_ = static_cast<index_type>(capacity); -} - -void CordRepRing::Delete(CordRepRing* rep) { + return false; + } + + begin_pos = end_pos; + head = advance(head); + } while (head != tail_); + + return true; +} + +#ifdef EXTRA_CORD_RING_VALIDATION +CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file, + int line) { + if (!rep->IsValid(std::cerr)) { + std::cerr << "\nERROR: CordRepRing corrupted"; + if (line) std::cerr << " at line " << line; + if (file) std::cerr << " in file " << file; + std::cerr << "\nContent = " << *rep; + abort(); + } + return rep; +} +#endif // EXTRA_CORD_RING_VALIDATION + +CordRepRing* CordRepRing::New(size_t capacity, size_t extra) { + CheckCapacity(capacity, extra); + + size_t size = AllocSize(capacity += extra); + void* mem = ::operator new(size); + auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity)); + rep->tag = RING; + rep->capacity_ = static_cast<index_type>(capacity); + rep->begin_pos_ = 0; + return rep; +} + +void CordRepRing::SetCapacityForTesting(size_t capacity) { + // Adjust for the changed layout + assert(capacity <= capacity_); + assert(head() == 0 || head() < tail()); + memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(), + Layout::Partial(capacity_).Pointer<1>(data_) + head(), + entries() * sizeof(Layout::ElementType<1>)); + memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(), + Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(), + entries() * sizeof(Layout::ElementType<2>)); + capacity_ = static_cast<index_type>(capacity); +} + +void CordRepRing::Delete(CordRepRing* rep) { assert(rep != nullptr && rep->IsRing()); -#if defined(__cpp_sized_deallocation) - size_t size = AllocSize(rep->capacity_); - rep->~CordRepRing(); - ::operator delete(rep, size); -#else - rep->~CordRepRing(); - ::operator delete(rep); -#endif -} - -void CordRepRing::Destroy(CordRepRing* rep) { - UnrefEntries(rep, rep->head(), rep->tail()); - Delete(rep); -} - -template <bool ref> -void CordRepRing::Fill(const CordRepRing* src, index_type head, - index_type tail) { - this->length = src->length; - head_ = 0; - tail_ = advance(0, src->entries(head, tail)); - begin_pos_ = src->begin_pos_; - - // TODO(mvels): there may be opportunities here for large buffers. - auto* dst_pos = entry_end_pos(); - auto* dst_child = entry_child(); - auto* dst_offset = entry_data_offset(); - src->ForEach(head, tail, [&](index_type index) { - *dst_pos++ = src->entry_end_pos(index); - CordRep* child = src->entry_child(index); - *dst_child++ = ref ? CordRep::Ref(child) : child; - *dst_offset++ = src->entry_data_offset(index); - }); -} - -CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head, - index_type tail, size_t extra) { - CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra); - newrep->Fill<true>(rep, head, tail); - CordRep::Unref(rep); - return newrep; -} - -CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) { - // Get current number of entries, and check for max capacity. - size_t entries = rep->entries(); - +#if defined(__cpp_sized_deallocation) + size_t size = AllocSize(rep->capacity_); + rep->~CordRepRing(); + ::operator delete(rep, size); +#else + rep->~CordRepRing(); + ::operator delete(rep); +#endif +} + +void CordRepRing::Destroy(CordRepRing* rep) { + UnrefEntries(rep, rep->head(), rep->tail()); + Delete(rep); +} + +template <bool ref> +void CordRepRing::Fill(const CordRepRing* src, index_type head, + index_type tail) { + this->length = src->length; + head_ = 0; + tail_ = advance(0, src->entries(head, tail)); + begin_pos_ = src->begin_pos_; + + // TODO(mvels): there may be opportunities here for large buffers. + auto* dst_pos = entry_end_pos(); + auto* dst_child = entry_child(); + auto* dst_offset = entry_data_offset(); + src->ForEach(head, tail, [&](index_type index) { + *dst_pos++ = src->entry_end_pos(index); + CordRep* child = src->entry_child(index); + *dst_child++ = ref ? CordRep::Ref(child) : child; + *dst_offset++ = src->entry_data_offset(index); + }); +} + +CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head, + index_type tail, size_t extra) { + CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra); + newrep->Fill<true>(rep, head, tail); + CordRep::Unref(rep); + return newrep; +} + +CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) { + // Get current number of entries, and check for max capacity. + size_t entries = rep->entries(); + if (!rep->refcount.IsMutable()) { return Copy(rep, rep->head(), rep->tail(), extra); - } else if (entries + extra > rep->capacity()) { + } else if (entries + extra > rep->capacity()) { const size_t min_grow = rep->capacity() + rep->capacity() / 2; const size_t min_extra = (std::max)(extra, min_grow - entries); - CordRepRing* newrep = CordRepRing::New(entries, min_extra); - newrep->Fill<false>(rep, rep->head(), rep->tail()); - CordRepRing::Delete(rep); - return newrep; - } else { - return rep; - } -} - -Span<char> CordRepRing::GetAppendBuffer(size_t size) { + CordRepRing* newrep = CordRepRing::New(entries, min_extra); + newrep->Fill<false>(rep, rep->head(), rep->tail()); + CordRepRing::Delete(rep); + return newrep; + } else { + return rep; + } +} + +Span<char> CordRepRing::GetAppendBuffer(size_t size) { assert(refcount.IsMutable()); - index_type back = retreat(tail_); - CordRep* child = entry_child(back); + index_type back = retreat(tail_); + CordRep* child = entry_child(back); if (child->tag >= FLAT && child->refcount.IsMutable()) { - size_t capacity = child->flat()->Capacity(); - pos_type end_pos = entry_end_pos(back); - size_t data_offset = entry_data_offset(back); - size_t entry_length = Distance(entry_begin_pos(back), end_pos); - size_t used = data_offset + entry_length; - if (size_t n = (std::min)(capacity - used, size)) { - child->length = data_offset + entry_length + n; - entry_end_pos()[back] = end_pos + n; - this->length += n; - return {child->flat()->Data() + used, n}; - } - } - return {nullptr, 0}; -} - -Span<char> CordRepRing::GetPrependBuffer(size_t size) { + size_t capacity = child->flat()->Capacity(); + pos_type end_pos = entry_end_pos(back); + size_t data_offset = entry_data_offset(back); + size_t entry_length = Distance(entry_begin_pos(back), end_pos); + size_t used = data_offset + entry_length; + if (size_t n = (std::min)(capacity - used, size)) { + child->length = data_offset + entry_length + n; + entry_end_pos()[back] = end_pos + n; + this->length += n; + return {child->flat()->Data() + used, n}; + } + } + return {nullptr, 0}; +} + +Span<char> CordRepRing::GetPrependBuffer(size_t size) { assert(refcount.IsMutable()); - CordRep* child = entry_child(head_); - size_t data_offset = entry_data_offset(head_); + CordRep* child = entry_child(head_); + size_t data_offset = entry_data_offset(head_); if (data_offset && child->refcount.IsMutable() && child->tag >= FLAT) { - size_t n = (std::min)(data_offset, size); - this->length += n; - begin_pos_ -= n; - data_offset -= n; - entry_data_offset()[head_] = static_cast<offset_type>(data_offset); - return {child->flat()->Data() + data_offset, n}; - } - return {nullptr, 0}; -} - -CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset, + size_t n = (std::min)(data_offset, size); + this->length += n; + begin_pos_ -= n; + data_offset -= n; + entry_data_offset()[head_] = static_cast<offset_type>(data_offset); + return {child->flat()->Data() + data_offset, n}; + } + return {nullptr, 0}; +} + +CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset, size_t len, size_t extra) { - CordRepRing* rep = CordRepRing::New(1, extra); - rep->head_ = 0; - rep->tail_ = rep->advance(0); + CordRepRing* rep = CordRepRing::New(1, extra); + rep->head_ = 0; + rep->tail_ = rep->advance(0); rep->length = len; rep->entry_end_pos()[0] = len; - rep->entry_child()[0] = child; - rep->entry_data_offset()[0] = static_cast<offset_type>(offset); - return Validate(rep); -} - -CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) { - CordRepRing* rep = nullptr; + rep->entry_child()[0] = child; + rep->entry_data_offset()[0] = static_cast<offset_type>(offset); + return Validate(rep); +} + +CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) { + CordRepRing* rep = nullptr; Consume(child, [&](CordRep* child_arg, size_t offset, size_t len) { if (IsFlatOrExternal(child_arg)) { rep = rep ? AppendLeaf(rep, child_arg, offset, len) : CreateFromLeaf(child_arg, offset, len, extra); - } else if (rep) { + } else if (rep) { rep = AddRing<AddMode::kAppend>(rep, child_arg->ring(), offset, len); } else if (offset == 0 && child_arg->length == len) { rep = Mutable(child_arg->ring(), extra); - } else { + } else { rep = SubRing(child_arg->ring(), offset, len, extra); - } - }); - return Validate(rep, nullptr, __LINE__); -} - -CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) { - size_t length = child->length; - if (IsFlatOrExternal(child)) { - return CreateFromLeaf(child, 0, length, extra); - } + } + }); + return Validate(rep, nullptr, __LINE__); +} + +CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) { + size_t length = child->length; + if (IsFlatOrExternal(child)) { + return CreateFromLeaf(child, 0, length, extra); + } if (child->IsRing()) { - return Mutable(child->ring(), extra); - } - return CreateSlow(child, extra); -} - -template <CordRepRing::AddMode mode> -CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring, + return Mutable(child->ring(), extra); + } + return CreateSlow(child, extra); +} + +template <CordRepRing::AddMode mode> +CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring, size_t offset, size_t len) { - assert(offset < ring->length); - constexpr bool append = mode == AddMode::kAppend; - Position head = ring->Find(offset); + assert(offset < ring->length); + constexpr bool append = mode == AddMode::kAppend; + Position head = ring->Find(offset); Position tail = ring->FindTail(head.index, offset + len); - const index_type entries = ring->entries(head.index, tail.index); - - rep = Mutable(rep, entries); - - // The delta for making ring[head].end_pos into 'len - offset' - const pos_type delta_length = + const index_type entries = ring->entries(head.index, tail.index); + + rep = Mutable(rep, entries); + + // The delta for making ring[head].end_pos into 'len - offset' + const pos_type delta_length = (append ? rep->begin_pos_ + rep->length : rep->begin_pos_ - len) - - ring->entry_begin_pos(head.index) - head.offset; - - // Start filling at `tail`, or `entries` before `head` - Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries)); - - if (ring->refcount.IsOne()) { - // Copy entries from source stealing the ref and adjusting the end position. - // Commit the filler as this is no-op. - ring->ForEach(head.index, tail.index, [&](index_type ix) { - filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix), - ring->entry_end_pos(ix) + delta_length); - }); - - // Unref entries we did not copy over, and delete source. - if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index); - if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_); - CordRepRing::Delete(ring); - } else { - ring->ForEach(head.index, tail.index, [&](index_type ix) { - CordRep* child = ring->entry_child(ix); - filler.Add(child, ring->entry_data_offset(ix), - ring->entry_end_pos(ix) + delta_length); - CordRep::Ref(child); - }); - CordRepRing::Unref(ring); - } - - if (head.offset) { - // Increase offset of first 'source' entry appended or prepended. - // This is always the entry in `filler.head()` - rep->AddDataOffset(filler.head(), head.offset); - } - - if (tail.offset) { - // Reduce length of last 'source' entry appended or prepended. - // This is always the entry tailed by `filler.pos()` - rep->SubLength(rep->retreat(filler.pos()), tail.offset); - } - - // Commit changes + ring->entry_begin_pos(head.index) - head.offset; + + // Start filling at `tail`, or `entries` before `head` + Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries)); + + if (ring->refcount.IsOne()) { + // Copy entries from source stealing the ref and adjusting the end position. + // Commit the filler as this is no-op. + ring->ForEach(head.index, tail.index, [&](index_type ix) { + filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix), + ring->entry_end_pos(ix) + delta_length); + }); + + // Unref entries we did not copy over, and delete source. + if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index); + if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_); + CordRepRing::Delete(ring); + } else { + ring->ForEach(head.index, tail.index, [&](index_type ix) { + CordRep* child = ring->entry_child(ix); + filler.Add(child, ring->entry_data_offset(ix), + ring->entry_end_pos(ix) + delta_length); + CordRep::Ref(child); + }); + CordRepRing::Unref(ring); + } + + if (head.offset) { + // Increase offset of first 'source' entry appended or prepended. + // This is always the entry in `filler.head()` + rep->AddDataOffset(filler.head(), head.offset); + } + + if (tail.offset) { + // Reduce length of last 'source' entry appended or prepended. + // This is always the entry tailed by `filler.pos()` + rep->SubLength(rep->retreat(filler.pos()), tail.offset); + } + + // Commit changes rep->length += len; - if (append) { - rep->tail_ = filler.pos(); - } else { - rep->head_ = filler.head(); + if (append) { + rep->tail_ = filler.pos(); + } else { + rep->head_ = filler.head(); rep->begin_pos_ -= len; - } - - return Validate(rep); -} - -CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) { + } + + return Validate(rep); +} + +CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) { Consume(child, [&rep](CordRep* child_arg, size_t offset, size_t len) { if (child_arg->IsRing()) { rep = AddRing<AddMode::kAppend>(rep, child_arg->ring(), offset, len); - } else { + } else { rep = AppendLeaf(rep, child_arg, offset, len); - } - }); - return rep; -} - -CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child, + } + }); + return rep; +} + +CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child, size_t offset, size_t len) { - rep = Mutable(rep, 1); - index_type back = rep->tail_; - const pos_type begin_pos = rep->begin_pos_ + rep->length; - rep->tail_ = rep->advance(rep->tail_); + rep = Mutable(rep, 1); + index_type back = rep->tail_; + const pos_type begin_pos = rep->begin_pos_ + rep->length; + rep->tail_ = rep->advance(rep->tail_); rep->length += len; rep->entry_end_pos()[back] = begin_pos + len; - rep->entry_child()[back] = child; - rep->entry_data_offset()[back] = static_cast<offset_type>(offset); - return Validate(rep, nullptr, __LINE__); -} - -CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) { - size_t length = child->length; - if (IsFlatOrExternal(child)) { - return AppendLeaf(rep, child, 0, length); - } + rep->entry_child()[back] = child; + rep->entry_data_offset()[back] = static_cast<offset_type>(offset); + return Validate(rep, nullptr, __LINE__); +} + +CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) { + size_t length = child->length; + if (IsFlatOrExternal(child)) { + return AppendLeaf(rep, child, 0, length); + } if (child->IsRing()) { - return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length); - } - return AppendSlow(rep, child); -} - -CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) { + return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length); + } + return AppendSlow(rep, child); +} + +CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) { ReverseConsume(child, [&](CordRep* child_arg, size_t offset, size_t len) { if (IsFlatOrExternal(child_arg)) { rep = PrependLeaf(rep, child_arg, offset, len); - } else { + } else { rep = AddRing<AddMode::kPrepend>(rep, child_arg->ring(), offset, len); - } - }); - return Validate(rep); -} - -CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child, + } + }); + return Validate(rep); +} + +CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child, size_t offset, size_t len) { - rep = Mutable(rep, 1); - index_type head = rep->retreat(rep->head_); - pos_type end_pos = rep->begin_pos_; - rep->head_ = head; + rep = Mutable(rep, 1); + index_type head = rep->retreat(rep->head_); + pos_type end_pos = rep->begin_pos_; + rep->head_ = head; rep->length += len; rep->begin_pos_ -= len; - rep->entry_end_pos()[head] = end_pos; - rep->entry_child()[head] = child; - rep->entry_data_offset()[head] = static_cast<offset_type>(offset); - return Validate(rep); -} - -CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) { - size_t length = child->length; - if (IsFlatOrExternal(child)) { - return PrependLeaf(rep, child, 0, length); - } + rep->entry_end_pos()[head] = end_pos; + rep->entry_child()[head] = child; + rep->entry_data_offset()[head] = static_cast<offset_type>(offset); + return Validate(rep); +} + +CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) { + size_t length = child->length; + if (IsFlatOrExternal(child)) { + return PrependLeaf(rep, child, 0, length); + } if (child->IsRing()) { - return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length); - } - return PrependSlow(rep, child); -} - -CordRepRing* CordRepRing::Append(CordRepRing* rep, y_absl::string_view data, - size_t extra) { + return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length); + } + return PrependSlow(rep, child); +} + +CordRepRing* CordRepRing::Append(CordRepRing* rep, y_absl::string_view data, + size_t extra) { if (rep->refcount.IsMutable()) { - Span<char> avail = rep->GetAppendBuffer(data.length()); - if (!avail.empty()) { - memcpy(avail.data(), data.data(), avail.length()); - data.remove_prefix(avail.length()); - } - } - if (data.empty()) return Validate(rep); - - const size_t flats = (data.length() - 1) / kMaxFlatLength + 1; - rep = Mutable(rep, flats); - - Filler filler(rep, rep->tail_); - pos_type pos = rep->begin_pos_ + rep->length; - - while (data.length() >= kMaxFlatLength) { - auto* flat = CreateFlat(data.data(), kMaxFlatLength); - filler.Add(flat, 0, pos += kMaxFlatLength); - data.remove_prefix(kMaxFlatLength); - } - - if (data.length()) { - auto* flat = CreateFlat(data.data(), data.length(), extra); - filler.Add(flat, 0, pos += data.length()); - } - - rep->length = pos - rep->begin_pos_; - rep->tail_ = filler.pos(); - - return Validate(rep); -} - -CordRepRing* CordRepRing::Prepend(CordRepRing* rep, y_absl::string_view data, - size_t extra) { + Span<char> avail = rep->GetAppendBuffer(data.length()); + if (!avail.empty()) { + memcpy(avail.data(), data.data(), avail.length()); + data.remove_prefix(avail.length()); + } + } + if (data.empty()) return Validate(rep); + + const size_t flats = (data.length() - 1) / kMaxFlatLength + 1; + rep = Mutable(rep, flats); + + Filler filler(rep, rep->tail_); + pos_type pos = rep->begin_pos_ + rep->length; + + while (data.length() >= kMaxFlatLength) { + auto* flat = CreateFlat(data.data(), kMaxFlatLength); + filler.Add(flat, 0, pos += kMaxFlatLength); + data.remove_prefix(kMaxFlatLength); + } + + if (data.length()) { + auto* flat = CreateFlat(data.data(), data.length(), extra); + filler.Add(flat, 0, pos += data.length()); + } + + rep->length = pos - rep->begin_pos_; + rep->tail_ = filler.pos(); + + return Validate(rep); +} + +CordRepRing* CordRepRing::Prepend(CordRepRing* rep, y_absl::string_view data, + size_t extra) { if (rep->refcount.IsMutable()) { - Span<char> avail = rep->GetPrependBuffer(data.length()); - if (!avail.empty()) { - const char* tail = data.data() + data.length() - avail.length(); - memcpy(avail.data(), tail, avail.length()); - data.remove_suffix(avail.length()); - } - } - if (data.empty()) return rep; - - const size_t flats = (data.length() - 1) / kMaxFlatLength + 1; - rep = Mutable(rep, flats); - pos_type pos = rep->begin_pos_; - Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats))); - - size_t first_size = data.size() - (flats - 1) * kMaxFlatLength; - CordRepFlat* flat = CordRepFlat::New(first_size + extra); - flat->length = first_size + extra; - memcpy(flat->Data() + extra, data.data(), first_size); - data.remove_prefix(first_size); - filler.Add(flat, extra, pos); - pos -= first_size; - - while (!data.empty()) { - assert(data.size() >= kMaxFlatLength); - flat = CreateFlat(data.data(), kMaxFlatLength); - filler.Add(flat, 0, pos); - pos -= kMaxFlatLength; - data.remove_prefix(kMaxFlatLength); - } - - rep->head_ = filler.head(); - rep->length += rep->begin_pos_ - pos; - rep->begin_pos_ = pos; - - return Validate(rep); -} - -// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86 -static constexpr index_type kBinarySearchThreshold = 32; -static constexpr index_type kBinarySearchEndCount = 8; - -template <bool wrap> -CordRepRing::index_type CordRepRing::FindBinary(index_type head, - index_type tail, - size_t offset) const { - index_type count = tail + (wrap ? capacity_ : 0) - head; - do { - count = (count - 1) / 2; - assert(count < entries(head, tail_)); - index_type mid = wrap ? advance(head, count) : head + count; - index_type after_mid = wrap ? advance(mid) : mid + 1; - bool larger = (offset >= entry_end_offset(mid)); - head = larger ? after_mid : head; - tail = larger ? tail : mid; - assert(head != tail); - } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount)); - return head; -} - -CordRepRing::Position CordRepRing::FindSlow(index_type head, - size_t offset) const { - index_type tail = tail_; - - // Binary search until we are good for linear search - // Optimize for branchless / non wrapping ops - if (tail > head) { - index_type count = tail - head; - if (count > kBinarySearchThreshold) { - head = FindBinary<false>(head, tail, offset); - } - } else { - index_type count = capacity_ + tail - head; - if (count > kBinarySearchThreshold) { - head = FindBinary<true>(head, tail, offset); - } - } - - pos_type pos = entry_begin_pos(head); - pos_type end_pos = entry_end_pos(head); - while (offset >= Distance(begin_pos_, end_pos)) { - head = advance(head); - pos = end_pos; - end_pos = entry_end_pos(head); - } - - return {head, offset - Distance(begin_pos_, pos)}; -} - -CordRepRing::Position CordRepRing::FindTailSlow(index_type head, - size_t offset) const { - index_type tail = tail_; - const size_t tail_offset = offset - 1; - - // Binary search until we are good for linear search - // Optimize for branchless / non wrapping ops - if (tail > head) { - index_type count = tail - head; - if (count > kBinarySearchThreshold) { - head = FindBinary<false>(head, tail, tail_offset); - } - } else { - index_type count = capacity_ + tail - head; - if (count > kBinarySearchThreshold) { - head = FindBinary<true>(head, tail, tail_offset); - } - } - - size_t end_offset = entry_end_offset(head); - while (tail_offset >= end_offset) { - head = advance(head); - end_offset = entry_end_offset(head); - } - - return {advance(head), end_offset - offset}; -} - -char CordRepRing::GetCharacter(size_t offset) const { - assert(offset < length); - - Position pos = Find(offset); - size_t data_offset = entry_data_offset(pos.index) + pos.offset; - return GetRepData(entry_child(pos.index))[data_offset]; -} - -CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset, + Span<char> avail = rep->GetPrependBuffer(data.length()); + if (!avail.empty()) { + const char* tail = data.data() + data.length() - avail.length(); + memcpy(avail.data(), tail, avail.length()); + data.remove_suffix(avail.length()); + } + } + if (data.empty()) return rep; + + const size_t flats = (data.length() - 1) / kMaxFlatLength + 1; + rep = Mutable(rep, flats); + pos_type pos = rep->begin_pos_; + Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats))); + + size_t first_size = data.size() - (flats - 1) * kMaxFlatLength; + CordRepFlat* flat = CordRepFlat::New(first_size + extra); + flat->length = first_size + extra; + memcpy(flat->Data() + extra, data.data(), first_size); + data.remove_prefix(first_size); + filler.Add(flat, extra, pos); + pos -= first_size; + + while (!data.empty()) { + assert(data.size() >= kMaxFlatLength); + flat = CreateFlat(data.data(), kMaxFlatLength); + filler.Add(flat, 0, pos); + pos -= kMaxFlatLength; + data.remove_prefix(kMaxFlatLength); + } + + rep->head_ = filler.head(); + rep->length += rep->begin_pos_ - pos; + rep->begin_pos_ = pos; + + return Validate(rep); +} + +// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86 +static constexpr index_type kBinarySearchThreshold = 32; +static constexpr index_type kBinarySearchEndCount = 8; + +template <bool wrap> +CordRepRing::index_type CordRepRing::FindBinary(index_type head, + index_type tail, + size_t offset) const { + index_type count = tail + (wrap ? capacity_ : 0) - head; + do { + count = (count - 1) / 2; + assert(count < entries(head, tail_)); + index_type mid = wrap ? advance(head, count) : head + count; + index_type after_mid = wrap ? advance(mid) : mid + 1; + bool larger = (offset >= entry_end_offset(mid)); + head = larger ? after_mid : head; + tail = larger ? tail : mid; + assert(head != tail); + } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount)); + return head; +} + +CordRepRing::Position CordRepRing::FindSlow(index_type head, + size_t offset) const { + index_type tail = tail_; + + // Binary search until we are good for linear search + // Optimize for branchless / non wrapping ops + if (tail > head) { + index_type count = tail - head; + if (count > kBinarySearchThreshold) { + head = FindBinary<false>(head, tail, offset); + } + } else { + index_type count = capacity_ + tail - head; + if (count > kBinarySearchThreshold) { + head = FindBinary<true>(head, tail, offset); + } + } + + pos_type pos = entry_begin_pos(head); + pos_type end_pos = entry_end_pos(head); + while (offset >= Distance(begin_pos_, end_pos)) { + head = advance(head); + pos = end_pos; + end_pos = entry_end_pos(head); + } + + return {head, offset - Distance(begin_pos_, pos)}; +} + +CordRepRing::Position CordRepRing::FindTailSlow(index_type head, + size_t offset) const { + index_type tail = tail_; + const size_t tail_offset = offset - 1; + + // Binary search until we are good for linear search + // Optimize for branchless / non wrapping ops + if (tail > head) { + index_type count = tail - head; + if (count > kBinarySearchThreshold) { + head = FindBinary<false>(head, tail, tail_offset); + } + } else { + index_type count = capacity_ + tail - head; + if (count > kBinarySearchThreshold) { + head = FindBinary<true>(head, tail, tail_offset); + } + } + + size_t end_offset = entry_end_offset(head); + while (tail_offset >= end_offset) { + head = advance(head); + end_offset = entry_end_offset(head); + } + + return {advance(head), end_offset - offset}; +} + +char CordRepRing::GetCharacter(size_t offset) const { + assert(offset < length); + + Position pos = Find(offset); + size_t data_offset = entry_data_offset(pos.index) + pos.offset; + return GetRepData(entry_child(pos.index))[data_offset]; +} + +CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset, size_t len, size_t extra) { - assert(offset <= rep->length); + assert(offset <= rep->length); assert(offset <= rep->length - len); - + if (len == 0) { - CordRep::Unref(rep); - return nullptr; - } - - // Find position of first byte - Position head = rep->Find(offset); + CordRep::Unref(rep); + return nullptr; + } + + // Find position of first byte + Position head = rep->Find(offset); Position tail = rep->FindTail(head.index, offset + len); - const size_t new_entries = rep->entries(head.index, tail.index); - + const size_t new_entries = rep->entries(head.index, tail.index); + if (rep->refcount.IsMutable() && extra <= (rep->capacity() - new_entries)) { - // We adopt a privately owned rep and no extra entries needed. - if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index); - if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_); - rep->head_ = head.index; - rep->tail_ = tail.index; - } else { - // Copy subset to new rep - rep = Copy(rep, head.index, tail.index, extra); - head.index = rep->head_; - tail.index = rep->tail_; - } - - // Adjust begin_pos and length + // We adopt a privately owned rep and no extra entries needed. + if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index); + if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_); + rep->head_ = head.index; + rep->tail_ = tail.index; + } else { + // Copy subset to new rep + rep = Copy(rep, head.index, tail.index, extra); + head.index = rep->head_; + tail.index = rep->tail_; + } + + // Adjust begin_pos and length rep->length = len; - rep->begin_pos_ += offset; - - // Adjust head and tail blocks - if (head.offset) { - rep->AddDataOffset(head.index, head.offset); - } - if (tail.offset) { - rep->SubLength(rep->retreat(tail.index), tail.offset); - } - - return Validate(rep); -} - -CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len, - size_t extra) { - assert(len <= rep->length); - if (len == rep->length) { - CordRep::Unref(rep); - return nullptr; - } - - Position head = rep->Find(len); + rep->begin_pos_ += offset; + + // Adjust head and tail blocks + if (head.offset) { + rep->AddDataOffset(head.index, head.offset); + } + if (tail.offset) { + rep->SubLength(rep->retreat(tail.index), tail.offset); + } + + return Validate(rep); +} + +CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len, + size_t extra) { + assert(len <= rep->length); + if (len == rep->length) { + CordRep::Unref(rep); + return nullptr; + } + + Position head = rep->Find(len); if (rep->refcount.IsMutable()) { - if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index); - rep->head_ = head.index; - } else { - rep = Copy(rep, head.index, rep->tail_, extra); - head.index = rep->head_; - } - - // Adjust begin_pos and length - rep->length -= len; - rep->begin_pos_ += len; - - // Adjust head block - if (head.offset) { - rep->AddDataOffset(head.index, head.offset); - } - - return Validate(rep); -} - -CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len, - size_t extra) { - assert(len <= rep->length); - - if (len == rep->length) { - CordRep::Unref(rep); - return nullptr; - } - - Position tail = rep->FindTail(rep->length - len); + if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index); + rep->head_ = head.index; + } else { + rep = Copy(rep, head.index, rep->tail_, extra); + head.index = rep->head_; + } + + // Adjust begin_pos and length + rep->length -= len; + rep->begin_pos_ += len; + + // Adjust head block + if (head.offset) { + rep->AddDataOffset(head.index, head.offset); + } + + return Validate(rep); +} + +CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len, + size_t extra) { + assert(len <= rep->length); + + if (len == rep->length) { + CordRep::Unref(rep); + return nullptr; + } + + Position tail = rep->FindTail(rep->length - len); if (rep->refcount.IsMutable()) { - // We adopt a privately owned rep, scrub. - if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_); - rep->tail_ = tail.index; - } else { - // Copy subset to new rep - rep = Copy(rep, rep->head_, tail.index, extra); - tail.index = rep->tail_; - } - - // Adjust length - rep->length -= len; - - // Adjust tail block - if (tail.offset) { - rep->SubLength(rep->retreat(tail.index), tail.offset); - } - - return Validate(rep); -} - -} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace y_absl + // We adopt a privately owned rep, scrub. + if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_); + rep->tail_ = tail.index; + } else { + // Copy subset to new rep + rep = Copy(rep, rep->head_, tail.index, extra); + tail.index = rep->tail_; + } + + // Adjust length + rep->length -= len; + + // Adjust tail block + if (tail.offset) { + rep->SubLength(rep->retreat(tail.index), tail.offset); + } + + return Validate(rep); +} + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h index 5f9784d8da..a6a4890ab4 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h @@ -1,233 +1,233 @@ -// Copyright 2020 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ -#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ - -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <iosfwd> -#include <limits> -#include <memory> - -#include "y_absl/container/internal/layout.h" -#include "y_absl/strings/internal/cord_internal.h" -#include "y_absl/strings/internal/cord_rep_flat.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - -// All operations modifying a ring buffer are implemented as static methods -// requiring a CordRepRing instance with a reference adopted by the method. -// -// The methods return the modified ring buffer, which may be equal to the input -// if the input was not shared, and having large enough capacity to accommodate -// any newly added node(s). Otherwise, a copy of the input rep with the new -// node(s) added is returned. -// -// Any modification on non shared ring buffers with enough capacity will then -// require minimum atomic operations. Caller should where possible provide -// reasonable `extra` hints for both anticipated extra `flat` byte space, as -// well as anticipated extra nodes required for complex operations. -// -// Example of code creating a ring buffer, adding some data to it, -// and discarding the buffer when done: -// -// void FunWithRings() { -// // Create ring with 3 flats -// CordRep* flat = CreateFlat("Hello"); -// CordRepRing* ring = CordRepRing::Create(flat, 2); -// ring = CordRepRing::Append(ring, CreateFlat(" ")); -// ring = CordRepRing::Append(ring, CreateFlat("world")); -// DoSomethingWithRing(ring); -// CordRep::Unref(ring); -// } -// -// Example of code Copying an existing ring buffer and modifying it: -// -// void MoreFunWithRings(CordRepRing* src) { -// CordRepRing* ring = CordRep::Ref(src)->ring(); -// ring = CordRepRing::Append(ring, CreateFlat("Hello")); -// ring = CordRepRing::Append(ring, CreateFlat(" ")); -// ring = CordRepRing::Append(ring, CreateFlat("world")); -// DoSomethingWithRing(ring); -// CordRep::Unref(ring); -// } -// -class CordRepRing : public CordRep { - public: - // `pos_type` represents a 'logical position'. A CordRepRing instance has a - // `begin_pos` (default 0), and each node inside the buffer will have an - // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus - // this node's length. The purpose is to allow for a binary search on this - // position, while allowing O(1) prepend and append operations. - using pos_type = size_t; - - // `index_type` is the type for the `head`, `tail` and `capacity` indexes. - // Ring buffers are limited to having no more than four billion entries. - using index_type = uint32_t; - - // `offset_type` is the type for the data offset inside a child rep's data. - using offset_type = uint32_t; - - // Position holds the node index and relative offset into the node for - // some physical offset in the contained data as returned by the Find() - // and FindTail() methods. - struct Position { - index_type index; - size_t offset; - }; - - // The maximum # of child nodes that can be hosted inside a CordRepRing. - static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)(); - - // CordRepring can not be default constructed, moved, copied or assigned. - CordRepRing() = delete; - CordRepRing(const CordRepRing&) = delete; - CordRepRing& operator=(const CordRepRing&) = delete; - - // Returns true if this instance is valid, false if some or all of the - // invariants are broken. Intended for debug purposes only. - // `output` receives an explanation of the broken invariants. - bool IsValid(std::ostream& output) const; - - // Returns the size in bytes for a CordRepRing with `capacity' entries. - static constexpr size_t AllocSize(size_t capacity); - - // Returns the distance in bytes from `pos` to `end_pos`. - static constexpr size_t Distance(pos_type pos, pos_type end_pos); - - // Creates a new ring buffer from the provided `rep`. Adopts a reference - // on `rep`. The returned ring buffer has a capacity of at least `extra + 1` - static CordRepRing* Create(CordRep* child, size_t extra = 0); - - // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries. - index_type head() const { return head_; } - index_type tail() const { return tail_; } - index_type capacity() const { return capacity_; } - - // Returns the number of entries in this instance. - index_type entries() const { return entries(head_, tail_); } - - // Returns the logical begin position of this instance. - pos_type begin_pos() const { return begin_pos_; } - - // Returns the number of entries for a given head-tail range. - // Requires `head` and `tail` values to be less than `capacity()`. - index_type entries(index_type head, index_type tail) const { - assert(head < capacity_ && tail < capacity_); - return tail - head + ((tail > head) ? 0 : capacity_); - } - - // Returns the logical end position of entry `index`. - pos_type const& entry_end_pos(index_type index) const { - assert(IsValidIndex(index)); - return Layout::Partial().Pointer<0>(data_)[index]; - } - - // Returns the child pointer of entry `index`. - CordRep* const& entry_child(index_type index) const { - assert(IsValidIndex(index)); - return Layout::Partial(capacity()).Pointer<1>(data_)[index]; - } - - // Returns the data offset of entry `index` - offset_type const& entry_data_offset(index_type index) const { - assert(IsValidIndex(index)); - return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index]; - } - - // Appends the provided child node to the `rep` instance. - // Adopts a reference from `rep` and `child` which may not be null. - // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node - // containing a FLAT or EXTERNAL node, then flat or external the node is added - // 'as is', with an offset added for the SUBSTRING case. - // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or - // CONCAT tree, then all child nodes not excluded by any start offset or - // length values are added recursively. - static CordRepRing* Append(CordRepRing* rep, CordRep* child); - - // Appends the provided string data to the `rep` instance. - // This function will attempt to utilize any remaining capacity in the last - // node of the input if that node is not shared (directly or indirectly), and - // of type FLAT. Remaining data will be added as one or more FLAT nodes. - // Any last node added to the ring buffer will be allocated with up to - // `extra` bytes of capacity for (anticipated) subsequent append actions. - static CordRepRing* Append(CordRepRing* rep, string_view data, - size_t extra = 0); - - // Prepends the provided child node to the `rep` instance. - // Adopts a reference from `rep` and `child` which may not be null. - // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node - // containing a FLAT or EXTERNAL node, then flat or external the node is - // prepended 'as is', with an optional offset added for the SUBSTRING case. - // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING - // or CONCAT tree, then all child nodes not excluded by any start offset or - // length values are added recursively. - static CordRepRing* Prepend(CordRepRing* rep, CordRep* child); - - // Prepends the provided string data to the `rep` instance. - // This function will attempt to utilize any remaining capacity in the first - // node of the input if that node is not shared (directly or indirectly), and - // of type FLAT. Remaining data will be added as one or more FLAT nodes. - // Any first node prepnded to the ring buffer will be allocated with up to - // `extra` bytes of capacity for (anticipated) subsequent prepend actions. - static CordRepRing* Prepend(CordRepRing* rep, string_view data, - size_t extra = 0); - - // Returns a span referencing potentially unused capacity in the last node. - // The returned span may be empty if no such capacity is available, or if the - // current instance is shared. Else, a span of size `n <= size` is returned. - // If non empty, the ring buffer is adjusted to the new length, with the newly - // added capacity left uninitialized. Callers should assign a value to the - // entire span before any other operations on this instance. - Span<char> GetAppendBuffer(size_t size); - - // Returns a span referencing potentially unused capacity in the first node. - // This function is identical to GetAppendBuffer except that it returns a span - // referencing up to `size` capacity directly before the existing data. - Span<char> GetPrependBuffer(size_t size); - +// Copyright 2020 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ +#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <iosfwd> +#include <limits> +#include <memory> + +#include "y_absl/container/internal/layout.h" +#include "y_absl/strings/internal/cord_internal.h" +#include "y_absl/strings/internal/cord_rep_flat.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// All operations modifying a ring buffer are implemented as static methods +// requiring a CordRepRing instance with a reference adopted by the method. +// +// The methods return the modified ring buffer, which may be equal to the input +// if the input was not shared, and having large enough capacity to accommodate +// any newly added node(s). Otherwise, a copy of the input rep with the new +// node(s) added is returned. +// +// Any modification on non shared ring buffers with enough capacity will then +// require minimum atomic operations. Caller should where possible provide +// reasonable `extra` hints for both anticipated extra `flat` byte space, as +// well as anticipated extra nodes required for complex operations. +// +// Example of code creating a ring buffer, adding some data to it, +// and discarding the buffer when done: +// +// void FunWithRings() { +// // Create ring with 3 flats +// CordRep* flat = CreateFlat("Hello"); +// CordRepRing* ring = CordRepRing::Create(flat, 2); +// ring = CordRepRing::Append(ring, CreateFlat(" ")); +// ring = CordRepRing::Append(ring, CreateFlat("world")); +// DoSomethingWithRing(ring); +// CordRep::Unref(ring); +// } +// +// Example of code Copying an existing ring buffer and modifying it: +// +// void MoreFunWithRings(CordRepRing* src) { +// CordRepRing* ring = CordRep::Ref(src)->ring(); +// ring = CordRepRing::Append(ring, CreateFlat("Hello")); +// ring = CordRepRing::Append(ring, CreateFlat(" ")); +// ring = CordRepRing::Append(ring, CreateFlat("world")); +// DoSomethingWithRing(ring); +// CordRep::Unref(ring); +// } +// +class CordRepRing : public CordRep { + public: + // `pos_type` represents a 'logical position'. A CordRepRing instance has a + // `begin_pos` (default 0), and each node inside the buffer will have an + // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus + // this node's length. The purpose is to allow for a binary search on this + // position, while allowing O(1) prepend and append operations. + using pos_type = size_t; + + // `index_type` is the type for the `head`, `tail` and `capacity` indexes. + // Ring buffers are limited to having no more than four billion entries. + using index_type = uint32_t; + + // `offset_type` is the type for the data offset inside a child rep's data. + using offset_type = uint32_t; + + // Position holds the node index and relative offset into the node for + // some physical offset in the contained data as returned by the Find() + // and FindTail() methods. + struct Position { + index_type index; + size_t offset; + }; + + // The maximum # of child nodes that can be hosted inside a CordRepRing. + static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)(); + + // CordRepring can not be default constructed, moved, copied or assigned. + CordRepRing() = delete; + CordRepRing(const CordRepRing&) = delete; + CordRepRing& operator=(const CordRepRing&) = delete; + + // Returns true if this instance is valid, false if some or all of the + // invariants are broken. Intended for debug purposes only. + // `output` receives an explanation of the broken invariants. + bool IsValid(std::ostream& output) const; + + // Returns the size in bytes for a CordRepRing with `capacity' entries. + static constexpr size_t AllocSize(size_t capacity); + + // Returns the distance in bytes from `pos` to `end_pos`. + static constexpr size_t Distance(pos_type pos, pos_type end_pos); + + // Creates a new ring buffer from the provided `rep`. Adopts a reference + // on `rep`. The returned ring buffer has a capacity of at least `extra + 1` + static CordRepRing* Create(CordRep* child, size_t extra = 0); + + // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries. + index_type head() const { return head_; } + index_type tail() const { return tail_; } + index_type capacity() const { return capacity_; } + + // Returns the number of entries in this instance. + index_type entries() const { return entries(head_, tail_); } + + // Returns the logical begin position of this instance. + pos_type begin_pos() const { return begin_pos_; } + + // Returns the number of entries for a given head-tail range. + // Requires `head` and `tail` values to be less than `capacity()`. + index_type entries(index_type head, index_type tail) const { + assert(head < capacity_ && tail < capacity_); + return tail - head + ((tail > head) ? 0 : capacity_); + } + + // Returns the logical end position of entry `index`. + pos_type const& entry_end_pos(index_type index) const { + assert(IsValidIndex(index)); + return Layout::Partial().Pointer<0>(data_)[index]; + } + + // Returns the child pointer of entry `index`. + CordRep* const& entry_child(index_type index) const { + assert(IsValidIndex(index)); + return Layout::Partial(capacity()).Pointer<1>(data_)[index]; + } + + // Returns the data offset of entry `index` + offset_type const& entry_data_offset(index_type index) const { + assert(IsValidIndex(index)); + return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index]; + } + + // Appends the provided child node to the `rep` instance. + // Adopts a reference from `rep` and `child` which may not be null. + // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node + // containing a FLAT or EXTERNAL node, then flat or external the node is added + // 'as is', with an offset added for the SUBSTRING case. + // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or + // CONCAT tree, then all child nodes not excluded by any start offset or + // length values are added recursively. + static CordRepRing* Append(CordRepRing* rep, CordRep* child); + + // Appends the provided string data to the `rep` instance. + // This function will attempt to utilize any remaining capacity in the last + // node of the input if that node is not shared (directly or indirectly), and + // of type FLAT. Remaining data will be added as one or more FLAT nodes. + // Any last node added to the ring buffer will be allocated with up to + // `extra` bytes of capacity for (anticipated) subsequent append actions. + static CordRepRing* Append(CordRepRing* rep, string_view data, + size_t extra = 0); + + // Prepends the provided child node to the `rep` instance. + // Adopts a reference from `rep` and `child` which may not be null. + // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node + // containing a FLAT or EXTERNAL node, then flat or external the node is + // prepended 'as is', with an optional offset added for the SUBSTRING case. + // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING + // or CONCAT tree, then all child nodes not excluded by any start offset or + // length values are added recursively. + static CordRepRing* Prepend(CordRepRing* rep, CordRep* child); + + // Prepends the provided string data to the `rep` instance. + // This function will attempt to utilize any remaining capacity in the first + // node of the input if that node is not shared (directly or indirectly), and + // of type FLAT. Remaining data will be added as one or more FLAT nodes. + // Any first node prepnded to the ring buffer will be allocated with up to + // `extra` bytes of capacity for (anticipated) subsequent prepend actions. + static CordRepRing* Prepend(CordRepRing* rep, string_view data, + size_t extra = 0); + + // Returns a span referencing potentially unused capacity in the last node. + // The returned span may be empty if no such capacity is available, or if the + // current instance is shared. Else, a span of size `n <= size` is returned. + // If non empty, the ring buffer is adjusted to the new length, with the newly + // added capacity left uninitialized. Callers should assign a value to the + // entire span before any other operations on this instance. + Span<char> GetAppendBuffer(size_t size); + + // Returns a span referencing potentially unused capacity in the first node. + // This function is identical to GetAppendBuffer except that it returns a span + // referencing up to `size` capacity directly before the existing data. + Span<char> GetPrependBuffer(size_t size); + // Returns a cord ring buffer containing `len` bytes of data starting at - // `offset`. If the input is not shared, this function will remove all head - // and tail child nodes outside of the requested range, and adjust the new - // head and tail nodes as required. If the input is shared, this function - // returns a new instance sharing some or all of the nodes from the input. + // `offset`. If the input is not shared, this function will remove all head + // and tail child nodes outside of the requested range, and adjust the new + // head and tail nodes as required. If the input is shared, this function + // returns a new instance sharing some or all of the nodes from the input. static CordRepRing* SubRing(CordRepRing* r, size_t offset, size_t len, - size_t extra = 0); - + size_t extra = 0); + // Returns a cord ring buffer with the first `len` bytes removed. - // If the input is not shared, this function will remove all head child nodes - // fully inside the first `length` bytes, and adjust the new head as required. - // If the input is shared, this function returns a new instance sharing some - // or all of the nodes from the input. + // If the input is not shared, this function will remove all head child nodes + // fully inside the first `length` bytes, and adjust the new head as required. + // If the input is shared, this function returns a new instance sharing some + // or all of the nodes from the input. static CordRepRing* RemoveSuffix(CordRepRing* r, size_t len, - size_t extra = 0); - + size_t extra = 0); + // Returns a cord ring buffer with the last `len` bytes removed. - // If the input is not shared, this function will remove all head child nodes - // fully inside the first `length` bytes, and adjust the new head as required. - // If the input is shared, this function returns a new instance sharing some - // or all of the nodes from the input. - static CordRepRing* RemovePrefix(CordRepRing* r, size_t len, - size_t extra = 0); - - // Returns the character at `offset`. Requires that `offset < length`. - char GetCharacter(size_t offset) const; - + // If the input is not shared, this function will remove all head child nodes + // fully inside the first `length` bytes, and adjust the new head as required. + // If the input is shared, this function returns a new instance sharing some + // or all of the nodes from the input. + static CordRepRing* RemovePrefix(CordRepRing* r, size_t len, + size_t extra = 0); + + // Returns the character at `offset`. Requires that `offset < length`. + char GetCharacter(size_t offset) const; + // Returns true if this instance manages a single contiguous buffer, in which // case the (optional) output parameter `fragment` is set. Otherwise, the // function returns false, and `fragment` is left unchanged. @@ -240,345 +240,345 @@ class CordRepRing : public CordRep { // returns false, and `fragment` is left unchanged. bool IsFlat(size_t offset, size_t len, y_absl::string_view* fragment) const; - // Testing only: set capacity to requested capacity. - void SetCapacityForTesting(size_t capacity); - - // Returns the CordRep data pointer for the provided CordRep. - // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep. - static const char* GetLeafData(const CordRep* rep); - - // Returns the CordRep data pointer for the provided CordRep. - // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep. - static const char* GetRepData(const CordRep* rep); - - // Advances the provided position, wrapping around capacity as needed. - // Requires `index` < capacity() - inline index_type advance(index_type index) const; - - // Advances the provided position by 'n`, wrapping around capacity as needed. - // Requires `index` < capacity() and `n` <= capacity. - inline index_type advance(index_type index, index_type n) const; - - // Retreats the provided position, wrapping around 0 as needed. - // Requires `index` < capacity() - inline index_type retreat(index_type index) const; - - // Retreats the provided position by 'n', wrapping around 0 as needed. - // Requires `index` < capacity() - inline index_type retreat(index_type index, index_type n) const; - - // Returns the logical begin position of entry `index` - pos_type const& entry_begin_pos(index_type index) const { - return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index)); - } - - // Returns the physical start offset of entry `index` - size_t entry_start_offset(index_type index) const { - return Distance(begin_pos_, entry_begin_pos(index)); - } - - // Returns the physical end offset of entry `index` - size_t entry_end_offset(index_type index) const { - return Distance(begin_pos_, entry_end_pos(index)); - } - - // Returns the data length for entry `index` - size_t entry_length(index_type index) const { - return Distance(entry_begin_pos(index), entry_end_pos(index)); - } - - // Returns the data for entry `index` - y_absl::string_view entry_data(index_type index) const; - - // Returns the position for `offset` as {index, prefix}. `index` holds the - // index of the entry at the specified offset and `prefix` holds the relative - // offset inside that entry. - // Requires `offset` < length. - // - // For example we can implement GetCharacter(offset) as: - // char GetCharacter(size_t offset) { - // Position pos = this->Find(offset); - // return this->entry_data(pos.pos)[pos.offset]; - // } - inline Position Find(size_t offset) const; - - // Find starting at `head` - inline Position Find(index_type head, size_t offset) const; - - // Returns the tail position for `offset` as {tail index, suffix}. - // `tail index` holds holds the index of the entry holding the offset directly - // before 'offset` advanced by one. 'suffix` holds the relative offset from - // that relative offset in the entry to the end of the entry. - // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5) - // will return {retreat(tail), 5)} provided the preceding entry contains at - // least 5 bytes of data. - // Requires offset >= 1 && offset <= length. - // - // This function is very useful in functions that need to clip the end of some - // ring buffer such as 'RemovePrefix'. - // For example, we could implement RemovePrefix for non shared instances as: - // void RemoveSuffix(size_t n) { - // Position pos = FindTail(length - n); - // UnrefEntries(pos.pos, this->tail_); - // this->tail_ = pos.pos; - // entry(retreat(pos.pos)).end_pos -= pos.offset; - // } - inline Position FindTail(size_t offset) const; - - // Find tail starting at `head` - inline Position FindTail(index_type head, size_t offset) const; - - // Invokes f(index_type index) for each entry inside the range [head, tail> - template <typename F> - void ForEach(index_type head, index_type tail, F&& f) const { - index_type n1 = (tail > head) ? tail : capacity_; - for (index_type i = head; i < n1; ++i) f(i); - if (tail <= head) { - for (index_type i = 0; i < tail; ++i) f(i); - } - } - - // Invokes f(index_type index) for each entry inside this instance. - template <typename F> - void ForEach(F&& f) const { - ForEach(head_, tail_, std::forward<F>(f)); - } - - // Dump this instance's data tp stream `s` in human readable format, excluding - // the actual data content itself. Intended for debug purposes only. - friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep); - - private: - enum class AddMode { kAppend, kPrepend }; - - using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>; - - class Filler; - class Transaction; - class CreateTransaction; - - static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment(); - - // Creates a new CordRepRing. - explicit CordRepRing(index_type capacity) : capacity_(capacity) {} - - // Returns true if `index` is a valid index into this instance. - bool IsValidIndex(index_type index) const; - - // Debug use only: validates the provided CordRepRing invariants. - // Verification of all CordRepRing methods can be enabled by defining - // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION` - // Verification is VERY expensive, so only do it for debugging purposes. - static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr, - int line = 0); - - // Allocates a CordRepRing large enough to hold `capacity + extra' entries. - // The returned capacity may be larger if the allocated memory allows for it. - // The maximum capacity of a CordRepRing is capped at kMaxCapacity. - // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity. - static CordRepRing* New(size_t capacity, size_t extra); - - // Deallocates (but does not destroy) the provided ring buffer. - static void Delete(CordRepRing* rep); - - // Destroys the provided ring buffer, decrementing the reference count of all - // contained child CordReps. The provided 1\`rep` should have a ref count of + // Testing only: set capacity to requested capacity. + void SetCapacityForTesting(size_t capacity); + + // Returns the CordRep data pointer for the provided CordRep. + // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep. + static const char* GetLeafData(const CordRep* rep); + + // Returns the CordRep data pointer for the provided CordRep. + // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep. + static const char* GetRepData(const CordRep* rep); + + // Advances the provided position, wrapping around capacity as needed. + // Requires `index` < capacity() + inline index_type advance(index_type index) const; + + // Advances the provided position by 'n`, wrapping around capacity as needed. + // Requires `index` < capacity() and `n` <= capacity. + inline index_type advance(index_type index, index_type n) const; + + // Retreats the provided position, wrapping around 0 as needed. + // Requires `index` < capacity() + inline index_type retreat(index_type index) const; + + // Retreats the provided position by 'n', wrapping around 0 as needed. + // Requires `index` < capacity() + inline index_type retreat(index_type index, index_type n) const; + + // Returns the logical begin position of entry `index` + pos_type const& entry_begin_pos(index_type index) const { + return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index)); + } + + // Returns the physical start offset of entry `index` + size_t entry_start_offset(index_type index) const { + return Distance(begin_pos_, entry_begin_pos(index)); + } + + // Returns the physical end offset of entry `index` + size_t entry_end_offset(index_type index) const { + return Distance(begin_pos_, entry_end_pos(index)); + } + + // Returns the data length for entry `index` + size_t entry_length(index_type index) const { + return Distance(entry_begin_pos(index), entry_end_pos(index)); + } + + // Returns the data for entry `index` + y_absl::string_view entry_data(index_type index) const; + + // Returns the position for `offset` as {index, prefix}. `index` holds the + // index of the entry at the specified offset and `prefix` holds the relative + // offset inside that entry. + // Requires `offset` < length. + // + // For example we can implement GetCharacter(offset) as: + // char GetCharacter(size_t offset) { + // Position pos = this->Find(offset); + // return this->entry_data(pos.pos)[pos.offset]; + // } + inline Position Find(size_t offset) const; + + // Find starting at `head` + inline Position Find(index_type head, size_t offset) const; + + // Returns the tail position for `offset` as {tail index, suffix}. + // `tail index` holds holds the index of the entry holding the offset directly + // before 'offset` advanced by one. 'suffix` holds the relative offset from + // that relative offset in the entry to the end of the entry. + // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5) + // will return {retreat(tail), 5)} provided the preceding entry contains at + // least 5 bytes of data. + // Requires offset >= 1 && offset <= length. + // + // This function is very useful in functions that need to clip the end of some + // ring buffer such as 'RemovePrefix'. + // For example, we could implement RemovePrefix for non shared instances as: + // void RemoveSuffix(size_t n) { + // Position pos = FindTail(length - n); + // UnrefEntries(pos.pos, this->tail_); + // this->tail_ = pos.pos; + // entry(retreat(pos.pos)).end_pos -= pos.offset; + // } + inline Position FindTail(size_t offset) const; + + // Find tail starting at `head` + inline Position FindTail(index_type head, size_t offset) const; + + // Invokes f(index_type index) for each entry inside the range [head, tail> + template <typename F> + void ForEach(index_type head, index_type tail, F&& f) const { + index_type n1 = (tail > head) ? tail : capacity_; + for (index_type i = head; i < n1; ++i) f(i); + if (tail <= head) { + for (index_type i = 0; i < tail; ++i) f(i); + } + } + + // Invokes f(index_type index) for each entry inside this instance. + template <typename F> + void ForEach(F&& f) const { + ForEach(head_, tail_, std::forward<F>(f)); + } + + // Dump this instance's data tp stream `s` in human readable format, excluding + // the actual data content itself. Intended for debug purposes only. + friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep); + + private: + enum class AddMode { kAppend, kPrepend }; + + using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>; + + class Filler; + class Transaction; + class CreateTransaction; + + static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment(); + + // Creates a new CordRepRing. + explicit CordRepRing(index_type capacity) : capacity_(capacity) {} + + // Returns true if `index` is a valid index into this instance. + bool IsValidIndex(index_type index) const; + + // Debug use only: validates the provided CordRepRing invariants. + // Verification of all CordRepRing methods can be enabled by defining + // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION` + // Verification is VERY expensive, so only do it for debugging purposes. + static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr, + int line = 0); + + // Allocates a CordRepRing large enough to hold `capacity + extra' entries. + // The returned capacity may be larger if the allocated memory allows for it. + // The maximum capacity of a CordRepRing is capped at kMaxCapacity. + // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity. + static CordRepRing* New(size_t capacity, size_t extra); + + // Deallocates (but does not destroy) the provided ring buffer. + static void Delete(CordRepRing* rep); + + // Destroys the provided ring buffer, decrementing the reference count of all + // contained child CordReps. The provided 1\`rep` should have a ref count of // one (pre decrement destroy call observing `refcount.IsOne()`) or zero // (post decrement destroy call observing `!refcount.Decrement()`). - static void Destroy(CordRepRing* rep); - - // Returns a mutable reference to the logical end position array. - pos_type* entry_end_pos() { - return Layout::Partial().Pointer<0>(data_); - } - - // Returns a mutable reference to the child pointer array. - CordRep** entry_child() { - return Layout::Partial(capacity()).Pointer<1>(data_); - } - - // Returns a mutable reference to the data offset array. - offset_type* entry_data_offset() { - return Layout::Partial(capacity(), capacity()).Pointer<2>(data_); - } - - // Find implementations for the non fast path 0 / length cases. - Position FindSlow(index_type head, size_t offset) const; - Position FindTailSlow(index_type head, size_t offset) const; - - // Finds the index of the first node that is inside a reasonable distance - // of the node at `offset` from which we can continue with a linear search. - template <bool wrap> - index_type FindBinary(index_type head, index_type tail, size_t offset) const; - - // Fills the current (initialized) instance from the provided source, copying - // entries [head, tail). Adds a reference to copied entries if `ref` is true. - template <bool ref> - void Fill(const CordRepRing* src, index_type head, index_type tail); - - // Create a copy of 'rep', copying all entries [head, tail), allocating room - // for `extra` entries. Adds a reference on all copied entries. - static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail, - size_t extra = 0); - - // Returns a Mutable CordRepRing reference from `rep` with room for at least - // `extra` additional nodes. Adopts a reference count from `rep`. - // This function will return `rep` if, and only if: - // - rep.entries + extra <= rep.capacity - // - rep.refcount == 1 - // Otherwise, this function will create a new copy of `rep` with additional - // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance. - // - // If a new CordRepRing can not be allocated, or the new capacity would exceed - // the maxmimum capacity, then the input is consumed only, and an exception is - // thrown. - static CordRepRing* Mutable(CordRepRing* rep, size_t extra); - - // Slow path for Append(CordRepRing* rep, CordRep* child). This function is - // exercised if the provided `child` in Append() is not a leaf node, i.e., a - // ring buffer or old (concat) cord tree. - static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child); - - // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL. - static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child, - size_t offset, size_t length); - - // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL. - static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child, - size_t offset, size_t length); - - // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is - // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a - // ring buffer or old (concat) cord tree. - static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child); - - // Slow path for Create(CordRep* child, size_t extra). This function is - // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a - // ring buffer or old (concat) cord tree. - static CordRepRing* CreateSlow(CordRep* child, size_t extra); - - // Creates a new ring buffer from the provided `child` leaf node. Requires - // `child` to be FLAT or EXTERNAL. on `rep`. - // The returned ring buffer has a capacity of at least `1 + extra` - static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset, - size_t length, size_t extra); - - // Appends or prepends (depending on AddMode) the ring buffer in `ring' to + static void Destroy(CordRepRing* rep); + + // Returns a mutable reference to the logical end position array. + pos_type* entry_end_pos() { + return Layout::Partial().Pointer<0>(data_); + } + + // Returns a mutable reference to the child pointer array. + CordRep** entry_child() { + return Layout::Partial(capacity()).Pointer<1>(data_); + } + + // Returns a mutable reference to the data offset array. + offset_type* entry_data_offset() { + return Layout::Partial(capacity(), capacity()).Pointer<2>(data_); + } + + // Find implementations for the non fast path 0 / length cases. + Position FindSlow(index_type head, size_t offset) const; + Position FindTailSlow(index_type head, size_t offset) const; + + // Finds the index of the first node that is inside a reasonable distance + // of the node at `offset` from which we can continue with a linear search. + template <bool wrap> + index_type FindBinary(index_type head, index_type tail, size_t offset) const; + + // Fills the current (initialized) instance from the provided source, copying + // entries [head, tail). Adds a reference to copied entries if `ref` is true. + template <bool ref> + void Fill(const CordRepRing* src, index_type head, index_type tail); + + // Create a copy of 'rep', copying all entries [head, tail), allocating room + // for `extra` entries. Adds a reference on all copied entries. + static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail, + size_t extra = 0); + + // Returns a Mutable CordRepRing reference from `rep` with room for at least + // `extra` additional nodes. Adopts a reference count from `rep`. + // This function will return `rep` if, and only if: + // - rep.entries + extra <= rep.capacity + // - rep.refcount == 1 + // Otherwise, this function will create a new copy of `rep` with additional + // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance. + // + // If a new CordRepRing can not be allocated, or the new capacity would exceed + // the maxmimum capacity, then the input is consumed only, and an exception is + // thrown. + static CordRepRing* Mutable(CordRepRing* rep, size_t extra); + + // Slow path for Append(CordRepRing* rep, CordRep* child). This function is + // exercised if the provided `child` in Append() is not a leaf node, i.e., a + // ring buffer or old (concat) cord tree. + static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child); + + // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL. + static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child, + size_t offset, size_t length); + + // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL. + static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child, + size_t offset, size_t length); + + // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is + // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a + // ring buffer or old (concat) cord tree. + static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child); + + // Slow path for Create(CordRep* child, size_t extra). This function is + // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a + // ring buffer or old (concat) cord tree. + static CordRepRing* CreateSlow(CordRep* child, size_t extra); + + // Creates a new ring buffer from the provided `child` leaf node. Requires + // `child` to be FLAT or EXTERNAL. on `rep`. + // The returned ring buffer has a capacity of at least `1 + extra` + static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset, + size_t length, size_t extra); + + // Appends or prepends (depending on AddMode) the ring buffer in `ring' to // `rep` starting at `offset` with length `len`. - template <AddMode mode> - static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring, + template <AddMode mode> + static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring, size_t offset, size_t len); - - // Increases the data offset for entry `index` by `n`. - void AddDataOffset(index_type index, size_t n); - - // Descreases the length for entry `index` by `n`. - void SubLength(index_type index, size_t n); - - index_type head_; - index_type tail_; - index_type capacity_; - pos_type begin_pos_; - - alignas(kLayoutAlignment) char data_[kLayoutAlignment]; - - friend struct CordRep; -}; - -constexpr size_t CordRepRing::AllocSize(size_t capacity) { - return sizeof(CordRepRing) - sizeof(data_) + - Layout(capacity, capacity, capacity).AllocSize(); -} - -inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) { - return (end_pos - pos); -} - -inline const char* CordRepRing::GetLeafData(const CordRep* rep) { - return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base; -} - -inline const char* CordRepRing::GetRepData(const CordRep* rep) { - if (rep->tag >= FLAT) return rep->flat()->Data(); - if (rep->tag == EXTERNAL) return rep->external()->base; - return GetLeafData(rep->substring()->child) + rep->substring()->start; -} - -inline CordRepRing::index_type CordRepRing::advance(index_type index) const { - assert(index < capacity_); - return ++index == capacity_ ? 0 : index; -} - -inline CordRepRing::index_type CordRepRing::advance(index_type index, - index_type n) const { - assert(index < capacity_ && n <= capacity_); - return (index += n) >= capacity_ ? index - capacity_ : index; -} - -inline CordRepRing::index_type CordRepRing::retreat(index_type index) const { - assert(index < capacity_); - return (index > 0 ? index : capacity_) - 1; -} - -inline CordRepRing::index_type CordRepRing::retreat(index_type index, - index_type n) const { - assert(index < capacity_ && n <= capacity_); - return index >= n ? index - n : capacity_ - n + index; -} - -inline y_absl::string_view CordRepRing::entry_data(index_type index) const { - size_t data_offset = entry_data_offset(index); - return {GetRepData(entry_child(index)) + data_offset, entry_length(index)}; -} - -inline bool CordRepRing::IsValidIndex(index_type index) const { - if (index >= capacity_) return false; - return (tail_ > head_) ? (index >= head_ && index < tail_) - : (index >= head_ || index < tail_); -} - -#ifndef EXTRA_CORD_RING_VALIDATION -inline CordRepRing* CordRepRing::Validate(CordRepRing* rep, - const char* /*file*/, int /*line*/) { - return rep; -} -#endif - -inline CordRepRing::Position CordRepRing::Find(size_t offset) const { - assert(offset < length); - return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset); -} - -inline CordRepRing::Position CordRepRing::Find(index_type head, - size_t offset) const { - assert(offset < length); - assert(IsValidIndex(head) && offset >= entry_start_offset(head)); - return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset); -} - -inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const { - assert(offset > 0 && offset <= length); - return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset); -} - -inline CordRepRing::Position CordRepRing::FindTail(index_type head, - size_t offset) const { - assert(offset > 0 && offset <= length); - assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1); - return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset); -} - -// Now that CordRepRing is defined, we can define CordRep's helper casts: -inline CordRepRing* CordRep::ring() { + + // Increases the data offset for entry `index` by `n`. + void AddDataOffset(index_type index, size_t n); + + // Descreases the length for entry `index` by `n`. + void SubLength(index_type index, size_t n); + + index_type head_; + index_type tail_; + index_type capacity_; + pos_type begin_pos_; + + alignas(kLayoutAlignment) char data_[kLayoutAlignment]; + + friend struct CordRep; +}; + +constexpr size_t CordRepRing::AllocSize(size_t capacity) { + return sizeof(CordRepRing) - sizeof(data_) + + Layout(capacity, capacity, capacity).AllocSize(); +} + +inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) { + return (end_pos - pos); +} + +inline const char* CordRepRing::GetLeafData(const CordRep* rep) { + return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base; +} + +inline const char* CordRepRing::GetRepData(const CordRep* rep) { + if (rep->tag >= FLAT) return rep->flat()->Data(); + if (rep->tag == EXTERNAL) return rep->external()->base; + return GetLeafData(rep->substring()->child) + rep->substring()->start; +} + +inline CordRepRing::index_type CordRepRing::advance(index_type index) const { + assert(index < capacity_); + return ++index == capacity_ ? 0 : index; +} + +inline CordRepRing::index_type CordRepRing::advance(index_type index, + index_type n) const { + assert(index < capacity_ && n <= capacity_); + return (index += n) >= capacity_ ? index - capacity_ : index; +} + +inline CordRepRing::index_type CordRepRing::retreat(index_type index) const { + assert(index < capacity_); + return (index > 0 ? index : capacity_) - 1; +} + +inline CordRepRing::index_type CordRepRing::retreat(index_type index, + index_type n) const { + assert(index < capacity_ && n <= capacity_); + return index >= n ? index - n : capacity_ - n + index; +} + +inline y_absl::string_view CordRepRing::entry_data(index_type index) const { + size_t data_offset = entry_data_offset(index); + return {GetRepData(entry_child(index)) + data_offset, entry_length(index)}; +} + +inline bool CordRepRing::IsValidIndex(index_type index) const { + if (index >= capacity_) return false; + return (tail_ > head_) ? (index >= head_ && index < tail_) + : (index >= head_ || index < tail_); +} + +#ifndef EXTRA_CORD_RING_VALIDATION +inline CordRepRing* CordRepRing::Validate(CordRepRing* rep, + const char* /*file*/, int /*line*/) { + return rep; +} +#endif + +inline CordRepRing::Position CordRepRing::Find(size_t offset) const { + assert(offset < length); + return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset); +} + +inline CordRepRing::Position CordRepRing::Find(index_type head, + size_t offset) const { + assert(offset < length); + assert(IsValidIndex(head) && offset >= entry_start_offset(head)); + return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset); +} + +inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const { + assert(offset > 0 && offset <= length); + return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset); +} + +inline CordRepRing::Position CordRepRing::FindTail(index_type head, + size_t offset) const { + assert(offset > 0 && offset <= length); + assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1); + return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset); +} + +// Now that CordRepRing is defined, we can define CordRep's helper casts: +inline CordRepRing* CordRep::ring() { assert(IsRing()); - return static_cast<CordRepRing*>(this); -} - -inline const CordRepRing* CordRep::ring() const { + return static_cast<CordRepRing*>(this); +} + +inline const CordRepRing* CordRep::ring() const { assert(IsRing()); - return static_cast<const CordRepRing*>(this); -} - + return static_cast<const CordRepRing*>(this); +} + inline bool CordRepRing::IsFlat(y_absl::string_view* fragment) const { if (entries() == 1) { if (fragment) *fragment = entry_data(head()); @@ -598,10 +598,10 @@ inline bool CordRepRing::IsFlat(size_t offset, size_t len, return false; } -std::ostream& operator<<(std::ostream& s, const CordRepRing& rep); - -} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ +std::ostream& operator<<(std::ostream& s, const CordRepRing& rep); + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace y_absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h index 3f64d04fae..98ea8c170a 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h @@ -1,118 +1,118 @@ -// Copyright 2021 The Abseil Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ -#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ - -#include <cassert> -#include <cstddef> -#include <cstdint> - -#include "y_absl/strings/internal/cord_internal.h" -#include "y_absl/strings/internal/cord_rep_ring.h" -#include "y_absl/strings/string_view.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - -// CordRepRingReader provides basic navigation over CordRepRing data. -class CordRepRingReader { - public: - // Returns true if this instance is not empty. - explicit operator bool() const { return ring_ != nullptr; } - - // Returns the ring buffer reference for this instance, or nullptr if empty. - CordRepRing* ring() const { return ring_; } - - // Returns the current node index inside the ring buffer for this instance. - // The returned value is undefined if this instance is empty. - CordRepRing::index_type index() const { return index_; } - +// Copyright 2021 The Abseil Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ +#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ + +#include <cassert> +#include <cstddef> +#include <cstdint> + +#include "y_absl/strings/internal/cord_internal.h" +#include "y_absl/strings/internal/cord_rep_ring.h" +#include "y_absl/strings/string_view.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + +// CordRepRingReader provides basic navigation over CordRepRing data. +class CordRepRingReader { + public: + // Returns true if this instance is not empty. + explicit operator bool() const { return ring_ != nullptr; } + + // Returns the ring buffer reference for this instance, or nullptr if empty. + CordRepRing* ring() const { return ring_; } + + // Returns the current node index inside the ring buffer for this instance. + // The returned value is undefined if this instance is empty. + CordRepRing::index_type index() const { return index_; } + // Returns the current node inside the ring buffer for this instance. // The returned value is undefined if this instance is empty. CordRep* node() const { return ring_->entry_child(index_); } - // Returns the length of the referenced ring buffer. - // Requires the current instance to be non empty. - size_t length() const { - assert(ring_); - return ring_->length; - } - - // Returns the end offset of the last navigated-to chunk, which represents the - // total bytes 'consumed' relative to the start of the ring. The returned - // value is never zero. For example, initializing a reader with a ring buffer - // with a first chunk of 19 bytes will return consumed() = 19. - // Requires the current instance to be non empty. - size_t consumed() const { - assert(ring_); - return ring_->entry_end_offset(index_); - } - - // Returns the number of bytes remaining beyond the last navigated-to chunk. - // Requires the current instance to be non empty. - size_t remaining() const { - assert(ring_); - return length() - consumed(); - } - - // Resets this instance to an empty value - void Reset() { ring_ = nullptr; } - - // Resets this instance to the start of `ring`. `ring` must not be null. - // Returns a reference into the first chunk of the provided ring. - y_absl::string_view Reset(CordRepRing* ring) { - assert(ring); - ring_ = ring; - index_ = ring_->head(); - return ring_->entry_data(index_); - } - - // Navigates to the next chunk inside the reference ring buffer. - // Returns a reference into the navigated-to chunk. - // Requires remaining() to be non zero. - y_absl::string_view Next() { - assert(remaining()); - index_ = ring_->advance(index_); - return ring_->entry_data(index_); - } - - // Navigates to the chunk at offset `offset`. - // Returns a reference into the navigated-to chunk, adjusted for the relative - // position of `offset` into that chunk. For example, calling Seek(13) on a - // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return - // a string view into the second chunk starting at offset 3 with a size of 17. - // Requires `offset` to be less than `length()` - y_absl::string_view Seek(size_t offset) { - assert(offset < length()); - size_t current = ring_->entry_end_offset(index_); - CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head(); - const CordRepRing::Position head = ring_->Find(hint, offset); - index_ = head.index; - auto data = ring_->entry_data(head.index); - data.remove_prefix(head.offset); - return data; - } - - private: - CordRepRing* ring_ = nullptr; - CordRepRing::index_type index_; -}; - -} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ + // Returns the length of the referenced ring buffer. + // Requires the current instance to be non empty. + size_t length() const { + assert(ring_); + return ring_->length; + } + + // Returns the end offset of the last navigated-to chunk, which represents the + // total bytes 'consumed' relative to the start of the ring. The returned + // value is never zero. For example, initializing a reader with a ring buffer + // with a first chunk of 19 bytes will return consumed() = 19. + // Requires the current instance to be non empty. + size_t consumed() const { + assert(ring_); + return ring_->entry_end_offset(index_); + } + + // Returns the number of bytes remaining beyond the last navigated-to chunk. + // Requires the current instance to be non empty. + size_t remaining() const { + assert(ring_); + return length() - consumed(); + } + + // Resets this instance to an empty value + void Reset() { ring_ = nullptr; } + + // Resets this instance to the start of `ring`. `ring` must not be null. + // Returns a reference into the first chunk of the provided ring. + y_absl::string_view Reset(CordRepRing* ring) { + assert(ring); + ring_ = ring; + index_ = ring_->head(); + return ring_->entry_data(index_); + } + + // Navigates to the next chunk inside the reference ring buffer. + // Returns a reference into the navigated-to chunk. + // Requires remaining() to be non zero. + y_absl::string_view Next() { + assert(remaining()); + index_ = ring_->advance(index_); + return ring_->entry_data(index_); + } + + // Navigates to the chunk at offset `offset`. + // Returns a reference into the navigated-to chunk, adjusted for the relative + // position of `offset` into that chunk. For example, calling Seek(13) on a + // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return + // a string view into the second chunk starting at offset 3 with a size of 17. + // Requires `offset` to be less than `length()` + y_absl::string_view Seek(size_t offset) { + assert(offset < length()); + size_t current = ring_->entry_end_offset(index_); + CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head(); + const CordRepRing::Position head = ring_->Find(hint, offset); + index_ = head.index; + auto data = ring_->entry_data(head.index); + data.remove_prefix(head.offset); + return data; + } + + private: + CordRepRing* ring_ = nullptr; + CordRepRing::index_type index_; +}; + +} // namespace cord_internal +ABSL_NAMESPACE_END +} // namespace y_absl + +#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make index 06e99346da..d2522532e2 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make @@ -2,13 +2,13 @@ LIBRARY() -WITHOUT_LICENSE_TEXTS() - -OWNER( - somov - g:cpp-contrib -) +WITHOUT_LICENSE_TEXTS() +OWNER( + somov + g:cpp-contrib +) + LICENSE(Apache-2.0) PEERDIR( diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make index e181217139..0220a75bd1 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make @@ -1,47 +1,47 @@ -# Generated by devtools/yamaker. - -LIBRARY() - -WITHOUT_LICENSE_TEXTS() - -OWNER( - somov - g:cpp-contrib -) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp-tstring/y_absl/base +# Generated by devtools/yamaker. + +LIBRARY() + +WITHOUT_LICENSE_TEXTS() + +OWNER( + somov + g:cpp-contrib +) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/low_level_alloc - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity contrib/restricted/abseil-cpp-tstring/y_absl/debugging contrib/restricted/abseil-cpp-tstring/y_absl/debugging/stacktrace contrib/restricted/abseil-cpp-tstring/y_absl/debugging/symbolize contrib/restricted/abseil-cpp-tstring/y_absl/demangle - contrib/restricted/abseil-cpp-tstring/y_absl/numeric - contrib/restricted/abseil-cpp-tstring/y_absl/strings + contrib/restricted/abseil-cpp-tstring/y_absl/numeric + contrib/restricted/abseil-cpp-tstring/y_absl/strings contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal contrib/restricted/abseil-cpp-tstring/y_absl/synchronization contrib/restricted/abseil-cpp-tstring/y_absl/synchronization/internal contrib/restricted/abseil-cpp-tstring/y_absl/time contrib/restricted/abseil-cpp-tstring/y_absl/time/civil_time contrib/restricted/abseil-cpp-tstring/y_absl/time/time_zone -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp-tstring -) - -NO_COMPILER_WARNINGS() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp-tstring +) + +NO_COMPILER_WARNINGS() + SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal) - -SRCS( + +SRCS( cordz_handle.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make index 930eaa8b05..4d749dc50b 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make @@ -1,30 +1,30 @@ -# Generated by devtools/yamaker. - -LIBRARY() - -WITHOUT_LICENSE_TEXTS() - -OWNER( - somov - g:cpp-contrib -) - -LICENSE(Apache-2.0) - -PEERDIR( - contrib/restricted/abseil-cpp-tstring/y_absl/base +# Generated by devtools/yamaker. + +LIBRARY() + +WITHOUT_LICENSE_TEXTS() + +OWNER( + somov + g:cpp-contrib +) + +LICENSE(Apache-2.0) + +PEERDIR( + contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/low_level_alloc - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait + contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate + contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity contrib/restricted/abseil-cpp-tstring/y_absl/debugging contrib/restricted/abseil-cpp-tstring/y_absl/debugging/stacktrace contrib/restricted/abseil-cpp-tstring/y_absl/debugging/symbolize contrib/restricted/abseil-cpp-tstring/y_absl/demangle - contrib/restricted/abseil-cpp-tstring/y_absl/numeric + contrib/restricted/abseil-cpp-tstring/y_absl/numeric contrib/restricted/abseil-cpp-tstring/y_absl/profiling/internal/exponential_biased - contrib/restricted/abseil-cpp-tstring/y_absl/strings + contrib/restricted/abseil-cpp-tstring/y_absl/strings contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions @@ -34,18 +34,18 @@ PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/time contrib/restricted/abseil-cpp-tstring/y_absl/time/civil_time contrib/restricted/abseil-cpp-tstring/y_absl/time/time_zone -) - -ADDINCL( - GLOBAL contrib/restricted/abseil-cpp-tstring -) - -NO_COMPILER_WARNINGS() - +) + +ADDINCL( + GLOBAL contrib/restricted/abseil-cpp-tstring +) + +NO_COMPILER_WARNINGS() + SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal) - -SRCS( + +SRCS( cordz_info.cc -) - -END() +) + +END() diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h index 12aec3ac11..022633ac82 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h @@ -170,7 +170,7 @@ inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { {"0x1234", true, 16, 0x1234}, - // Base-10 string version. + // Base-10 string version. {"1234", true, 0, 1234}, {nullptr, false, 0, 0}, }}; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt index 33d60b3d2b..95cff783b8 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt @@ -1,20 +1,20 @@ -====================Apache-2.0==================== -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -====================COPYRIGHT==================== -// Copyright 2017 The Abseil Authors. - - -====================COPYRIGHT==================== -// Copyright 2020 The Abseil Authors. +====================Apache-2.0==================== +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +====================COPYRIGHT==================== +// Copyright 2017 The Abseil Authors. + + +====================COPYRIGHT==================== +// Copyright 2020 The Abseil Authors. diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc index 8d5c3b61ac..dbd80e7052 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc @@ -1,18 +1,18 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. // +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// // POSIX spec: // http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html // @@ -26,7 +26,7 @@ #include "y_absl/base/port.h" #include "y_absl/strings/internal/str_format/float_conversion.h" -#include "y_absl/strings/numbers.h" +#include "y_absl/strings/numbers.h" namespace y_absl { ABSL_NAMESPACE_BEGIN @@ -61,179 +61,179 @@ struct IsSigned<y_absl::int128> : std::true_type {}; template <> struct IsSigned<y_absl::uint128> : std::false_type {}; -// Integral digit printer. -// Call one of the PrintAs* routines after construction once. -// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results. -class IntDigits { +// Integral digit printer. +// Call one of the PrintAs* routines after construction once. +// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results. +class IntDigits { public: - // Print the unsigned integer as octal. - // Supports unsigned integral types and uint128. + // Print the unsigned integer as octal. + // Supports unsigned integral types and uint128. template <typename T> - void PrintAsOct(T v) { - static_assert(!IsSigned<T>::value, ""); - char *p = storage_ + sizeof(storage_); - do { - *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7)); - v >>= 3; - } while (v); - start_ = p; - size_ = storage_ + sizeof(storage_) - p; - } - - // Print the signed or unsigned integer as decimal. - // Supports all integral types. - template <typename T> - void PrintAsDec(T v) { - static_assert(std::is_integral<T>::value, ""); - start_ = storage_; - size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_; - } - - void PrintAsDec(int128 v) { - auto u = static_cast<uint128>(v); - bool add_neg = false; - if (v < 0) { - add_neg = true; - u = uint128{} - u; + void PrintAsOct(T v) { + static_assert(!IsSigned<T>::value, ""); + char *p = storage_ + sizeof(storage_); + do { + *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7)); + v >>= 3; + } while (v); + start_ = p; + size_ = storage_ + sizeof(storage_) - p; + } + + // Print the signed or unsigned integer as decimal. + // Supports all integral types. + template <typename T> + void PrintAsDec(T v) { + static_assert(std::is_integral<T>::value, ""); + start_ = storage_; + size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_; + } + + void PrintAsDec(int128 v) { + auto u = static_cast<uint128>(v); + bool add_neg = false; + if (v < 0) { + add_neg = true; + u = uint128{} - u; } - PrintAsDec(u, add_neg); + PrintAsDec(u, add_neg); } - void PrintAsDec(uint128 v, bool add_neg = false) { - // This function can be sped up if needed. We can call FastIntToBuffer - // twice, or fix FastIntToBuffer to support uint128. - char *p = storage_ + sizeof(storage_); - do { - p -= 2; - numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p); - v /= 100; - } while (v); - if (p[0] == '0') { - // We printed one too many hexits. - ++p; - } - if (add_neg) { - *--p = '-'; - } - size_ = storage_ + sizeof(storage_) - p; - start_ = p; + void PrintAsDec(uint128 v, bool add_neg = false) { + // This function can be sped up if needed. We can call FastIntToBuffer + // twice, or fix FastIntToBuffer to support uint128. + char *p = storage_ + sizeof(storage_); + do { + p -= 2; + numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p); + v /= 100; + } while (v); + if (p[0] == '0') { + // We printed one too many hexits. + ++p; + } + if (add_neg) { + *--p = '-'; + } + size_ = storage_ + sizeof(storage_) - p; + start_ = p; } - // Print the unsigned integer as hex using lowercase. - // Supports unsigned integral types and uint128. + // Print the unsigned integer as hex using lowercase. + // Supports unsigned integral types and uint128. template <typename T> - void PrintAsHexLower(T v) { - static_assert(!IsSigned<T>::value, ""); - char *p = storage_ + sizeof(storage_); - - do { - p -= 2; - constexpr const char* table = numbers_internal::kHexTable; - std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2); - if (sizeof(T) == 1) break; - v >>= 8; - } while (v); - if (p[0] == '0') { - // We printed one too many digits. - ++p; + void PrintAsHexLower(T v) { + static_assert(!IsSigned<T>::value, ""); + char *p = storage_ + sizeof(storage_); + + do { + p -= 2; + constexpr const char* table = numbers_internal::kHexTable; + std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2); + if (sizeof(T) == 1) break; + v >>= 8; + } while (v); + if (p[0] == '0') { + // We printed one too many digits. + ++p; } - start_ = p; - size_ = storage_ + sizeof(storage_) - p; - } + start_ = p; + size_ = storage_ + sizeof(storage_) - p; + } - // Print the unsigned integer as hex using uppercase. - // Supports unsigned integral types and uint128. + // Print the unsigned integer as hex using uppercase. + // Supports unsigned integral types and uint128. template <typename T> - void PrintAsHexUpper(T v) { - static_assert(!IsSigned<T>::value, ""); - char *p = storage_ + sizeof(storage_); - - // kHexTable is only lowercase, so do it manually for uppercase. - do { - *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15]; - v >>= 4; - } while (v); - start_ = p; - size_ = storage_ + sizeof(storage_) - p; + void PrintAsHexUpper(T v) { + static_assert(!IsSigned<T>::value, ""); + char *p = storage_ + sizeof(storage_); + + // kHexTable is only lowercase, so do it manually for uppercase. + do { + *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15]; + v >>= 4; + } while (v); + start_ = p; + size_ = storage_ + sizeof(storage_) - p; } - // The printed value including the '-' sign if available. - // For inputs of value `0`, this will return "0" - string_view with_neg_and_zero() const { return {start_, size_}; } - - // The printed value not including the '-' sign. - // For inputs of value `0`, this will return "". - string_view without_neg_or_zero() const { - static_assert('-' < '0', "The check below verifies both."); - size_t advance = start_[0] <= '0' ? 1 : 0; - return {start_ + advance, size_ - advance}; + // The printed value including the '-' sign if available. + // For inputs of value `0`, this will return "0" + string_view with_neg_and_zero() const { return {start_, size_}; } + + // The printed value not including the '-' sign. + // For inputs of value `0`, this will return "". + string_view without_neg_or_zero() const { + static_assert('-' < '0', "The check below verifies both."); + size_t advance = start_[0] <= '0' ? 1 : 0; + return {start_ + advance, size_ - advance}; } - bool is_negative() const { return start_[0] == '-'; } + bool is_negative() const { return start_[0] == '-'; } - private: - const char *start_; - size_t size_; - // Max size: 128 bit value as octal -> 43 digits, plus sign char - char storage_[128 / 3 + 1 + 1]; + private: + const char *start_; + size_t size_; + // Max size: 128 bit value as octal -> 43 digits, plus sign char + char storage_[128 / 3 + 1 + 1]; }; // Note: 'o' conversions do not have a base indicator, it's just that // the '#' flag is specified to modify the precision for 'o' conversions. -string_view BaseIndicator(const IntDigits &as_digits, - const FormatConversionSpecImpl conv) { - // always show 0x for %p. - bool alt = conv.has_alt_flag() || - conv.conversion_char() == FormatConversionCharInternal::p; - bool hex = (conv.conversion_char() == FormatConversionCharInternal::x || - conv.conversion_char() == FormatConversionCharInternal::X || - conv.conversion_char() == FormatConversionCharInternal::p); +string_view BaseIndicator(const IntDigits &as_digits, + const FormatConversionSpecImpl conv) { + // always show 0x for %p. + bool alt = conv.has_alt_flag() || + conv.conversion_char() == FormatConversionCharInternal::p; + bool hex = (conv.conversion_char() == FormatConversionCharInternal::x || + conv.conversion_char() == FormatConversionCharInternal::X || + conv.conversion_char() == FormatConversionCharInternal::p); // From the POSIX description of '#' flag: // "For x or X conversion specifiers, a non-zero result shall have // 0x (or 0X) prefixed to it." - if (alt && hex && !as_digits.without_neg_or_zero().empty()) { - return conv.conversion_char() == FormatConversionCharInternal::X ? "0X" - : "0x"; + if (alt && hex && !as_digits.without_neg_or_zero().empty()) { + return conv.conversion_char() == FormatConversionCharInternal::X ? "0X" + : "0x"; } return {}; } -string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) { - if (conv.conversion_char() == FormatConversionCharInternal::d || - conv.conversion_char() == FormatConversionCharInternal::i) { +string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) { + if (conv.conversion_char() == FormatConversionCharInternal::d || + conv.conversion_char() == FormatConversionCharInternal::i) { if (neg) return "-"; - if (conv.has_show_pos_flag()) return "+"; - if (conv.has_sign_col_flag()) return " "; + if (conv.has_show_pos_flag()) return "+"; + if (conv.has_sign_col_flag()) return " "; } return {}; } -bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv, +bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { size_t fill = 0; if (conv.width() >= 0) fill = conv.width(); ReducePadding(1, &fill); - if (!conv.has_left_flag()) sink->Append(fill, ' '); + if (!conv.has_left_flag()) sink->Append(fill, ' '); sink->Append(1, v); - if (conv.has_left_flag()) sink->Append(fill, ' '); + if (conv.has_left_flag()) sink->Append(fill, ' '); return true; } -bool ConvertIntImplInnerSlow(const IntDigits &as_digits, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +bool ConvertIntImplInnerSlow(const IntDigits &as_digits, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { // Print as a sequence of Substrings: // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] size_t fill = 0; if (conv.width() >= 0) fill = conv.width(); - string_view formatted = as_digits.without_neg_or_zero(); + string_view formatted = as_digits.without_neg_or_zero(); ReducePadding(formatted, &fill); - string_view sign = SignColumn(as_digits.is_negative(), conv); + string_view sign = SignColumn(as_digits.is_negative(), conv); ReducePadding(sign, &fill); - string_view base_indicator = BaseIndicator(as_digits, conv); + string_view base_indicator = BaseIndicator(as_digits, conv); ReducePadding(base_indicator, &fill); int precision = conv.precision(); @@ -241,8 +241,8 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, if (!precision_specified) precision = 1; - if (conv.has_alt_flag() && - conv.conversion_char() == FormatConversionCharInternal::o) { + if (conv.has_alt_flag() && + conv.conversion_char() == FormatConversionCharInternal::o) { // From POSIX description of the '#' (alt) flag: // "For o conversion, it increases the precision (if necessary) to // force the first digit of the result to be zero." @@ -255,13 +255,13 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, size_t num_zeroes = Excess(formatted.size(), precision); ReducePadding(num_zeroes, &fill); - size_t num_left_spaces = !conv.has_left_flag() ? fill : 0; - size_t num_right_spaces = conv.has_left_flag() ? fill : 0; + size_t num_left_spaces = !conv.has_left_flag() ? fill : 0; + size_t num_right_spaces = conv.has_left_flag() ? fill : 0; // From POSIX description of the '0' (zero) flag: // "For d, i, o, u, x, and X conversion specifiers, if a precision // is specified, the '0' flag is ignored." - if (!precision_specified && conv.has_zero_flag()) { + if (!precision_specified && conv.has_zero_flag()) { num_zeroes += num_left_spaces; num_left_spaces = 0; } @@ -276,97 +276,97 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits, } template <typename T> -bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - using U = typename MakeUnsigned<T>::type; - IntDigits as_digits; - - // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes - // it to complain about a switch/case type mismatch, even though both are - // FormatConverionChar. Likely this is because at this point - // FormatConversionChar is declared, but not defined. - switch (static_cast<uint8_t>(conv.conversion_char())) { - case static_cast<uint8_t>(FormatConversionCharInternal::c): - return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink); - - case static_cast<uint8_t>(FormatConversionCharInternal::o): - as_digits.PrintAsOct(static_cast<U>(v)); - break; - - case static_cast<uint8_t>(FormatConversionCharInternal::x): - as_digits.PrintAsHexLower(static_cast<U>(v)); - break; - case static_cast<uint8_t>(FormatConversionCharInternal::X): - as_digits.PrintAsHexUpper(static_cast<U>(v)); - break; - - case static_cast<uint8_t>(FormatConversionCharInternal::u): - as_digits.PrintAsDec(static_cast<U>(v)); - break; - - case static_cast<uint8_t>(FormatConversionCharInternal::d): - case static_cast<uint8_t>(FormatConversionCharInternal::i): - as_digits.PrintAsDec(v); - break; - - case static_cast<uint8_t>(FormatConversionCharInternal::a): - case static_cast<uint8_t>(FormatConversionCharInternal::e): - case static_cast<uint8_t>(FormatConversionCharInternal::f): - case static_cast<uint8_t>(FormatConversionCharInternal::g): - case static_cast<uint8_t>(FormatConversionCharInternal::A): - case static_cast<uint8_t>(FormatConversionCharInternal::E): - case static_cast<uint8_t>(FormatConversionCharInternal::F): - case static_cast<uint8_t>(FormatConversionCharInternal::G): - return ConvertFloatImpl(static_cast<double>(v), conv, sink); - - default: - ABSL_INTERNAL_ASSUME(false); +bool ConvertIntArg(T v, const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { + using U = typename MakeUnsigned<T>::type; + IntDigits as_digits; + + // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes + // it to complain about a switch/case type mismatch, even though both are + // FormatConverionChar. Likely this is because at this point + // FormatConversionChar is declared, but not defined. + switch (static_cast<uint8_t>(conv.conversion_char())) { + case static_cast<uint8_t>(FormatConversionCharInternal::c): + return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink); + + case static_cast<uint8_t>(FormatConversionCharInternal::o): + as_digits.PrintAsOct(static_cast<U>(v)); + break; + + case static_cast<uint8_t>(FormatConversionCharInternal::x): + as_digits.PrintAsHexLower(static_cast<U>(v)); + break; + case static_cast<uint8_t>(FormatConversionCharInternal::X): + as_digits.PrintAsHexUpper(static_cast<U>(v)); + break; + + case static_cast<uint8_t>(FormatConversionCharInternal::u): + as_digits.PrintAsDec(static_cast<U>(v)); + break; + + case static_cast<uint8_t>(FormatConversionCharInternal::d): + case static_cast<uint8_t>(FormatConversionCharInternal::i): + as_digits.PrintAsDec(v); + break; + + case static_cast<uint8_t>(FormatConversionCharInternal::a): + case static_cast<uint8_t>(FormatConversionCharInternal::e): + case static_cast<uint8_t>(FormatConversionCharInternal::f): + case static_cast<uint8_t>(FormatConversionCharInternal::g): + case static_cast<uint8_t>(FormatConversionCharInternal::A): + case static_cast<uint8_t>(FormatConversionCharInternal::E): + case static_cast<uint8_t>(FormatConversionCharInternal::F): + case static_cast<uint8_t>(FormatConversionCharInternal::G): + return ConvertFloatImpl(static_cast<double>(v), conv, sink); + + default: + ABSL_INTERNAL_ASSUME(false); } - if (conv.is_basic()) { - sink->Append(as_digits.with_neg_and_zero()); - return true; + if (conv.is_basic()) { + sink->Append(as_digits.with_neg_and_zero()); + return true; } - return ConvertIntImplInnerSlow(as_digits, conv, sink); + return ConvertIntImplInnerSlow(as_digits, conv, sink); } template <typename T> -bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - return FormatConversionCharIsFloat(conv.conversion_char()) && +bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { + return FormatConversionCharIsFloat(conv.conversion_char()) && ConvertFloatImpl(v, conv, sink); } -inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv, +inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { - if (conv.is_basic()) { + if (conv.is_basic()) { sink->Append(v); return true; } return sink->PutPaddedString(v, conv.width(), conv.precision(), - conv.has_left_flag()); + conv.has_left_flag()); } } // namespace // ==================== Strings ==================== -StringConvertResult FormatConvertImpl(const TString &v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +StringConvertResult FormatConvertImpl(const TString &v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertStringArg(v, conv, sink)}; } -StringConvertResult FormatConvertImpl(string_view v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +StringConvertResult FormatConvertImpl(string_view v, + const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { return {ConvertStringArg(v, conv, sink)}; } -ArgConvertResult<FormatConversionCharSetUnion( - FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> -FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { - if (conv.conversion_char() == FormatConversionCharInternal::p) +ArgConvertResult<FormatConversionCharSetUnion( + FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> +FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, + FormatSinkImpl *sink) { + if (conv.conversion_char() == FormatConversionCharInternal::p) return {FormatConvertImpl(VoidPtr(v), conv, sink).value}; size_t len; if (v == nullptr) { @@ -381,99 +381,99 @@ FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, } // ==================== Raw pointers ==================== -ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( - VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { +ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( + VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { if (!v.value) { sink->Append("(nil)"); return {true}; } - IntDigits as_digits; - as_digits.PrintAsHexLower(v.value); - return {ConvertIntImplInnerSlow(as_digits, conv, sink)}; + IntDigits as_digits; + as_digits.PrintAsHexLower(v.value); + return {ConvertIntImplInnerSlow(as_digits, conv, sink)}; } // ==================== Floats ==================== -FloatingConvertResult FormatConvertImpl(float v, - const FormatConversionSpecImpl conv, +FloatingConvertResult FormatConvertImpl(float v, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } -FloatingConvertResult FormatConvertImpl(double v, - const FormatConversionSpecImpl conv, +FloatingConvertResult FormatConvertImpl(double v, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } FloatingConvertResult FormatConvertImpl(long double v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertFloatArg(v, conv, sink)}; } // ==================== Chars ==================== -IntegralConvertResult FormatConvertImpl(char v, - const FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(char v, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(signed char v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned char v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } // ==================== Ints ==================== IntegralConvertResult FormatConvertImpl(short v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -IntegralConvertResult FormatConvertImpl(int v, - const FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(int v, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } -IntegralConvertResult FormatConvertImpl(unsigned v, - const FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(unsigned v, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(long v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(long long v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(y_absl::int128 v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(y_absl::uint128 v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h index 59b7bcc727..fee261cbe3 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ @@ -24,7 +24,7 @@ #include <memory> #include <sstream> #include <util/generic/string.h> -#include <util/stream/str.h> +#include <util/stream/str.h> #include <type_traits> #include "y_absl/base/port.h" @@ -40,52 +40,52 @@ class Cord; class FormatCountCapture; class FormatSink; -template <y_absl::FormatConversionCharSet C> -struct FormatConvertResult; -class FormatConversionSpec; - +template <y_absl::FormatConversionCharSet C> +struct FormatConvertResult; +class FormatConversionSpec; + namespace str_format_internal { template <typename T, typename = void> struct HasUserDefinedConvert : std::false_type {}; template <typename T> -struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( - std::declval<const T&>(), - std::declval<const FormatConversionSpec&>(), - std::declval<FormatSink*>()))>> - : std::true_type {}; - -void AbslFormatConvert(); // Stops the lexical name lookup -template <typename T> -auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink) - -> decltype(AbslFormatConvert(v, - std::declval<const FormatConversionSpec&>(), - std::declval<FormatSink*>())) { - using FormatConversionSpecT = - y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; - using FormatSinkT = - y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; - auto fcs = conv.Wrap<FormatConversionSpecT>(); - auto fs = sink->Wrap<FormatSinkT>(); - return AbslFormatConvert(v, fcs, &fs); -} +struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert( + std::declval<const T&>(), + std::declval<const FormatConversionSpec&>(), + std::declval<FormatSink*>()))>> + : std::true_type {}; +void AbslFormatConvert(); // Stops the lexical name lookup template <typename T> +auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv, + FormatSinkImpl* sink) + -> decltype(AbslFormatConvert(v, + std::declval<const FormatConversionSpec&>(), + std::declval<FormatSink*>())) { + using FormatConversionSpecT = + y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; + using FormatSinkT = + y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>; + auto fcs = conv.Wrap<FormatConversionSpecT>(); + auto fs = sink->Wrap<FormatSinkT>(); + return AbslFormatConvert(v, fcs, &fs); +} + +template <typename T> class StreamedWrapper; // If 'v' can be converted (in the printf sense) according to 'conv', // then convert it, appending to `sink` and return `true`. // Otherwise fail and return `false`. -// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v' -// as an extension mechanism. These FormatConvertImpl functions are the default -// implementations. -// The ADL search is augmented via the 'Sink*' parameter, which also -// serves as a disambiguator to reject possible unintended 'AbslFormatConvert' -// functions in the namespaces associated with 'v'. - +// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v' +// as an extension mechanism. These FormatConvertImpl functions are the default +// implementations. +// The ADL search is augmented via the 'Sink*' parameter, which also +// serves as a disambiguator to reject possible unintended 'AbslFormatConvert' +// functions in the namespaces associated with 'v'. + // Raw pointers. struct VoidPtr { VoidPtr() = default; @@ -96,33 +96,33 @@ struct VoidPtr { uintptr_t value; }; -template <FormatConversionCharSet C> -struct ArgConvertResult { - bool value; -}; - -template <FormatConversionCharSet C> -constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) { - return C; -} - -template <FormatConversionCharSet C> -constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { - return C; -} - -using StringConvertResult = - ArgConvertResult<FormatConversionCharSetInternal::s>; -ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( - VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); - +template <FormatConversionCharSet C> +struct ArgConvertResult { + bool value; +}; + +template <FormatConversionCharSet C> +constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) { + return C; +} + +template <FormatConversionCharSet C> +constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) { + return C; +} + +using StringConvertResult = + ArgConvertResult<FormatConversionCharSetInternal::s>; +ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl( + VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); + // Strings. -StringConvertResult FormatConvertImpl(const TString& v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -StringConvertResult FormatConvertImpl(string_view v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); +StringConvertResult FormatConvertImpl(const TString& v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); +StringConvertResult FormatConvertImpl(string_view v, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink); #if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW) inline StringConvertResult FormatConvertImpl(std::string_view v, FormatConversionSpecImpl conv, @@ -131,17 +131,17 @@ inline StringConvertResult FormatConvertImpl(std::string_view v, } #endif // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW -ArgConvertResult<FormatConversionCharSetUnion( - FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> -FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv, - FormatSinkImpl* sink); - -template <class AbslCord, typename std::enable_if<std::is_same< - AbslCord, y_absl::Cord>::value>::type* = nullptr> -StringConvertResult FormatConvertImpl(const AbslCord& value, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink) { - bool is_left = conv.has_left_flag(); +ArgConvertResult<FormatConversionCharSetUnion( + FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)> +FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv, + FormatSinkImpl* sink); + +template <class AbslCord, typename std::enable_if<std::is_same< + AbslCord, y_absl::Cord>::value>::type* = nullptr> +StringConvertResult FormatConvertImpl(const AbslCord& value, + FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { + bool is_left = conv.has_left_flag(); size_t space_remaining = 0; int width = conv.width(); @@ -174,63 +174,63 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, return {true}; } -using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( - FormatConversionCharSetInternal::c, - FormatConversionCharSetInternal::kNumeric, - FormatConversionCharSetInternal::kStar)>; -using FloatingConvertResult = - ArgConvertResult<FormatConversionCharSetInternal::kFloating>; +using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion( + FormatConversionCharSetInternal::c, + FormatConversionCharSetInternal::kNumeric, + FormatConversionCharSetInternal::kStar)>; +using FloatingConvertResult = + ArgConvertResult<FormatConversionCharSetInternal::kFloating>; // Floats. -FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, +FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv, +FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -FloatingConvertResult FormatConvertImpl(long double v, - FormatConversionSpecImpl conv, +FloatingConvertResult FormatConvertImpl(long double v, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); // Chars. -IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(signed char v, - FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(signed char v, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned char v, - FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(unsigned char v, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); // Ints. IntegralConvertResult FormatConvertImpl(short v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(unsigned v, - FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(unsigned v, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(long v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(long long v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT - FormatConversionSpecImpl conv, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); -IntegralConvertResult FormatConvertImpl(uint128 v, - FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(uint128 v, + FormatConversionSpecImpl conv, FormatSinkImpl* sink); template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> -IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, +IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink) { return FormatConvertImpl(static_cast<int>(v), conv, sink); } @@ -241,41 +241,41 @@ template <typename T> typename std::enable_if<std::is_enum<T>::value && !HasUserDefinedConvert<T>::value, IntegralConvertResult>::type -FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); +FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink); template <typename T> -StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, - FormatConversionSpecImpl conv, - FormatSinkImpl* out) { - TString buf; - TStringOutput oss(buf); +StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, + FormatConversionSpecImpl conv, + FormatSinkImpl* out) { + TString buf; + TStringOutput oss(buf); oss << v.v_; - if (!buf) return {false}; - return str_format_internal::FormatConvertImpl(buf, conv, out); + if (!buf) return {false}; + return str_format_internal::FormatConvertImpl(buf, conv, out); } // Use templates and dependent types to delay evaluation of the function // until after FormatCountCapture is fully defined. struct FormatCountCaptureHelper { template <class T = int> - static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( - const FormatCountCapture& v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink) { + static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper( + const FormatCountCapture& v, FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { const y_absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; - if (conv.conversion_char() != - str_format_internal::FormatConversionCharInternal::n) { - return {false}; - } + if (conv.conversion_char() != + str_format_internal::FormatConversionCharInternal::n) { + return {false}; + } *v2.p_ = static_cast<int>(sink->size()); return {true}; } }; template <class T = int> -ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( - const FormatCountCapture& v, FormatConversionSpecImpl conv, - FormatSinkImpl* sink) { +ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( + const FormatCountCapture& v, FormatConversionSpecImpl conv, + FormatSinkImpl* sink) { return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); } @@ -284,13 +284,13 @@ ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl( struct FormatArgImplFriend { template <typename Arg> static bool ToInt(Arg arg, int* out) { - // A value initialized FormatConversionSpecImpl has a `none` conv, which - // tells the dispatcher to run the `int` conversion. + // A value initialized FormatConversionSpecImpl has a `none` conv, which + // tells the dispatcher to run the `int` conversion. return arg.dispatcher_(arg.data_, {}, out); } template <typename Arg> - static bool Convert(Arg arg, FormatConversionSpecImpl conv, + static bool Convert(Arg arg, FormatConversionSpecImpl conv, FormatSinkImpl* out) { return arg.dispatcher_(arg.data_, conv, out); } @@ -301,15 +301,15 @@ struct FormatArgImplFriend { } }; -template <typename Arg> -constexpr FormatConversionCharSet ArgumentToConv() { - return y_absl::str_format_internal::ExtractCharSet( - decltype(str_format_internal::FormatConvertImpl( - std::declval<const Arg&>(), - std::declval<const FormatConversionSpecImpl&>(), - std::declval<FormatSinkImpl*>())){}); -} - +template <typename Arg> +constexpr FormatConversionCharSet ArgumentToConv() { + return y_absl::str_format_internal::ExtractCharSet( + decltype(str_format_internal::FormatConvertImpl( + std::declval<const Arg&>(), + std::declval<const FormatConversionSpecImpl&>(), + std::declval<FormatSinkImpl*>())){}); +} + // A type-erased handle to a format argument. class FormatArgImpl { private: @@ -323,7 +323,7 @@ class FormatArgImpl { char buf[kInlinedSpace]; }; - using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out); + using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out); template <typename T> struct store_by_value @@ -465,20 +465,20 @@ class FormatArgImpl { } template <typename T> - static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) { + static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) { // A `none` conv indicates that we want the `int` conversion. - if (ABSL_PREDICT_FALSE(spec.conversion_char() == - FormatConversionCharInternal::kNone)) { + if (ABSL_PREDICT_FALSE(spec.conversion_char() == + FormatConversionCharInternal::kNone)) { return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(), std::is_enum<T>()); } - if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), - spec.conversion_char()))) { - return false; - } + if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(), + spec.conversion_char()))) { + return false; + } return str_format_internal::FormatConvertImpl( - Manager<T>::Value(arg), spec, - static_cast<FormatSinkImpl*>(out)) + Manager<T>::Value(arg), spec, + static_cast<FormatSinkImpl*>(out)) .value; } @@ -486,9 +486,9 @@ class FormatArgImpl { Dispatcher dispatcher_; }; -#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ - E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \ - void*) +#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \ + E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \ + void*) #define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \ ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc index 211ce25dea..5a62088bff 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/str_format/bind.h" #include <cerrno> @@ -160,7 +160,7 @@ class SummarizingConverter { << FormatConversionSpecImplFriend::FlagsToString(bound); if (bound.width() >= 0) ss << bound.width(); if (bound.precision() >= 0) ss << "." << bound.precision(); - ss << bound.conversion_char() << "}"; + ss << bound.conversion_char() << "}"; Append(ss.str()); return true; } @@ -234,7 +234,7 @@ int FprintF(std::FILE* output, const UntypedFormatSpecImpl format, errno = sink.error(); return -1; } - if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) { + if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) { errno = EFBIG; return -1; } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h index 3966610710..f0e73a6db2 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ @@ -33,7 +33,7 @@ class UntypedFormatSpec; namespace str_format_internal { -class BoundConversion : public FormatConversionSpecImpl { +class BoundConversion : public FormatConversionSpecImpl { public: const FormatArgImpl* arg() const { return arg_; } void set_arg(const FormatArgImpl* a) { arg_ = a; } @@ -74,7 +74,7 @@ class UntypedFormatSpecImpl { size_t size_; }; -template <typename T, FormatConversionCharSet...> +template <typename T, FormatConversionCharSet...> struct MakeDependent { using type = T; }; @@ -82,7 +82,7 @@ struct MakeDependent { // Implicitly convertible from `const char*`, `string_view`, and the // `ExtendedParsedFormat` type. This abstraction allows all format functions to // operate on any without providing too many overloads. -template <FormatConversionCharSet... Args> +template <FormatConversionCharSet... Args> class FormatSpecTemplate : public MakeDependent<UntypedFormatSpec, Args...>::type { using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; @@ -90,11 +90,11 @@ class FormatSpecTemplate public: #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - // Honeypot overload for when the string is not constexpr. + // Honeypot overload for when the string is not constexpr. // We use the 'unavailable' attribute to give a better compiler error than // just 'method is deleted'. FormatSpecTemplate(...) // NOLINT - __attribute__((unavailable("Format string is not constexpr."))); + __attribute__((unavailable("Format string is not constexpr."))); // Honeypot overload for when the format is constexpr and invalid. // We use the 'unavailable' attribute to give a better compiler error than @@ -119,11 +119,11 @@ class FormatSpecTemplate // Good format overload. FormatSpecTemplate(const char* s) // NOLINT - __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) + __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) : Base(s) {} FormatSpecTemplate(string_view s) // NOLINT - __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) + __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap"))) : Base(s) {} #else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER @@ -133,11 +133,11 @@ class FormatSpecTemplate #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER - template < - FormatConversionCharSet... C, - typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type, - typename = typename std::enable_if<AllOf(Contains(Args, - C)...)>::type> + template < + FormatConversionCharSet... C, + typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type, + typename = typename std::enable_if<AllOf(Contains(Args, + C)...)>::type> FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT : Base(&pc) {} }; @@ -204,9 +204,9 @@ class StreamedWrapper { private: template <typename S> - friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( - const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, - FormatSinkImpl* out); + friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl( + const StreamedWrapper<S>& v, FormatConversionSpecImpl conv, + FormatSinkImpl* out); const T& v_; }; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h index 7c530d2507..ba3b3d02f3 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ @@ -46,14 +46,14 @@ constexpr bool ContainsChar(const char* chars, char c) { // A constexpr compatible list of Convs. struct ConvList { - const FormatConversionCharSet* array; + const FormatConversionCharSet* array; int count; // We do the bound check here to avoid having to do it on the callers. - // Returning an empty FormatConversionCharSet has the same effect as - // short circuiting because it will never match any conversion. - constexpr FormatConversionCharSet operator[](int i) const { - return i < count ? array[i] : FormatConversionCharSet{}; + // Returning an empty FormatConversionCharSet has the same effect as + // short circuiting because it will never match any conversion. + constexpr FormatConversionCharSet operator[](int i) const { + return i < count ? array[i] : FormatConversionCharSet{}; } constexpr ConvList without_front() const { @@ -64,7 +64,7 @@ struct ConvList { template <size_t count> struct ConvListT { // Make sure the array has size > 0. - FormatConversionCharSet list[count ? count : 1]; + FormatConversionCharSet list[count ? count : 1]; }; constexpr char GetChar(string_view str, size_t index) { @@ -317,7 +317,7 @@ class FormatParser { ConvList args_; }; -template <FormatConversionCharSet... C> +template <FormatConversionCharSet... C> constexpr bool ValidFormatImpl(string_view format) { return FormatParser(format, {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)}) diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc index f2a4169ae7..13c452cb8e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc @@ -33,40 +33,40 @@ TString FlagsToString(Flags v) { return s; } -#define ABSL_INTERNAL_X_VAL(id) \ - constexpr y_absl::FormatConversionChar FormatConversionCharInternal::id; -ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) -#undef ABSL_INTERNAL_X_VAL -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr y_absl::FormatConversionChar FormatConversionCharInternal::kNone; - -#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ - constexpr FormatConversionCharSet FormatConversionCharSetInternal::c; -ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) -#undef ABSL_INTERNAL_CHAR_SET_CASE - -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar; -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral; -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating; -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric; -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer; - -bool FormatSinkImpl::PutPaddedString(string_view value, int width, - int precision, bool left) { +#define ABSL_INTERNAL_X_VAL(id) \ + constexpr y_absl::FormatConversionChar FormatConversionCharInternal::id; +ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) +#undef ABSL_INTERNAL_X_VAL +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr y_absl::FormatConversionChar FormatConversionCharInternal::kNone; + +#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ + constexpr FormatConversionCharSet FormatConversionCharSetInternal::c; +ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) +#undef ABSL_INTERNAL_CHAR_SET_CASE + +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar; +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral; +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating; +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric; +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer; + +bool FormatSinkImpl::PutPaddedString(string_view value, int width, + int precision, bool left) { size_t space_remaining = 0; - if (width >= 0) space_remaining = width; - size_t n = value.size(); - if (precision >= 0) n = std::min(n, static_cast<size_t>(precision)); - string_view shown(value.data(), n); + if (width >= 0) space_remaining = width; + size_t n = value.size(); + if (precision >= 0) n = std::min(n, static_cast<size_t>(precision)); + string_view shown(value.data(), n); space_remaining = Excess(shown.size(), space_remaining); - if (!left) Append(space_remaining, ' '); + if (!left) Append(space_remaining, ' '); Append(shown); - if (left) Append(space_remaining, ' '); + if (left) Append(space_remaining, ' '); return true; } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h index e5de5cb6a1..1548d56578 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h @@ -24,16 +24,16 @@ #include "y_absl/base/config.h" #include "y_absl/base/port.h" -#include "y_absl/meta/type_traits.h" +#include "y_absl/meta/type_traits.h" #include "y_absl/strings/internal/str_format/output.h" #include "y_absl/strings/string_view.h" namespace y_absl { ABSL_NAMESPACE_BEGIN - -enum class FormatConversionChar : uint8_t; -enum class FormatConversionCharSet : uint64_t; - + +enum class FormatConversionChar : uint8_t; +enum class FormatConversionCharSet : uint64_t; + namespace str_format_internal { class FormatRawSinkImpl { @@ -107,7 +107,7 @@ class FormatSinkImpl { size_t size() const { return size_; } // Put 'v' to 'sink' with specified width, precision, and left flag. - bool PutPaddedString(string_view v, int width, int precision, bool left); + bool PutPaddedString(string_view v, int width, int precision, bool left); template <typename T> T Wrap() { @@ -158,7 +158,7 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) { // clang-format off #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \ /* text */ \ - X_VAL(c) X_SEP X_VAL(s) X_SEP \ + X_VAL(c) X_SEP X_VAL(s) X_SEP \ /* ints */ \ X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \ X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \ @@ -167,39 +167,39 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) { X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \ /* misc */ \ X_VAL(n) X_SEP X_VAL(p) -// clang-format on - -// This type should not be referenced, it exists only to provide labels -// internally that match the values declared in FormatConversionChar in -// str_format.h. This is meant to allow internal libraries to use the same -// declared interface type as the public interface -// (y_absl::StrFormatConversionChar) while keeping the definition in a public -// header. -// Internal libraries should use the form -// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for -// comparisons. Use in switch statements is not recommended due to a bug in how -// gcc 4.9 -Wswitch handles declared but undefined enums. -struct FormatConversionCharInternal { - FormatConversionCharInternal() = delete; - - private: - // clang-format off - enum class Enum : uint8_t { - c, s, // text +// clang-format on + +// This type should not be referenced, it exists only to provide labels +// internally that match the values declared in FormatConversionChar in +// str_format.h. This is meant to allow internal libraries to use the same +// declared interface type as the public interface +// (y_absl::StrFormatConversionChar) while keeping the definition in a public +// header. +// Internal libraries should use the form +// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for +// comparisons. Use in switch statements is not recommended due to a bug in how +// gcc 4.9 -Wswitch handles declared but undefined enums. +struct FormatConversionCharInternal { + FormatConversionCharInternal() = delete; + + private: + // clang-format off + enum class Enum : uint8_t { + c, s, // text d, i, o, u, x, X, // int f, F, e, E, g, G, a, A, // float n, p, // misc - kNone - }; - // clang-format on - public: -#define ABSL_INTERNAL_X_VAL(id) \ - static constexpr FormatConversionChar id = \ - static_cast<FormatConversionChar>(Enum::id); - ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) -#undef ABSL_INTERNAL_X_VAL - static constexpr FormatConversionChar kNone = - static_cast<FormatConversionChar>(Enum::kNone); + kNone + }; + // clang-format on + public: +#define ABSL_INTERNAL_X_VAL(id) \ + static constexpr FormatConversionChar id = \ + static_cast<FormatConversionChar>(Enum::id); + ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) +#undef ABSL_INTERNAL_X_VAL + static constexpr FormatConversionChar kNone = + static_cast<FormatConversionChar>(Enum::kNone); }; // clang-format on @@ -207,54 +207,54 @@ inline FormatConversionChar FormatConversionCharFromChar(char c) { switch (c) { #define ABSL_INTERNAL_X_VAL(id) \ case #id[0]: \ - return FormatConversionCharInternal::id; + return FormatConversionCharInternal::id; ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) #undef ABSL_INTERNAL_X_VAL } - return FormatConversionCharInternal::kNone; + return FormatConversionCharInternal::kNone; } inline bool FormatConversionCharIsUpper(FormatConversionChar c) { - if (c == FormatConversionCharInternal::X || - c == FormatConversionCharInternal::F || - c == FormatConversionCharInternal::E || - c == FormatConversionCharInternal::G || - c == FormatConversionCharInternal::A) { - return true; - } else { - return false; + if (c == FormatConversionCharInternal::X || + c == FormatConversionCharInternal::F || + c == FormatConversionCharInternal::E || + c == FormatConversionCharInternal::G || + c == FormatConversionCharInternal::A) { + return true; + } else { + return false; } } inline bool FormatConversionCharIsFloat(FormatConversionChar c) { - if (c == FormatConversionCharInternal::a || - c == FormatConversionCharInternal::e || - c == FormatConversionCharInternal::f || - c == FormatConversionCharInternal::g || - c == FormatConversionCharInternal::A || - c == FormatConversionCharInternal::E || - c == FormatConversionCharInternal::F || - c == FormatConversionCharInternal::G) { - return true; - } else { - return false; + if (c == FormatConversionCharInternal::a || + c == FormatConversionCharInternal::e || + c == FormatConversionCharInternal::f || + c == FormatConversionCharInternal::g || + c == FormatConversionCharInternal::A || + c == FormatConversionCharInternal::E || + c == FormatConversionCharInternal::F || + c == FormatConversionCharInternal::G) { + return true; + } else { + return false; } } inline char FormatConversionCharToChar(FormatConversionChar c) { - if (c == FormatConversionCharInternal::kNone) { - return '\0'; - -#define ABSL_INTERNAL_X_VAL(e) \ - } else if (c == FormatConversionCharInternal::e) { \ + if (c == FormatConversionCharInternal::kNone) { + return '\0'; + +#define ABSL_INTERNAL_X_VAL(e) \ + } else if (c == FormatConversionCharInternal::e) { \ return #e[0]; #define ABSL_INTERNAL_X_SEP - ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, - ABSL_INTERNAL_X_SEP) - } else { - return '\0'; - } - + ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, + ABSL_INTERNAL_X_SEP) + } else { + return '\0'; + } + #undef ABSL_INTERNAL_X_VAL #undef ABSL_INTERNAL_X_SEP } @@ -268,7 +268,7 @@ inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) { struct FormatConversionSpecImplFriend; -class FormatConversionSpecImpl { +class FormatConversionSpecImpl { public: // Width and precison are not specified, no flags are set. bool is_basic() const { return flags_ == Flags::kBasic; } @@ -285,7 +285,7 @@ class FormatConversionSpecImpl { FormatConversionChar conversion_char() const { // Keep this field first in the struct . It generates better code when // accessing it when ConversionSpec is passed by value in registers. - static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, ""); + static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, ""); return conv_; } @@ -296,65 +296,65 @@ class FormatConversionSpecImpl { // negative value. int precision() const { return precision_; } - template <typename T> - T Wrap() { - return T(*this); - } + template <typename T> + T Wrap() { + return T(*this); + } private: friend struct str_format_internal::FormatConversionSpecImplFriend; - FormatConversionChar conv_ = FormatConversionCharInternal::kNone; + FormatConversionChar conv_ = FormatConversionCharInternal::kNone; Flags flags_; int width_; int precision_; }; struct FormatConversionSpecImplFriend final { - static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { + static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { conv->flags_ = f; } static void SetConversionChar(FormatConversionChar c, - FormatConversionSpecImpl* conv) { + FormatConversionSpecImpl* conv) { conv->conv_ = c; } - static void SetWidth(int w, FormatConversionSpecImpl* conv) { - conv->width_ = w; - } - static void SetPrecision(int p, FormatConversionSpecImpl* conv) { + static void SetWidth(int w, FormatConversionSpecImpl* conv) { + conv->width_ = w; + } + static void SetPrecision(int p, FormatConversionSpecImpl* conv) { conv->precision_ = p; } - static TString FlagsToString(const FormatConversionSpecImpl& spec) { + static TString FlagsToString(const FormatConversionSpecImpl& spec) { return str_format_internal::FlagsToString(spec.flags_); } }; -// Type safe OR operator. -// We need this for two reasons: -// 1. operator| on enums makes them decay to integers and the result is an -// integer. We need the result to stay as an enum. -// 2. We use "enum class" which would not work even if we accepted the decay. -constexpr FormatConversionCharSet FormatConversionCharSetUnion( - FormatConversionCharSet a) { - return a; -} - -template <typename... CharSet> -constexpr FormatConversionCharSet FormatConversionCharSetUnion( - FormatConversionCharSet a, CharSet... rest) { - return static_cast<FormatConversionCharSet>( - static_cast<uint64_t>(a) | - static_cast<uint64_t>(FormatConversionCharSetUnion(rest...))); -} - -constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) { - return uint64_t{1} << (1 + static_cast<uint8_t>(c)); -} - -constexpr uint64_t FormatConversionCharToConvInt(char conv) { +// Type safe OR operator. +// We need this for two reasons: +// 1. operator| on enums makes them decay to integers and the result is an +// integer. We need the result to stay as an enum. +// 2. We use "enum class" which would not work even if we accepted the decay. +constexpr FormatConversionCharSet FormatConversionCharSetUnion( + FormatConversionCharSet a) { + return a; +} + +template <typename... CharSet> +constexpr FormatConversionCharSet FormatConversionCharSetUnion( + FormatConversionCharSet a, CharSet... rest) { + return static_cast<FormatConversionCharSet>( + static_cast<uint64_t>(a) | + static_cast<uint64_t>(FormatConversionCharSetUnion(rest...))); +} + +constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) { + return uint64_t{1} << (1 + static_cast<uint8_t>(c)); +} + +constexpr uint64_t FormatConversionCharToConvInt(char conv) { return -#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ - conv == #c[0] \ - ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \ +#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ + conv == #c[0] \ + ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \ : ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) #undef ABSL_INTERNAL_CHAR_SET_CASE @@ -363,29 +363,29 @@ constexpr uint64_t FormatConversionCharToConvInt(char conv) { : 0; } -constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) { - return static_cast<FormatConversionCharSet>( - FormatConversionCharToConvInt(conv)); -} - -struct FormatConversionCharSetInternal { -#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ - static constexpr FormatConversionCharSet c = \ - FormatConversionCharToConvValue(#c[0]); +constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) { + return static_cast<FormatConversionCharSet>( + FormatConversionCharToConvInt(conv)); +} + +struct FormatConversionCharSetInternal { +#define ABSL_INTERNAL_CHAR_SET_CASE(c) \ + static constexpr FormatConversionCharSet c = \ + FormatConversionCharToConvValue(#c[0]); ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) #undef ABSL_INTERNAL_CHAR_SET_CASE // Used for width/precision '*' specification. - static constexpr FormatConversionCharSet kStar = - FormatConversionCharToConvValue('*'); - - static constexpr FormatConversionCharSet kIntegral = - FormatConversionCharSetUnion(d, i, u, o, x, X); - static constexpr FormatConversionCharSet kFloating = - FormatConversionCharSetUnion(a, e, f, g, A, E, F, G); - static constexpr FormatConversionCharSet kNumeric = - FormatConversionCharSetUnion(kIntegral, kFloating); - static constexpr FormatConversionCharSet kPointer = p; + static constexpr FormatConversionCharSet kStar = + FormatConversionCharToConvValue('*'); + + static constexpr FormatConversionCharSet kIntegral = + FormatConversionCharSetUnion(d, i, u, o, x, X); + static constexpr FormatConversionCharSet kFloating = + FormatConversionCharSetUnion(a, e, f, g, A, E, F, G); + static constexpr FormatConversionCharSet kNumeric = + FormatConversionCharSetUnion(kIntegral, kFloating); + static constexpr FormatConversionCharSet kPointer = p; }; // Type safe OR operator. @@ -395,29 +395,29 @@ struct FormatConversionCharSetInternal { // 2. We use "enum class" which would not work even if we accepted the decay. constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, FormatConversionCharSet b) { - return FormatConversionCharSetUnion(a, b); -} - -// Overloaded conversion functions to support y_absl::ParsedFormat. -// Get a conversion with a single character in it. -constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { - return static_cast<FormatConversionCharSet>( - FormatConversionCharToConvValue(c)); + return FormatConversionCharSetUnion(a, b); } +// Overloaded conversion functions to support y_absl::ParsedFormat. // Get a conversion with a single character in it. -constexpr FormatConversionCharSet ToFormatConversionCharSet( - FormatConversionCharSet c) { - return c; +constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { + return static_cast<FormatConversionCharSet>( + FormatConversionCharToConvValue(c)); } -template <typename T> -void ToFormatConversionCharSet(T) = delete; - +// Get a conversion with a single character in it. +constexpr FormatConversionCharSet ToFormatConversionCharSet( + FormatConversionCharSet c) { + return c; +} + +template <typename T> +void ToFormatConversionCharSet(T) = delete; + // Checks whether `c` exists in `set`. constexpr bool Contains(FormatConversionCharSet set, char c) { - return (static_cast<uint64_t>(set) & - static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0; + return (static_cast<uint64_t>(set) & + static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0; } // Checks whether all the characters in `c` are contained in `set` @@ -427,10 +427,10 @@ constexpr bool Contains(FormatConversionCharSet set, static_cast<uint64_t>(c); } -// Checks whether all the characters in `c` are contained in `set` -constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) { - return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0; -} +// Checks whether all the characters in `c` are contained in `set` +constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) { + return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0; +} // Return capacity - used, clipped to a minimum of 0. inline size_t Excess(size_t used, size_t capacity) { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc index c49062538d..af48a71cde 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc @@ -1,38 +1,38 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/str_format/float_conversion.h" #include <string.h> - + #include <algorithm> #include <cassert> #include <cmath> -#include <limits> +#include <limits> #include <util/generic/string.h> -#include "y_absl/base/attributes.h" +#include "y_absl/base/attributes.h" #include "y_absl/base/config.h" -#include "y_absl/base/optimization.h" -#include "y_absl/functional/function_ref.h" -#include "y_absl/meta/type_traits.h" -#include "y_absl/numeric/bits.h" -#include "y_absl/numeric/int128.h" -#include "y_absl/numeric/internal/representation.h" -#include "y_absl/strings/numbers.h" -#include "y_absl/types/optional.h" -#include "y_absl/types/span.h" +#include "y_absl/base/optimization.h" +#include "y_absl/functional/function_ref.h" +#include "y_absl/meta/type_traits.h" +#include "y_absl/numeric/bits.h" +#include "y_absl/numeric/int128.h" +#include "y_absl/numeric/internal/representation.h" +#include "y_absl/strings/numbers.h" +#include "y_absl/types/optional.h" +#include "y_absl/types/span.h" namespace y_absl { ABSL_NAMESPACE_BEGIN @@ -40,905 +40,905 @@ namespace str_format_internal { namespace { -using ::y_absl::numeric_internal::IsDoubleDouble; - -// The code below wants to avoid heap allocations. -// To do so it needs to allocate memory on the stack. -// `StackArray` will allocate memory on the stack in the form of a uint32_t -// array and call the provided callback with said memory. -// It will allocate memory in increments of 512 bytes. We could allocate the -// largest needed unconditionally, but that is more than we need in most of -// cases. This way we use less stack in the common cases. -class StackArray { - using Func = y_absl::FunctionRef<void(y_absl::Span<uint32_t>)>; - static constexpr size_t kStep = 512 / sizeof(uint32_t); - // 5 steps is 2560 bytes, which is enough to hold a long double with the - // largest/smallest exponents. - // The operations below will static_assert their particular maximum. - static constexpr size_t kNumSteps = 5; - - // We do not want this function to be inlined. - // Otherwise the caller will allocate the stack space unnecessarily for all - // the variants even though it only calls one. - template <size_t steps> - ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) { - uint32_t values[steps * kStep]{}; - f(y_absl::MakeSpan(values)); - } - - public: - static constexpr size_t kMaxCapacity = kStep * kNumSteps; - - static void RunWithCapacity(size_t capacity, Func f) { - assert(capacity <= kMaxCapacity); - const size_t step = (capacity + kStep - 1) / kStep; - assert(step <= kNumSteps); - switch (step) { - case 1: - return RunWithCapacityImpl<1>(f); - case 2: - return RunWithCapacityImpl<2>(f); - case 3: - return RunWithCapacityImpl<3>(f); - case 4: - return RunWithCapacityImpl<4>(f); - case 5: - return RunWithCapacityImpl<5>(f); - } - - assert(false && "Invalid capacity"); - } -}; - -// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns -// the carry. -template <typename Int> -inline Int MultiplyBy10WithCarry(Int *v, Int carry) { - using BiggerInt = y_absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>; - BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry; - *v = static_cast<Int>(tmp); - return static_cast<Int>(tmp >> (sizeof(Int) * 8)); -} - -// Calculates `(2^64 * carry + *v) / 10`. -// Stores the quotient in `*v` and returns the remainder. -// Requires: `0 <= carry <= 9` -inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) { - constexpr uint64_t divisor = 10; - // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor - constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2); - constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor; - - const uint64_t mod = *v % divisor; - const uint64_t next_carry = chunk_remainder * carry + mod; - *v = *v / divisor + carry * chunk_quotient + next_carry / divisor; - return next_carry % divisor; -} - -using MaxFloatType = - typename std::conditional<IsDoubleDouble(), double, long double>::type; - -// Generates the decimal representation for an integer of the form `v * 2^exp`, -// where `v` and `exp` are both positive integers. -// It generates the digits from the left (ie the most significant digit first) -// to allow for direct printing into the sink. -// -// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`. -class BinaryToDecimal { - static constexpr int ChunksNeeded(int exp) { - // We will left shift a uint128 by `exp` bits, so we need `128+exp` total - // bits. Round up to 32. - // See constructor for details about adding `10%` to the value. - return (128 + exp + 31) / 32 * 11 / 10; - } - - public: - // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`. - // This function will allocate enough stack space to perform the conversion. - static void RunConversion(uint128 v, int exp, - y_absl::FunctionRef<void(BinaryToDecimal)> f) { - assert(exp > 0); - assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent); - static_assert( - static_cast<int>(StackArray::kMaxCapacity) >= - ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent), - ""); - - StackArray::RunWithCapacity( - ChunksNeeded(exp), - [=](y_absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); }); - } - - int TotalDigits() const { - return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk + - CurrentDigits().size()); - } - - // See the current block of digits. - y_absl::string_view CurrentDigits() const { - return y_absl::string_view(digits_ + kDigitsPerChunk - size_, size_); - } - - // Advance the current view of digits. - // Returns `false` when no more digits are available. - bool AdvanceDigits() { - if (decimal_start_ >= decimal_end_) return false; - - uint32_t w = data_[decimal_start_++]; - for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) { - digits_[kDigitsPerChunk - ++size_] = w % 10 + '0'; - } - return true; - } - - private: - BinaryToDecimal(y_absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) { - // We need to print the digits directly into the sink object without - // buffering them all first. To do this we need two things: - // - to know the total number of digits to do padding when necessary - // - to generate the decimal digits from the left. - // - // In order to do this, we do a two pass conversion. - // On the first pass we convert the binary representation of the value into - // a decimal representation in which each uint32_t chunk holds up to 9 - // decimal digits. In the second pass we take each decimal-holding-uint32_t - // value and generate the ascii decimal digits into `digits_`. - // - // The binary and decimal representations actually share the same memory - // region. As we go converting the chunks from binary to decimal we free - // them up and reuse them for the decimal representation. One caveat is that - // the decimal representation is around 7% less efficient in space than the - // binary one. We allocate an extra 10% memory to account for this. See - // ChunksNeeded for this calculation. - int chunk_index = exp / 32; - decimal_start_ = decimal_end_ = ChunksNeeded(exp); - const int offset = exp % 32; - // Left shift v by exp bits. - data_[chunk_index] = static_cast<uint32_t>(v << offset); - for (v >>= (32 - offset); v; v >>= 32) - data_[++chunk_index] = static_cast<uint32_t>(v); - - while (chunk_index >= 0) { - // While we have more than one chunk available, go in steps of 1e9. - // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep - // the variable updated. - uint32_t carry = 0; - for (int i = chunk_index; i >= 0; --i) { - uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32); - data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000}); - carry = static_cast<uint32_t>(tmp % uint64_t{1000000000}); - } - - // If the highest chunk is now empty, remove it from view. - if (data_[chunk_index] == 0) --chunk_index; - - --decimal_start_; - assert(decimal_start_ != chunk_index); - data_[decimal_start_] = carry; - } - - // Fill the first set of digits. The first chunk might not be complete, so - // handle differently. - for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) { - digits_[kDigitsPerChunk - ++size_] = first % 10 + '0'; - } - } - - private: - static constexpr int kDigitsPerChunk = 9; - - int decimal_start_; - int decimal_end_; - - char digits_[kDigitsPerChunk]; - int size_ = 0; - - y_absl::Span<uint32_t> data_; -}; - -// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits. -// Requires `-exp < 0` and -// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`. -class FractionalDigitGenerator { - public: - // Run the conversion for `v * 2^exp` and call `f(generator)`. - // This function will allocate enough stack space to perform the conversion. - static void RunConversion( - uint128 v, int exp, y_absl::FunctionRef<void(FractionalDigitGenerator)> f) { - using Limits = std::numeric_limits<MaxFloatType>; - assert(-exp < 0); - assert(-exp >= Limits::min_exponent - 128); - static_assert(StackArray::kMaxCapacity >= - (Limits::digits + 128 - Limits::min_exponent + 31) / 32, - ""); - StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32, - [=](y_absl::Span<uint32_t> input) { - f(FractionalDigitGenerator(input, v, exp)); - }); - } - - // Returns true if there are any more non-zero digits left. - bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; } - - // Returns true if the remainder digits are greater than 5000... - bool IsGreaterThanHalf() const { - return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0); - } - // Returns true if the remainder digits are exactly 5000... - bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; } - - struct Digits { - int digit_before_nine; - int num_nines; - }; - - // Get the next set of digits. - // They are composed by a non-9 digit followed by a runs of zero or more 9s. - Digits GetDigits() { - Digits digits{next_digit_, 0}; - - next_digit_ = GetOneDigit(); - while (next_digit_ == 9) { - ++digits.num_nines; - next_digit_ = GetOneDigit(); - } - - return digits; - } - - private: - // Return the next digit. - int GetOneDigit() { - if (chunk_index_ < 0) return 0; - - uint32_t carry = 0; - for (int i = chunk_index_; i >= 0; --i) { - carry = MultiplyBy10WithCarry(&data_[i], carry); - } - // If the lowest chunk is now empty, remove it from view. - if (data_[chunk_index_] == 0) --chunk_index_; - return carry; - } - - FractionalDigitGenerator(y_absl::Span<uint32_t> data, uint128 v, int exp) - : chunk_index_(exp / 32), data_(data) { - const int offset = exp % 32; - // Right shift `v` by `exp` bits. - data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset)); - v >>= offset; - // Make sure we don't overflow the data. We already calculated that - // non-zero bits fit, so we might not have space for leading zero bits. - for (int pos = chunk_index_; v; v >>= 32) - data_[--pos] = static_cast<uint32_t>(v); - - // Fill next_digit_, as GetDigits expects it to be populated always. - next_digit_ = GetOneDigit(); - } - - int next_digit_; - int chunk_index_; - y_absl::Span<uint32_t> data_; -}; - -// Count the number of leading zero bits. -int LeadingZeros(uint64_t v) { return countl_zero(v); } -int LeadingZeros(uint128 v) { - auto high = static_cast<uint64_t>(v >> 64); - auto low = static_cast<uint64_t>(v); - return high != 0 ? countl_zero(high) : 64 + countl_zero(low); -} - -// Round up the text digits starting at `p`. -// The buffer must have an extra digit that is known to not need rounding. -// This is done below by having an extra '0' digit on the left. -void RoundUp(char *p) { - while (*p == '9' || *p == '.') { - if (*p == '9') *p = '0'; - --p; - } - ++*p; -} - -// Check the previous digit and round up or down to follow the round-to-even -// policy. -void RoundToEven(char *p) { - if (*p == '.') --p; - if (*p % 2 == 1) RoundUp(p); -} - -// Simple integral decimal digit printing for values that fit in 64-bits. -// Returns the pointer to the last written digit. -char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) { - do { - *--p = DivideBy10WithCarry(&v, 0) + '0'; - } while (v != 0); - return p; -} - -// Simple integral decimal digit printing for values that fit in 128-bits. -// Returns the pointer to the last written digit. -char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) { - auto high = static_cast<uint64_t>(v >> 64); - auto low = static_cast<uint64_t>(v); - - while (high != 0) { - uint64_t carry = DivideBy10WithCarry(&high, 0); - carry = DivideBy10WithCarry(&low, carry); - *--p = carry + '0'; - } - return PrintIntegralDigitsFromRightFast(low, p); -} - -// Simple fractional decimal digit printing for values that fir in 64-bits after -// shifting. -// Performs rounding if necessary to fit within `precision`. -// Returns the pointer to one after the last character written. -char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp, - int precision) { - char *p = start; - v <<= (64 - exp); - while (precision > 0) { - if (!v) return p; - *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0'; - --precision; - } - - // We need to round. - if (v < 0x8000000000000000) { - // We round down, so nothing to do. - } else if (v > 0x8000000000000000) { - // We round up. - RoundUp(p - 1); - } else { - RoundToEven(p - 1); - } - - assert(precision == 0); - // Precision can only be zero here. - return p; -} - -// Simple fractional decimal digit printing for values that fir in 128-bits -// after shifting. -// Performs rounding if necessary to fit within `precision`. -// Returns the pointer to one after the last character written. -char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, - int precision) { - char *p = start; - v <<= (128 - exp); - auto high = static_cast<uint64_t>(v >> 64); - auto low = static_cast<uint64_t>(v); - - // While we have digits to print and `low` is not empty, do the long - // multiplication. - while (precision > 0 && low != 0) { - uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0}); - carry = MultiplyBy10WithCarry(&high, carry); - - *p++ = carry + '0'; - --precision; - } - - // Now `low` is empty, so use a faster approach for the rest of the digits. - // This block is pretty much the same as the main loop for the 64-bit case - // above. - while (precision > 0) { - if (!high) return p; - *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0'; - --precision; - } - - // We need to round. - if (high < 0x8000000000000000) { - // We round down, so nothing to do. - } else if (high > 0x8000000000000000 || low != 0) { - // We round up. - RoundUp(p - 1); - } else { - RoundToEven(p - 1); - } - - assert(precision == 0); - // Precision can only be zero here. - return p; -} - -struct FormatState { - char sign_char; - int precision; - const FormatConversionSpecImpl &conv; - FormatSinkImpl *sink; - - // In `alt` mode (flag #) we keep the `.` even if there are no fractional - // digits. In non-alt mode, we strip it. - bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); } -}; - -struct Padding { - int left_spaces; - int zeros; - int right_spaces; -}; - -Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) { - if (state.conv.width() < 0 || - static_cast<size_t>(state.conv.width()) <= total_size) { - return {0, 0, 0}; - } - int missing_chars = state.conv.width() - total_size; - if (state.conv.has_left_flag()) { - return {0, 0, missing_chars}; - } else if (state.conv.has_zero_flag()) { - return {0, missing_chars, 0}; - } else { - return {missing_chars, 0, 0}; - } -} - -void FinalPrint(const FormatState &state, y_absl::string_view data, - int padding_offset, int trailing_zeros, - y_absl::string_view data_postfix) { - if (state.conv.width() < 0) { - // No width specified. Fast-path. - if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); - state.sink->Append(data); - state.sink->Append(trailing_zeros, '0'); - state.sink->Append(data_postfix); - return; - } - - auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + - data.size() + data_postfix.size() + - static_cast<size_t>(trailing_zeros), - state); - - state.sink->Append(padding.left_spaces, ' '); - if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); - // Padding in general needs to be inserted somewhere in the middle of `data`. - state.sink->Append(data.substr(0, padding_offset)); - state.sink->Append(padding.zeros, '0'); - state.sink->Append(data.substr(padding_offset)); - state.sink->Append(trailing_zeros, '0'); - state.sink->Append(data_postfix); - state.sink->Append(padding.right_spaces, ' '); -} - -// Fastpath %f formatter for when the shifted value fits in a simple integral -// type. -// Prints `v*2^exp` with the options from `state`. -template <typename Int> -void FormatFFast(Int v, int exp, const FormatState &state) { - constexpr int input_bits = sizeof(Int) * 8; - - static constexpr size_t integral_size = - /* in case we need to round up an extra digit */ 1 + - /* decimal digits for uint128 */ 40 + 1; - char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128]; - buffer[integral_size] = '.'; - char *const integral_digits_end = buffer + integral_size; - char *integral_digits_start; - char *const fractional_digits_start = buffer + integral_size + 1; - char *fractional_digits_end = fractional_digits_start; - - if (exp >= 0) { - const int total_bits = input_bits - LeadingZeros(v) + exp; - integral_digits_start = - total_bits <= 64 - ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp, - integral_digits_end) - : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp, - integral_digits_end); - } else { - exp = -exp; - - integral_digits_start = PrintIntegralDigitsFromRightFast( - exp < input_bits ? v >> exp : 0, integral_digits_end); - // PrintFractionalDigits may pull a carried 1 all the way up through the - // integral portion. - integral_digits_start[-1] = '0'; - - fractional_digits_end = - exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp, - state.precision) - : PrintFractionalDigitsFast(static_cast<uint128>(v), - fractional_digits_start, exp, - state.precision); - // There was a carry, so include the first digit too. - if (integral_digits_start[-1] != '0') --integral_digits_start; - } - - size_t size = fractional_digits_end - integral_digits_start; - - // In `alt` mode (flag #) we keep the `.` even if there are no fractional - // digits. In non-alt mode, we strip it. - if (!state.ShouldPrintDot()) --size; - FinalPrint(state, y_absl::string_view(integral_digits_start, size), - /*padding_offset=*/0, - static_cast<int>(state.precision - (fractional_digits_end - - fractional_digits_start)), - /*data_postfix=*/""); -} - -// Slow %f formatter for when the shifted value does not fit in a uint128, and -// `exp > 0`. -// Prints `v*2^exp` with the options from `state`. -// This one is guaranteed to not have fractional digits, so we don't have to -// worry about anything after the `.`. -void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) { - BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) { - const size_t total_digits = - btd.TotalDigits() + - (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0); - - const auto padding = ExtraWidthToPadding( - total_digits + (state.sign_char != '\0' ? 1 : 0), state); - - state.sink->Append(padding.left_spaces, ' '); - if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); - state.sink->Append(padding.zeros, '0'); - - do { - state.sink->Append(btd.CurrentDigits()); - } while (btd.AdvanceDigits()); - - if (state.ShouldPrintDot()) state.sink->Append(1, '.'); - state.sink->Append(state.precision, '0'); - state.sink->Append(padding.right_spaces, ' '); - }); -} - -// Slow %f formatter for when the shifted value does not fit in a uint128, and -// `exp < 0`. -// Prints `v*2^exp` with the options from `state`. -// This one is guaranteed to be < 1.0, so we don't have to worry about integral -// digits. -void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) { - const size_t total_digits = - /* 0 */ 1 + - (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0); - auto padding = - ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state); - padding.zeros += 1; - state.sink->Append(padding.left_spaces, ' '); - if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); - state.sink->Append(padding.zeros, '0'); - - if (state.ShouldPrintDot()) state.sink->Append(1, '.'); - - // Print digits - int digits_to_go = state.precision; - - FractionalDigitGenerator::RunConversion( - v, exp, [&](FractionalDigitGenerator digit_gen) { - // There are no digits to print here. - if (state.precision == 0) return; - - // We go one digit at a time, while keeping track of runs of nines. - // The runs of nines are used to perform rounding when necessary. - - while (digits_to_go > 0 && digit_gen.HasMoreDigits()) { - auto digits = digit_gen.GetDigits(); - - // Now we have a digit and a run of nines. - // See if we can print them all. - if (digits.num_nines + 1 < digits_to_go) { - // We don't have to round yet, so print them. - state.sink->Append(1, digits.digit_before_nine + '0'); - state.sink->Append(digits.num_nines, '9'); - digits_to_go -= digits.num_nines + 1; - - } else { - // We can't print all the nines, see where we have to truncate. - - bool round_up = false; - if (digits.num_nines + 1 > digits_to_go) { - // We round up at a nine. No need to print them. - round_up = true; - } else { - // We can fit all the nines, but truncate just after it. - if (digit_gen.IsGreaterThanHalf()) { - round_up = true; - } else if (digit_gen.IsExactlyHalf()) { - // Round to even - round_up = - digits.num_nines != 0 || digits.digit_before_nine % 2 == 1; - } - } - - if (round_up) { - state.sink->Append(1, digits.digit_before_nine + '1'); - --digits_to_go; - // The rest will be zeros. - } else { - state.sink->Append(1, digits.digit_before_nine + '0'); - state.sink->Append(digits_to_go - 1, '9'); - digits_to_go = 0; - } - return; - } - } - }); - - state.sink->Append(digits_to_go, '0'); - state.sink->Append(padding.right_spaces, ' '); -} - -template <typename Int> -void FormatF(Int mantissa, int exp, const FormatState &state) { - if (exp >= 0) { - const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp; - - // Fallback to the slow stack-based approach if we can't do it in a 64 or - // 128 bit state. - if (ABSL_PREDICT_FALSE(total_bits > 128)) { - return FormatFPositiveExpSlow(mantissa, exp, state); - } - } else { - // Fallback to the slow stack-based approach if we can't do it in a 64 or - // 128 bit state. - if (ABSL_PREDICT_FALSE(exp < -128)) { - return FormatFNegativeExpSlow(mantissa, -exp, state); - } - } - return FormatFFast(mantissa, exp, state); -} - -// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to -// bits 4-7. -template <typename Int> -uint8_t GetNibble(Int n, int nibble_index) { - constexpr Int mask_low_nibble = Int{0xf}; - int shift = nibble_index * 4; - n &= mask_low_nibble << shift; - return static_cast<uint8_t>((n >> shift) & 0xf); -} - -// Add one to the given nibble, applying carry to higher nibbles. Returns true -// if overflow, false otherwise. -template <typename Int> -bool IncrementNibble(int nibble_index, Int *n) { - constexpr int kShift = sizeof(Int) * 8 - 1; - constexpr int kNumNibbles = sizeof(Int) * 8 / 4; - Int before = *n >> kShift; - // Here we essentially want to take the number 1 and move it into the requsted - // nibble, then add it to *n to effectively increment the nibble. However, - // ASan will complain if we try to shift the 1 beyond the limits of the Int, - // i.e., if the nibble_index is out of range. So therefore we check for this - // and if we are out of range we just add 0 which leaves *n unchanged, which - // seems like the reasonable thing to do in that case. - *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4))); - Int after = *n >> kShift; - return (before && !after) || (nibble_index >= kNumNibbles); -} - -// Return a mask with 1's in the given nibble and all lower nibbles. -template <typename Int> -Int MaskUpToNibbleInclusive(int nibble_index) { - constexpr int kNumNibbles = sizeof(Int) * 8 / 4; - static const Int ones = ~Int{0}; - return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1)); -} - -// Return a mask with 1's below the given nibble. -template <typename Int> -Int MaskUpToNibbleExclusive(int nibble_index) { - return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1); -} - -template <typename Int> -Int MoveToNibble(uint8_t nibble, int nibble_index) { - return Int{nibble} << (4 * nibble_index); -} - -// Given mantissa size, find optimal # of mantissa bits to put in initial digit. -// -// In the hex representation we keep a single hex digit to the left of the dot. -// However, the question as to how many bits of the mantissa should be put into -// that hex digit in theory is arbitrary, but in practice it is optimal to -// choose based on the size of the mantissa. E.g., for a `double`, there are 53 -// mantissa bits, so that means that we should put 1 bit to the left of the dot, -// thereby leaving 52 bits to the right, which is evenly divisible by four and -// thus all fractional digits represent actual precision. For a `long double`, -// on the other hand, there are 64 bits of mantissa, thus we can use all four -// bits for the initial hex digit and still have a number left over (60) that is -// a multiple of four. Once again, the goal is to have all fractional digits -// represent real precision. -template <typename Float> -constexpr int HexFloatLeadingDigitSizeInBits() { - return std::numeric_limits<Float>::digits % 4 > 0 - ? std::numeric_limits<Float>::digits % 4 - : 4; -} - -// This function captures the rounding behavior of glibc for hex float -// representations. E.g. when rounding 0x1.ab800000 to a precision of .2 -// ("%.2a") glibc will round up because it rounds toward the even number (since -// 0xb is an odd number, it will round up to 0xc). However, when rounding at a -// point that is not followed by 800000..., it disregards the parity and rounds -// up if > 8 and rounds down if < 8. -template <typename Int> -bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed, - uint8_t leading) { - // If the last nibble (hex digit) to be displayed is the lowest on in the - // mantissa then that means that we don't have any further nibbles to inform - // rounding, so don't round. - if (final_nibble_displayed <= 0) { - return false; - } - int rounding_nibble_idx = final_nibble_displayed - 1; - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; - assert(final_nibble_displayed <= kTotalNibbles); - Int mantissa_up_to_rounding_nibble_inclusive = - mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx); - Int eight = MoveToNibble<Int>(8, rounding_nibble_idx); - if (mantissa_up_to_rounding_nibble_inclusive != eight) { - return mantissa_up_to_rounding_nibble_inclusive > eight; - } - // Nibble in question == 8. - uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles) - ? leading - : GetNibble(mantissa, final_nibble_displayed); - return round_if_odd % 2 == 1; -} - -// Stores values associated with a Float type needed by the FormatA -// implementation in order to avoid templatizing that function by the Float -// type. -struct HexFloatTypeParams { - template <typename Float> - explicit HexFloatTypeParams(Float) - : min_exponent(std::numeric_limits<Float>::min_exponent - 1), - leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) { - assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4); - } - - int min_exponent; - int leading_digit_size_bits; -}; - -// Hex Float Rounding. First check if we need to round; if so, then we do that -// by manipulating (incrementing) the mantissa, that way we can later print the -// mantissa digits by iterating through them in the same way regardless of -// whether a rounding happened. -template <typename Int> -void FormatARound(bool precision_specified, const FormatState &state, - uint8_t *leading, Int *mantissa, int *exp) { - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; - // Index of the last nibble that we could display given precision. - int final_nibble_displayed = - precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0; - if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) { - // Need to round up. - bool overflow = IncrementNibble(final_nibble_displayed, mantissa); - *leading += (overflow ? 1 : 0); - if (ABSL_PREDICT_FALSE(*leading > 15)) { - // We have overflowed the leading digit. This would mean that we would - // need two hex digits to the left of the dot, which is not allowed. So - // adjust the mantissa and exponent so that the result is always 1.0eXXX. - *leading = 1; - *mantissa = 0; - *exp += 4; - } - } - // Now that we have handled a possible round-up we can go ahead and zero out - // all the nibbles of the mantissa that we won't need. - if (precision_specified) { - *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed); - } -} - -template <typename Int> -void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading, - Int *mantissa, int *exp) { - constexpr int kIntBits = sizeof(Int) * 8; - static const Int kHighIntBit = Int{1} << (kIntBits - 1); - const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits; - // Normalize mantissa so that highest bit set is in MSB position, unless we - // get interrupted by the exponent threshold. - while (*mantissa && !(*mantissa & kHighIntBit)) { - if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) { - *mantissa >>= (float_traits.min_exponent - *exp); - *exp = float_traits.min_exponent; - return; - } - *mantissa <<= 1; - --*exp; - } - // Extract bits for leading digit then shift them away leaving the - // fractional part. - *leading = - static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount)); - *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp; - *mantissa <<= kLeadDigitBitsCount; -} - -template <typename Int> -void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, - bool uppercase, const FormatState &state) { - // Int properties. - constexpr int kIntBits = sizeof(Int) * 8; - constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; - // Did the user specify a precision explicitly? - const bool precision_specified = state.conv.precision() >= 0; - - // ========== Normalize/Denormalize ========== - exp += kIntBits; // make all digits fractional digits. - // This holds the (up to four) bits of leading digit, i.e., the '1' in the - // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal. - uint8_t leading = 0; - FormatANormalize(float_traits, &leading, &mantissa, &exp); - - // =============== Rounding ================== - // Check if we need to round; if so, then we do that by manipulating - // (incrementing) the mantissa before beginning to print characters. - FormatARound(precision_specified, state, &leading, &mantissa, &exp); - - // ============= Format Result =============== - // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the - // size with long double which is the largest of the floats. - constexpr size_t kBufSizeForHexFloatRepr = - 2 // 0x - + std::numeric_limits<MaxFloatType>::digits / 4 // number of hex digits - + 1 // round up - + 1; // "." (dot) - char digits_buffer[kBufSizeForHexFloatRepr]; - char *digits_iter = digits_buffer; - const char *const digits = - static_cast<const char *>("0123456789ABCDEF0123456789abcdef") + - (uppercase ? 0 : 16); - - // =============== Hex Prefix ================ - *digits_iter++ = '0'; - *digits_iter++ = uppercase ? 'X' : 'x'; - - // ========== Non-Fractional Digit =========== - *digits_iter++ = digits[leading]; - - // ================== Dot ==================== - // There are three reasons we might need a dot. Keep in mind that, at this - // point, the mantissa holds only the fractional part. - if ((precision_specified && state.precision > 0) || - (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) { - *digits_iter++ = '.'; - } - - // ============ Fractional Digits ============ - int digits_emitted = 0; - while (mantissa > 0) { - *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)]; - mantissa <<= 4; - ++digits_emitted; - } - int trailing_zeros = - precision_specified ? state.precision - digits_emitted : 0; - assert(trailing_zeros >= 0); - auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer); - - // =============== Exponent ================== - constexpr size_t kBufSizeForExpDecRepr = - numbers_internal::kFastToBufferSize // requred for FastIntToBuffer - + 1 // 'p' or 'P' - + 1; // '+' or '-' - char exp_buffer[kBufSizeForExpDecRepr]; - exp_buffer[0] = uppercase ? 'P' : 'p'; - exp_buffer[1] = exp >= 0 ? '+' : '-'; - numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2); - - // ============ Assemble Result ============== - FinalPrint(state, // - digits_result, // 0xN.NNN... - 2, // offset in `data` to start padding if needed. - trailing_zeros, // num remaining mantissa padding zeros - exp_buffer); // exponent -} - -char *CopyStringTo(y_absl::string_view v, char *out) { +using ::y_absl::numeric_internal::IsDoubleDouble; + +// The code below wants to avoid heap allocations. +// To do so it needs to allocate memory on the stack. +// `StackArray` will allocate memory on the stack in the form of a uint32_t +// array and call the provided callback with said memory. +// It will allocate memory in increments of 512 bytes. We could allocate the +// largest needed unconditionally, but that is more than we need in most of +// cases. This way we use less stack in the common cases. +class StackArray { + using Func = y_absl::FunctionRef<void(y_absl::Span<uint32_t>)>; + static constexpr size_t kStep = 512 / sizeof(uint32_t); + // 5 steps is 2560 bytes, which is enough to hold a long double with the + // largest/smallest exponents. + // The operations below will static_assert their particular maximum. + static constexpr size_t kNumSteps = 5; + + // We do not want this function to be inlined. + // Otherwise the caller will allocate the stack space unnecessarily for all + // the variants even though it only calls one. + template <size_t steps> + ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) { + uint32_t values[steps * kStep]{}; + f(y_absl::MakeSpan(values)); + } + + public: + static constexpr size_t kMaxCapacity = kStep * kNumSteps; + + static void RunWithCapacity(size_t capacity, Func f) { + assert(capacity <= kMaxCapacity); + const size_t step = (capacity + kStep - 1) / kStep; + assert(step <= kNumSteps); + switch (step) { + case 1: + return RunWithCapacityImpl<1>(f); + case 2: + return RunWithCapacityImpl<2>(f); + case 3: + return RunWithCapacityImpl<3>(f); + case 4: + return RunWithCapacityImpl<4>(f); + case 5: + return RunWithCapacityImpl<5>(f); + } + + assert(false && "Invalid capacity"); + } +}; + +// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns +// the carry. +template <typename Int> +inline Int MultiplyBy10WithCarry(Int *v, Int carry) { + using BiggerInt = y_absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>; + BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry; + *v = static_cast<Int>(tmp); + return static_cast<Int>(tmp >> (sizeof(Int) * 8)); +} + +// Calculates `(2^64 * carry + *v) / 10`. +// Stores the quotient in `*v` and returns the remainder. +// Requires: `0 <= carry <= 9` +inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) { + constexpr uint64_t divisor = 10; + // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor + constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2); + constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor; + + const uint64_t mod = *v % divisor; + const uint64_t next_carry = chunk_remainder * carry + mod; + *v = *v / divisor + carry * chunk_quotient + next_carry / divisor; + return next_carry % divisor; +} + +using MaxFloatType = + typename std::conditional<IsDoubleDouble(), double, long double>::type; + +// Generates the decimal representation for an integer of the form `v * 2^exp`, +// where `v` and `exp` are both positive integers. +// It generates the digits from the left (ie the most significant digit first) +// to allow for direct printing into the sink. +// +// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`. +class BinaryToDecimal { + static constexpr int ChunksNeeded(int exp) { + // We will left shift a uint128 by `exp` bits, so we need `128+exp` total + // bits. Round up to 32. + // See constructor for details about adding `10%` to the value. + return (128 + exp + 31) / 32 * 11 / 10; + } + + public: + // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`. + // This function will allocate enough stack space to perform the conversion. + static void RunConversion(uint128 v, int exp, + y_absl::FunctionRef<void(BinaryToDecimal)> f) { + assert(exp > 0); + assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent); + static_assert( + static_cast<int>(StackArray::kMaxCapacity) >= + ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent), + ""); + + StackArray::RunWithCapacity( + ChunksNeeded(exp), + [=](y_absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); }); + } + + int TotalDigits() const { + return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk + + CurrentDigits().size()); + } + + // See the current block of digits. + y_absl::string_view CurrentDigits() const { + return y_absl::string_view(digits_ + kDigitsPerChunk - size_, size_); + } + + // Advance the current view of digits. + // Returns `false` when no more digits are available. + bool AdvanceDigits() { + if (decimal_start_ >= decimal_end_) return false; + + uint32_t w = data_[decimal_start_++]; + for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) { + digits_[kDigitsPerChunk - ++size_] = w % 10 + '0'; + } + return true; + } + + private: + BinaryToDecimal(y_absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) { + // We need to print the digits directly into the sink object without + // buffering them all first. To do this we need two things: + // - to know the total number of digits to do padding when necessary + // - to generate the decimal digits from the left. + // + // In order to do this, we do a two pass conversion. + // On the first pass we convert the binary representation of the value into + // a decimal representation in which each uint32_t chunk holds up to 9 + // decimal digits. In the second pass we take each decimal-holding-uint32_t + // value and generate the ascii decimal digits into `digits_`. + // + // The binary and decimal representations actually share the same memory + // region. As we go converting the chunks from binary to decimal we free + // them up and reuse them for the decimal representation. One caveat is that + // the decimal representation is around 7% less efficient in space than the + // binary one. We allocate an extra 10% memory to account for this. See + // ChunksNeeded for this calculation. + int chunk_index = exp / 32; + decimal_start_ = decimal_end_ = ChunksNeeded(exp); + const int offset = exp % 32; + // Left shift v by exp bits. + data_[chunk_index] = static_cast<uint32_t>(v << offset); + for (v >>= (32 - offset); v; v >>= 32) + data_[++chunk_index] = static_cast<uint32_t>(v); + + while (chunk_index >= 0) { + // While we have more than one chunk available, go in steps of 1e9. + // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep + // the variable updated. + uint32_t carry = 0; + for (int i = chunk_index; i >= 0; --i) { + uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32); + data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000}); + carry = static_cast<uint32_t>(tmp % uint64_t{1000000000}); + } + + // If the highest chunk is now empty, remove it from view. + if (data_[chunk_index] == 0) --chunk_index; + + --decimal_start_; + assert(decimal_start_ != chunk_index); + data_[decimal_start_] = carry; + } + + // Fill the first set of digits. The first chunk might not be complete, so + // handle differently. + for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) { + digits_[kDigitsPerChunk - ++size_] = first % 10 + '0'; + } + } + + private: + static constexpr int kDigitsPerChunk = 9; + + int decimal_start_; + int decimal_end_; + + char digits_[kDigitsPerChunk]; + int size_ = 0; + + y_absl::Span<uint32_t> data_; +}; + +// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits. +// Requires `-exp < 0` and +// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`. +class FractionalDigitGenerator { + public: + // Run the conversion for `v * 2^exp` and call `f(generator)`. + // This function will allocate enough stack space to perform the conversion. + static void RunConversion( + uint128 v, int exp, y_absl::FunctionRef<void(FractionalDigitGenerator)> f) { + using Limits = std::numeric_limits<MaxFloatType>; + assert(-exp < 0); + assert(-exp >= Limits::min_exponent - 128); + static_assert(StackArray::kMaxCapacity >= + (Limits::digits + 128 - Limits::min_exponent + 31) / 32, + ""); + StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32, + [=](y_absl::Span<uint32_t> input) { + f(FractionalDigitGenerator(input, v, exp)); + }); + } + + // Returns true if there are any more non-zero digits left. + bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; } + + // Returns true if the remainder digits are greater than 5000... + bool IsGreaterThanHalf() const { + return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0); + } + // Returns true if the remainder digits are exactly 5000... + bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; } + + struct Digits { + int digit_before_nine; + int num_nines; + }; + + // Get the next set of digits. + // They are composed by a non-9 digit followed by a runs of zero or more 9s. + Digits GetDigits() { + Digits digits{next_digit_, 0}; + + next_digit_ = GetOneDigit(); + while (next_digit_ == 9) { + ++digits.num_nines; + next_digit_ = GetOneDigit(); + } + + return digits; + } + + private: + // Return the next digit. + int GetOneDigit() { + if (chunk_index_ < 0) return 0; + + uint32_t carry = 0; + for (int i = chunk_index_; i >= 0; --i) { + carry = MultiplyBy10WithCarry(&data_[i], carry); + } + // If the lowest chunk is now empty, remove it from view. + if (data_[chunk_index_] == 0) --chunk_index_; + return carry; + } + + FractionalDigitGenerator(y_absl::Span<uint32_t> data, uint128 v, int exp) + : chunk_index_(exp / 32), data_(data) { + const int offset = exp % 32; + // Right shift `v` by `exp` bits. + data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset)); + v >>= offset; + // Make sure we don't overflow the data. We already calculated that + // non-zero bits fit, so we might not have space for leading zero bits. + for (int pos = chunk_index_; v; v >>= 32) + data_[--pos] = static_cast<uint32_t>(v); + + // Fill next_digit_, as GetDigits expects it to be populated always. + next_digit_ = GetOneDigit(); + } + + int next_digit_; + int chunk_index_; + y_absl::Span<uint32_t> data_; +}; + +// Count the number of leading zero bits. +int LeadingZeros(uint64_t v) { return countl_zero(v); } +int LeadingZeros(uint128 v) { + auto high = static_cast<uint64_t>(v >> 64); + auto low = static_cast<uint64_t>(v); + return high != 0 ? countl_zero(high) : 64 + countl_zero(low); +} + +// Round up the text digits starting at `p`. +// The buffer must have an extra digit that is known to not need rounding. +// This is done below by having an extra '0' digit on the left. +void RoundUp(char *p) { + while (*p == '9' || *p == '.') { + if (*p == '9') *p = '0'; + --p; + } + ++*p; +} + +// Check the previous digit and round up or down to follow the round-to-even +// policy. +void RoundToEven(char *p) { + if (*p == '.') --p; + if (*p % 2 == 1) RoundUp(p); +} + +// Simple integral decimal digit printing for values that fit in 64-bits. +// Returns the pointer to the last written digit. +char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) { + do { + *--p = DivideBy10WithCarry(&v, 0) + '0'; + } while (v != 0); + return p; +} + +// Simple integral decimal digit printing for values that fit in 128-bits. +// Returns the pointer to the last written digit. +char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) { + auto high = static_cast<uint64_t>(v >> 64); + auto low = static_cast<uint64_t>(v); + + while (high != 0) { + uint64_t carry = DivideBy10WithCarry(&high, 0); + carry = DivideBy10WithCarry(&low, carry); + *--p = carry + '0'; + } + return PrintIntegralDigitsFromRightFast(low, p); +} + +// Simple fractional decimal digit printing for values that fir in 64-bits after +// shifting. +// Performs rounding if necessary to fit within `precision`. +// Returns the pointer to one after the last character written. +char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp, + int precision) { + char *p = start; + v <<= (64 - exp); + while (precision > 0) { + if (!v) return p; + *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0'; + --precision; + } + + // We need to round. + if (v < 0x8000000000000000) { + // We round down, so nothing to do. + } else if (v > 0x8000000000000000) { + // We round up. + RoundUp(p - 1); + } else { + RoundToEven(p - 1); + } + + assert(precision == 0); + // Precision can only be zero here. + return p; +} + +// Simple fractional decimal digit printing for values that fir in 128-bits +// after shifting. +// Performs rounding if necessary to fit within `precision`. +// Returns the pointer to one after the last character written. +char *PrintFractionalDigitsFast(uint128 v, char *start, int exp, + int precision) { + char *p = start; + v <<= (128 - exp); + auto high = static_cast<uint64_t>(v >> 64); + auto low = static_cast<uint64_t>(v); + + // While we have digits to print and `low` is not empty, do the long + // multiplication. + while (precision > 0 && low != 0) { + uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0}); + carry = MultiplyBy10WithCarry(&high, carry); + + *p++ = carry + '0'; + --precision; + } + + // Now `low` is empty, so use a faster approach for the rest of the digits. + // This block is pretty much the same as the main loop for the 64-bit case + // above. + while (precision > 0) { + if (!high) return p; + *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0'; + --precision; + } + + // We need to round. + if (high < 0x8000000000000000) { + // We round down, so nothing to do. + } else if (high > 0x8000000000000000 || low != 0) { + // We round up. + RoundUp(p - 1); + } else { + RoundToEven(p - 1); + } + + assert(precision == 0); + // Precision can only be zero here. + return p; +} + +struct FormatState { + char sign_char; + int precision; + const FormatConversionSpecImpl &conv; + FormatSinkImpl *sink; + + // In `alt` mode (flag #) we keep the `.` even if there are no fractional + // digits. In non-alt mode, we strip it. + bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); } +}; + +struct Padding { + int left_spaces; + int zeros; + int right_spaces; +}; + +Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) { + if (state.conv.width() < 0 || + static_cast<size_t>(state.conv.width()) <= total_size) { + return {0, 0, 0}; + } + int missing_chars = state.conv.width() - total_size; + if (state.conv.has_left_flag()) { + return {0, 0, missing_chars}; + } else if (state.conv.has_zero_flag()) { + return {0, missing_chars, 0}; + } else { + return {missing_chars, 0, 0}; + } +} + +void FinalPrint(const FormatState &state, y_absl::string_view data, + int padding_offset, int trailing_zeros, + y_absl::string_view data_postfix) { + if (state.conv.width() < 0) { + // No width specified. Fast-path. + if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); + state.sink->Append(data); + state.sink->Append(trailing_zeros, '0'); + state.sink->Append(data_postfix); + return; + } + + auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + + data.size() + data_postfix.size() + + static_cast<size_t>(trailing_zeros), + state); + + state.sink->Append(padding.left_spaces, ' '); + if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); + // Padding in general needs to be inserted somewhere in the middle of `data`. + state.sink->Append(data.substr(0, padding_offset)); + state.sink->Append(padding.zeros, '0'); + state.sink->Append(data.substr(padding_offset)); + state.sink->Append(trailing_zeros, '0'); + state.sink->Append(data_postfix); + state.sink->Append(padding.right_spaces, ' '); +} + +// Fastpath %f formatter for when the shifted value fits in a simple integral +// type. +// Prints `v*2^exp` with the options from `state`. +template <typename Int> +void FormatFFast(Int v, int exp, const FormatState &state) { + constexpr int input_bits = sizeof(Int) * 8; + + static constexpr size_t integral_size = + /* in case we need to round up an extra digit */ 1 + + /* decimal digits for uint128 */ 40 + 1; + char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128]; + buffer[integral_size] = '.'; + char *const integral_digits_end = buffer + integral_size; + char *integral_digits_start; + char *const fractional_digits_start = buffer + integral_size + 1; + char *fractional_digits_end = fractional_digits_start; + + if (exp >= 0) { + const int total_bits = input_bits - LeadingZeros(v) + exp; + integral_digits_start = + total_bits <= 64 + ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp, + integral_digits_end) + : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp, + integral_digits_end); + } else { + exp = -exp; + + integral_digits_start = PrintIntegralDigitsFromRightFast( + exp < input_bits ? v >> exp : 0, integral_digits_end); + // PrintFractionalDigits may pull a carried 1 all the way up through the + // integral portion. + integral_digits_start[-1] = '0'; + + fractional_digits_end = + exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp, + state.precision) + : PrintFractionalDigitsFast(static_cast<uint128>(v), + fractional_digits_start, exp, + state.precision); + // There was a carry, so include the first digit too. + if (integral_digits_start[-1] != '0') --integral_digits_start; + } + + size_t size = fractional_digits_end - integral_digits_start; + + // In `alt` mode (flag #) we keep the `.` even if there are no fractional + // digits. In non-alt mode, we strip it. + if (!state.ShouldPrintDot()) --size; + FinalPrint(state, y_absl::string_view(integral_digits_start, size), + /*padding_offset=*/0, + static_cast<int>(state.precision - (fractional_digits_end - + fractional_digits_start)), + /*data_postfix=*/""); +} + +// Slow %f formatter for when the shifted value does not fit in a uint128, and +// `exp > 0`. +// Prints `v*2^exp` with the options from `state`. +// This one is guaranteed to not have fractional digits, so we don't have to +// worry about anything after the `.`. +void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) { + BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) { + const size_t total_digits = + btd.TotalDigits() + + (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0); + + const auto padding = ExtraWidthToPadding( + total_digits + (state.sign_char != '\0' ? 1 : 0), state); + + state.sink->Append(padding.left_spaces, ' '); + if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); + state.sink->Append(padding.zeros, '0'); + + do { + state.sink->Append(btd.CurrentDigits()); + } while (btd.AdvanceDigits()); + + if (state.ShouldPrintDot()) state.sink->Append(1, '.'); + state.sink->Append(state.precision, '0'); + state.sink->Append(padding.right_spaces, ' '); + }); +} + +// Slow %f formatter for when the shifted value does not fit in a uint128, and +// `exp < 0`. +// Prints `v*2^exp` with the options from `state`. +// This one is guaranteed to be < 1.0, so we don't have to worry about integral +// digits. +void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) { + const size_t total_digits = + /* 0 */ 1 + + (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0); + auto padding = + ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state); + padding.zeros += 1; + state.sink->Append(padding.left_spaces, ' '); + if (state.sign_char != '\0') state.sink->Append(1, state.sign_char); + state.sink->Append(padding.zeros, '0'); + + if (state.ShouldPrintDot()) state.sink->Append(1, '.'); + + // Print digits + int digits_to_go = state.precision; + + FractionalDigitGenerator::RunConversion( + v, exp, [&](FractionalDigitGenerator digit_gen) { + // There are no digits to print here. + if (state.precision == 0) return; + + // We go one digit at a time, while keeping track of runs of nines. + // The runs of nines are used to perform rounding when necessary. + + while (digits_to_go > 0 && digit_gen.HasMoreDigits()) { + auto digits = digit_gen.GetDigits(); + + // Now we have a digit and a run of nines. + // See if we can print them all. + if (digits.num_nines + 1 < digits_to_go) { + // We don't have to round yet, so print them. + state.sink->Append(1, digits.digit_before_nine + '0'); + state.sink->Append(digits.num_nines, '9'); + digits_to_go -= digits.num_nines + 1; + + } else { + // We can't print all the nines, see where we have to truncate. + + bool round_up = false; + if (digits.num_nines + 1 > digits_to_go) { + // We round up at a nine. No need to print them. + round_up = true; + } else { + // We can fit all the nines, but truncate just after it. + if (digit_gen.IsGreaterThanHalf()) { + round_up = true; + } else if (digit_gen.IsExactlyHalf()) { + // Round to even + round_up = + digits.num_nines != 0 || digits.digit_before_nine % 2 == 1; + } + } + + if (round_up) { + state.sink->Append(1, digits.digit_before_nine + '1'); + --digits_to_go; + // The rest will be zeros. + } else { + state.sink->Append(1, digits.digit_before_nine + '0'); + state.sink->Append(digits_to_go - 1, '9'); + digits_to_go = 0; + } + return; + } + } + }); + + state.sink->Append(digits_to_go, '0'); + state.sink->Append(padding.right_spaces, ' '); +} + +template <typename Int> +void FormatF(Int mantissa, int exp, const FormatState &state) { + if (exp >= 0) { + const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp; + + // Fallback to the slow stack-based approach if we can't do it in a 64 or + // 128 bit state. + if (ABSL_PREDICT_FALSE(total_bits > 128)) { + return FormatFPositiveExpSlow(mantissa, exp, state); + } + } else { + // Fallback to the slow stack-based approach if we can't do it in a 64 or + // 128 bit state. + if (ABSL_PREDICT_FALSE(exp < -128)) { + return FormatFNegativeExpSlow(mantissa, -exp, state); + } + } + return FormatFFast(mantissa, exp, state); +} + +// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to +// bits 4-7. +template <typename Int> +uint8_t GetNibble(Int n, int nibble_index) { + constexpr Int mask_low_nibble = Int{0xf}; + int shift = nibble_index * 4; + n &= mask_low_nibble << shift; + return static_cast<uint8_t>((n >> shift) & 0xf); +} + +// Add one to the given nibble, applying carry to higher nibbles. Returns true +// if overflow, false otherwise. +template <typename Int> +bool IncrementNibble(int nibble_index, Int *n) { + constexpr int kShift = sizeof(Int) * 8 - 1; + constexpr int kNumNibbles = sizeof(Int) * 8 / 4; + Int before = *n >> kShift; + // Here we essentially want to take the number 1 and move it into the requsted + // nibble, then add it to *n to effectively increment the nibble. However, + // ASan will complain if we try to shift the 1 beyond the limits of the Int, + // i.e., if the nibble_index is out of range. So therefore we check for this + // and if we are out of range we just add 0 which leaves *n unchanged, which + // seems like the reasonable thing to do in that case. + *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4))); + Int after = *n >> kShift; + return (before && !after) || (nibble_index >= kNumNibbles); +} + +// Return a mask with 1's in the given nibble and all lower nibbles. +template <typename Int> +Int MaskUpToNibbleInclusive(int nibble_index) { + constexpr int kNumNibbles = sizeof(Int) * 8 / 4; + static const Int ones = ~Int{0}; + return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1)); +} + +// Return a mask with 1's below the given nibble. +template <typename Int> +Int MaskUpToNibbleExclusive(int nibble_index) { + return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1); +} + +template <typename Int> +Int MoveToNibble(uint8_t nibble, int nibble_index) { + return Int{nibble} << (4 * nibble_index); +} + +// Given mantissa size, find optimal # of mantissa bits to put in initial digit. +// +// In the hex representation we keep a single hex digit to the left of the dot. +// However, the question as to how many bits of the mantissa should be put into +// that hex digit in theory is arbitrary, but in practice it is optimal to +// choose based on the size of the mantissa. E.g., for a `double`, there are 53 +// mantissa bits, so that means that we should put 1 bit to the left of the dot, +// thereby leaving 52 bits to the right, which is evenly divisible by four and +// thus all fractional digits represent actual precision. For a `long double`, +// on the other hand, there are 64 bits of mantissa, thus we can use all four +// bits for the initial hex digit and still have a number left over (60) that is +// a multiple of four. Once again, the goal is to have all fractional digits +// represent real precision. +template <typename Float> +constexpr int HexFloatLeadingDigitSizeInBits() { + return std::numeric_limits<Float>::digits % 4 > 0 + ? std::numeric_limits<Float>::digits % 4 + : 4; +} + +// This function captures the rounding behavior of glibc for hex float +// representations. E.g. when rounding 0x1.ab800000 to a precision of .2 +// ("%.2a") glibc will round up because it rounds toward the even number (since +// 0xb is an odd number, it will round up to 0xc). However, when rounding at a +// point that is not followed by 800000..., it disregards the parity and rounds +// up if > 8 and rounds down if < 8. +template <typename Int> +bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed, + uint8_t leading) { + // If the last nibble (hex digit) to be displayed is the lowest on in the + // mantissa then that means that we don't have any further nibbles to inform + // rounding, so don't round. + if (final_nibble_displayed <= 0) { + return false; + } + int rounding_nibble_idx = final_nibble_displayed - 1; + constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + assert(final_nibble_displayed <= kTotalNibbles); + Int mantissa_up_to_rounding_nibble_inclusive = + mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx); + Int eight = MoveToNibble<Int>(8, rounding_nibble_idx); + if (mantissa_up_to_rounding_nibble_inclusive != eight) { + return mantissa_up_to_rounding_nibble_inclusive > eight; + } + // Nibble in question == 8. + uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles) + ? leading + : GetNibble(mantissa, final_nibble_displayed); + return round_if_odd % 2 == 1; +} + +// Stores values associated with a Float type needed by the FormatA +// implementation in order to avoid templatizing that function by the Float +// type. +struct HexFloatTypeParams { + template <typename Float> + explicit HexFloatTypeParams(Float) + : min_exponent(std::numeric_limits<Float>::min_exponent - 1), + leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) { + assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4); + } + + int min_exponent; + int leading_digit_size_bits; +}; + +// Hex Float Rounding. First check if we need to round; if so, then we do that +// by manipulating (incrementing) the mantissa, that way we can later print the +// mantissa digits by iterating through them in the same way regardless of +// whether a rounding happened. +template <typename Int> +void FormatARound(bool precision_specified, const FormatState &state, + uint8_t *leading, Int *mantissa, int *exp) { + constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + // Index of the last nibble that we could display given precision. + int final_nibble_displayed = + precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0; + if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) { + // Need to round up. + bool overflow = IncrementNibble(final_nibble_displayed, mantissa); + *leading += (overflow ? 1 : 0); + if (ABSL_PREDICT_FALSE(*leading > 15)) { + // We have overflowed the leading digit. This would mean that we would + // need two hex digits to the left of the dot, which is not allowed. So + // adjust the mantissa and exponent so that the result is always 1.0eXXX. + *leading = 1; + *mantissa = 0; + *exp += 4; + } + } + // Now that we have handled a possible round-up we can go ahead and zero out + // all the nibbles of the mantissa that we won't need. + if (precision_specified) { + *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed); + } +} + +template <typename Int> +void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading, + Int *mantissa, int *exp) { + constexpr int kIntBits = sizeof(Int) * 8; + static const Int kHighIntBit = Int{1} << (kIntBits - 1); + const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits; + // Normalize mantissa so that highest bit set is in MSB position, unless we + // get interrupted by the exponent threshold. + while (*mantissa && !(*mantissa & kHighIntBit)) { + if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) { + *mantissa >>= (float_traits.min_exponent - *exp); + *exp = float_traits.min_exponent; + return; + } + *mantissa <<= 1; + --*exp; + } + // Extract bits for leading digit then shift them away leaving the + // fractional part. + *leading = + static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount)); + *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp; + *mantissa <<= kLeadDigitBitsCount; +} + +template <typename Int> +void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp, + bool uppercase, const FormatState &state) { + // Int properties. + constexpr int kIntBits = sizeof(Int) * 8; + constexpr int kTotalNibbles = sizeof(Int) * 8 / 4; + // Did the user specify a precision explicitly? + const bool precision_specified = state.conv.precision() >= 0; + + // ========== Normalize/Denormalize ========== + exp += kIntBits; // make all digits fractional digits. + // This holds the (up to four) bits of leading digit, i.e., the '1' in the + // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal. + uint8_t leading = 0; + FormatANormalize(float_traits, &leading, &mantissa, &exp); + + // =============== Rounding ================== + // Check if we need to round; if so, then we do that by manipulating + // (incrementing) the mantissa before beginning to print characters. + FormatARound(precision_specified, state, &leading, &mantissa, &exp); + + // ============= Format Result =============== + // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the + // size with long double which is the largest of the floats. + constexpr size_t kBufSizeForHexFloatRepr = + 2 // 0x + + std::numeric_limits<MaxFloatType>::digits / 4 // number of hex digits + + 1 // round up + + 1; // "." (dot) + char digits_buffer[kBufSizeForHexFloatRepr]; + char *digits_iter = digits_buffer; + const char *const digits = + static_cast<const char *>("0123456789ABCDEF0123456789abcdef") + + (uppercase ? 0 : 16); + + // =============== Hex Prefix ================ + *digits_iter++ = '0'; + *digits_iter++ = uppercase ? 'X' : 'x'; + + // ========== Non-Fractional Digit =========== + *digits_iter++ = digits[leading]; + + // ================== Dot ==================== + // There are three reasons we might need a dot. Keep in mind that, at this + // point, the mantissa holds only the fractional part. + if ((precision_specified && state.precision > 0) || + (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) { + *digits_iter++ = '.'; + } + + // ============ Fractional Digits ============ + int digits_emitted = 0; + while (mantissa > 0) { + *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)]; + mantissa <<= 4; + ++digits_emitted; + } + int trailing_zeros = + precision_specified ? state.precision - digits_emitted : 0; + assert(trailing_zeros >= 0); + auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer); + + // =============== Exponent ================== + constexpr size_t kBufSizeForExpDecRepr = + numbers_internal::kFastToBufferSize // requred for FastIntToBuffer + + 1 // 'p' or 'P' + + 1; // '+' or '-' + char exp_buffer[kBufSizeForExpDecRepr]; + exp_buffer[0] = uppercase ? 'P' : 'p'; + exp_buffer[1] = exp >= 0 ? '+' : '-'; + numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2); + + // ============ Assemble Result ============== + FinalPrint(state, // + digits_result, // 0xN.NNN... + 2, // offset in `data` to start padding if needed. + trailing_zeros, // num remaining mantissa padding zeros + exp_buffer); // exponent +} + +char *CopyStringTo(y_absl::string_view v, char *out) { std::memcpy(out, v.data(), v.size()); return out + v.size(); } template <typename Float> -bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, +bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { int w = conv.width() >= 0 ? conv.width() : 0; int p = conv.precision() >= 0 ? conv.precision() : -1; @@ -951,17 +951,17 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, if (std::is_same<long double, Float>()) { *fp++ = 'L'; } - *fp++ = FormatConversionCharToChar(conv.conversion_char()); + *fp++ = FormatConversionCharToChar(conv.conversion_char()); *fp = 0; assert(fp < fmt + sizeof(fmt)); } TString space(512, '\0'); - y_absl::string_view result; + y_absl::string_view result; while (true) { int n = snprintf(&space[0], space.size(), fmt, w, p, v); if (n < 0) return false; if (static_cast<size_t>(n) < space.size()) { - result = y_absl::string_view(space.data(), n); + result = y_absl::string_view(space.data(), n); break; } space.resize(n + 1); @@ -1014,24 +1014,24 @@ enum class FormatStyle { Fixed, Precision }; // Otherwise, return false. template <typename Float> bool ConvertNonNumericFloats(char sign_char, Float v, - const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { + const FormatConversionSpecImpl &conv, + FormatSinkImpl *sink) { char text[4], *ptr = text; - if (sign_char != '\0') *ptr++ = sign_char; + if (sign_char != '\0') *ptr++ = sign_char; if (std::isnan(v)) { - ptr = std::copy_n( - FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3, - ptr); + ptr = std::copy_n( + FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3, + ptr); } else if (std::isinf(v)) { - ptr = std::copy_n( - FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3, - ptr); + ptr = std::copy_n( + FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3, + ptr); } else { return false; } return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1, - conv.has_left_flag()); + conv.has_left_flag()); } // Round up the last digit of the value. @@ -1091,12 +1091,12 @@ constexpr bool CanFitMantissa() { template <typename Float> struct Decomposed { - using MantissaType = - y_absl::conditional_t<std::is_same<long double, Float>::value, uint128, - uint64_t>; - static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8, - ""); - MantissaType mantissa; + using MantissaType = + y_absl::conditional_t<std::is_same<long double, Float>::value, uint128, + uint64_t>; + static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8, + ""); + MantissaType mantissa; int exponent; }; @@ -1107,8 +1107,8 @@ Decomposed<Float> Decompose(Float v) { Float m = std::frexp(v, &exp); m = std::ldexp(m, std::numeric_limits<Float>::digits); exp -= std::numeric_limits<Float>::digits; - - return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp}; + + return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp}; } // Print 'digits' as decimal. @@ -1277,32 +1277,32 @@ bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out, return false; } -void WriteBufferToSink(char sign_char, y_absl::string_view str, - const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { +void WriteBufferToSink(char sign_char, y_absl::string_view str, + const FormatConversionSpecImpl &conv, + FormatSinkImpl *sink) { int left_spaces = 0, zeros = 0, right_spaces = 0; int missing_chars = conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) - static_cast<int>(sign_char != 0), 0) : 0; - if (conv.has_left_flag()) { + if (conv.has_left_flag()) { right_spaces = missing_chars; - } else if (conv.has_zero_flag()) { + } else if (conv.has_zero_flag()) { zeros = missing_chars; } else { left_spaces = missing_chars; } sink->Append(left_spaces, ' '); - if (sign_char != '\0') sink->Append(1, sign_char); + if (sign_char != '\0') sink->Append(1, sign_char); sink->Append(zeros, '0'); sink->Append(str); sink->Append(right_spaces, ' '); } template <typename Float> -bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, +bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { // Print the sign or the sign column. Float abs_v = v; @@ -1310,9 +1310,9 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, if (std::signbit(abs_v)) { sign_char = '-'; abs_v = -abs_v; - } else if (conv.has_show_pos_flag()) { + } else if (conv.has_show_pos_flag()) { sign_char = '+'; - } else if (conv.has_sign_col_flag()) { + } else if (conv.has_sign_col_flag()) { sign_char = ' '; } @@ -1329,91 +1329,91 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv, Buffer buffer; - FormatConversionChar c = conv.conversion_char(); - - if (c == FormatConversionCharInternal::f || - c == FormatConversionCharInternal::F) { - FormatF(decomposed.mantissa, decomposed.exponent, - {sign_char, precision, conv, sink}); - return true; - } else if (c == FormatConversionCharInternal::e || - c == FormatConversionCharInternal::E) { - if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, - &exp)) { - return FallbackToSnprintf(v, conv, sink); - } - if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back(); - PrintExponent( - exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e', - &buffer); - } else if (c == FormatConversionCharInternal::g || - c == FormatConversionCharInternal::G) { - precision = std::max(0, precision - 1); - if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, - &exp)) { - return FallbackToSnprintf(v, conv, sink); - } - if (precision + 1 > exp && exp >= -4) { - if (exp < 0) { - // Have 1.23456, needs 0.00123456 - // Move the first digit - buffer.begin[1] = *buffer.begin; - // Add some zeros - for (; exp < -1; ++exp) *buffer.begin-- = '0'; - *buffer.begin-- = '.'; - *buffer.begin = '0'; - } else if (exp > 0) { - // Have 1.23456, needs 1234.56 - // Move the '.' exp positions to the right. - std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2); + FormatConversionChar c = conv.conversion_char(); + + if (c == FormatConversionCharInternal::f || + c == FormatConversionCharInternal::F) { + FormatF(decomposed.mantissa, decomposed.exponent, + {sign_char, precision, conv, sink}); + return true; + } else if (c == FormatConversionCharInternal::e || + c == FormatConversionCharInternal::E) { + if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, + &exp)) { + return FallbackToSnprintf(v, conv, sink); + } + if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back(); + PrintExponent( + exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e', + &buffer); + } else if (c == FormatConversionCharInternal::g || + c == FormatConversionCharInternal::G) { + precision = std::max(0, precision - 1); + if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, + &exp)) { + return FallbackToSnprintf(v, conv, sink); + } + if (precision + 1 > exp && exp >= -4) { + if (exp < 0) { + // Have 1.23456, needs 0.00123456 + // Move the first digit + buffer.begin[1] = *buffer.begin; + // Add some zeros + for (; exp < -1; ++exp) *buffer.begin-- = '0'; + *buffer.begin-- = '.'; + *buffer.begin = '0'; + } else if (exp > 0) { + // Have 1.23456, needs 1234.56 + // Move the '.' exp positions to the right. + std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2); } - exp = 0; - } - if (!conv.has_alt_flag()) { - while (buffer.back() == '0') buffer.pop_back(); - if (buffer.back() == '.') buffer.pop_back(); - } - if (exp) { - PrintExponent( - exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e', - &buffer); - } - } else if (c == FormatConversionCharInternal::a || - c == FormatConversionCharInternal::A) { - bool uppercase = (c == FormatConversionCharInternal::A); - FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa, - decomposed.exponent, uppercase, {sign_char, precision, conv, sink}); - return true; - } else { - return false; + exp = 0; + } + if (!conv.has_alt_flag()) { + while (buffer.back() == '0') buffer.pop_back(); + if (buffer.back() == '.') buffer.pop_back(); + } + if (exp) { + PrintExponent( + exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e', + &buffer); + } + } else if (c == FormatConversionCharInternal::a || + c == FormatConversionCharInternal::A) { + bool uppercase = (c == FormatConversionCharInternal::A); + FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa, + decomposed.exponent, uppercase, {sign_char, precision, conv, sink}); + return true; + } else { + return false; } WriteBufferToSink(sign_char, - y_absl::string_view(buffer.begin, buffer.end - buffer.begin), - conv, sink); + y_absl::string_view(buffer.begin, buffer.end - buffer.begin), + conv, sink); return true; } } // namespace -bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - if (IsDoubleDouble()) { - // This is the `double-double` representation of `long double`. We do not - // handle it natively. Fallback to snprintf. - return FallbackToSnprintf(v, conv, sink); - } - + if (IsDoubleDouble()) { + // This is the `double-double` representation of `long double`. We do not + // handle it natively. Fallback to snprintf. + return FallbackToSnprintf(v, conv, sink); + } + return FloatToSink(v, conv, sink); } -bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { - return FloatToSink(static_cast<double>(v), conv, sink); + return FloatToSink(static_cast<double>(v), conv, sink); } -bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink) { return FloatToSink(v, conv, sink); } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h index d93a415756..44e8ee2da2 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ @@ -21,13 +21,13 @@ namespace y_absl { ABSL_NAMESPACE_BEGIN namespace str_format_internal { -bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink); -bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink); -bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, +bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv, FormatSinkImpl *sink); } // namespace str_format_internal diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h index 8fc46fbafa..ae997ae7f7 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h @@ -82,11 +82,11 @@ inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { sink->Write(v); } -// This is a SFINAE to get a better compiler error message when the type -// is not supported. +// This is a SFINAE to get a better compiler error message when the type +// is not supported. template <typename T> -auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) { - AbslFormatFlush(out, s); +auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) { + AbslFormatFlush(out, s); } } // namespace str_format_internal diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc index af07e32fe5..c48cdc9ea3 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include "y_absl/strings/internal/str_format/parser.h" #include <assert.h> @@ -31,7 +31,7 @@ namespace y_absl { ABSL_NAMESPACE_BEGIN namespace str_format_internal { -using CC = FormatConversionCharInternal; +using CC = FormatConversionCharInternal; using LM = LengthMod; // Abbreviations to fit in the table below. @@ -299,17 +299,17 @@ struct ParsedFormatBase::ParsedFormatConsumer { char* data_pos; }; -ParsedFormatBase::ParsedFormatBase( - string_view format, bool allow_ignored, - std::initializer_list<FormatConversionCharSet> convs) +ParsedFormatBase::ParsedFormatBase( + string_view format, bool allow_ignored, + std::initializer_list<FormatConversionCharSet> convs) : data_(format.empty() ? nullptr : new char[format.size()]) { has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) || !MatchesConversions(allow_ignored, convs); } bool ParsedFormatBase::MatchesConversions( - bool allow_ignored, - std::initializer_list<FormatConversionCharSet> convs) const { + bool allow_ignored, + std::initializer_list<FormatConversionCharSet> convs) const { std::unordered_set<int> used; auto add_if_valid_conv = [&](int pos, char c) { if (static_cast<size_t>(pos) > convs.size() || diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h index ba614bb8b4..4fcdc28c5f 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h @@ -1,17 +1,17 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ @@ -78,7 +78,7 @@ struct UnboundConversion { Flags flags = Flags::kBasic; LengthMod length_mod = LengthMod::none; - FormatConversionChar conv = FormatConversionCharInternal::kNone; + FormatConversionChar conv = FormatConversionCharInternal::kNone; }; // Consume conversion spec prefix (not including '%') of [p, end) if valid. @@ -94,7 +94,7 @@ const char* ConsumeUnboundConversion(const char* p, const char* end, // conversions. class ConvTag { public: - constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT + constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT : tag_(static_cast<uint8_t>(conversion_char)) {} constexpr ConvTag(LengthMod length_mod) // NOLINT : tag_(0x80 | static_cast<uint8_t>(length_mod)) {} @@ -106,11 +106,11 @@ class ConvTag { bool is_length() const { return (tag_ & 0xC0) == 0x80; } bool is_flags() const { return (tag_ & 0xE0) == 0xC0; } - FormatConversionChar as_conv() const { + FormatConversionChar as_conv() const { assert(is_conv()); assert(!is_length()); assert(!is_flags()); - return static_cast<FormatConversionChar>(tag_); + return static_cast<FormatConversionChar>(tag_); } LengthMod as_length() const { assert(!is_conv()); @@ -165,7 +165,7 @@ bool ParseFormatString(string_view src, Consumer consumer) { auto tag = GetTagForChar(percent[1]); if (tag.is_conv()) { if (ABSL_PREDICT_FALSE(next_arg < 0)) { - // This indicates an error in the format string. + // This indicates an error in the format string. // The only way to get `next_arg < 0` here is to have a positional // argument first which sets next_arg to -1 and then a non-positional // argument. @@ -208,9 +208,9 @@ constexpr bool EnsureConstexpr(string_view s) { class ParsedFormatBase { public: - explicit ParsedFormatBase( - string_view format, bool allow_ignored, - std::initializer_list<FormatConversionCharSet> convs); + explicit ParsedFormatBase( + string_view format, bool allow_ignored, + std::initializer_list<FormatConversionCharSet> convs); ParsedFormatBase(const ParsedFormatBase& other) { *this = other; } @@ -257,9 +257,9 @@ class ParsedFormatBase { private: // Returns whether the conversions match and if !allow_ignored it verifies // that all conversions are used by the format. - bool MatchesConversions( - bool allow_ignored, - std::initializer_list<FormatConversionCharSet> convs) const; + bool MatchesConversions( + bool allow_ignored, + std::initializer_list<FormatConversionCharSet> convs) const; struct ParsedFormatConsumer; @@ -304,14 +304,14 @@ class ParsedFormatBase { // This is the only API that allows the user to pass a runtime specified format // string. These factory functions will return NULL if the format does not match // the conversions requested by the user. -template <FormatConversionCharSet... C> +template <FormatConversionCharSet... C> class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { public: explicit ExtendedParsedFormat(string_view format) #ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER __attribute__(( enable_if(str_format_internal::EnsureConstexpr(format), - "Format string is not constexpr."), + "Format string is not constexpr."), enable_if(str_format_internal::ValidFormatImpl<C...>(format), "Format specified does not match the template arguments."))) #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make index ff8069cd0f..2c855146e6 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make @@ -2,15 +2,15 @@ LIBRARY() -OWNER( - somov - g:cpp-contrib -) +OWNER( + somov + g:cpp-contrib +) LICENSE(Apache-2.0) -LICENSE_TEXTS(.yandex_meta/licenses.list.txt) - +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h index 237864c0ed..874f6f1d45 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h @@ -51,9 +51,9 @@ ABSL_NAMESPACE_BEGIN namespace strings_internal { // This class is implicitly constructible from everything that y_absl::string_view -// is implicitly constructible from, except for rvalue strings. This means it -// can be used as a function parameter in places where passing a temporary -// string might cause memory lifetime issues. +// is implicitly constructible from, except for rvalue strings. This means it +// can be used as a function parameter in places where passing a temporary +// string might cause memory lifetime issues. class ConvertibleToStringView { public: ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit) @@ -65,8 +65,8 @@ class ConvertibleToStringView { : value_(s) {} // Disable conversion from rvalue strings. - ConvertibleToStringView(TString&& s) = delete; - ConvertibleToStringView(const TString&& s) = delete; + ConvertibleToStringView(TString&& s) = delete; + ConvertibleToStringView(const TString&& s) = delete; y_absl::string_view value() const { return value_; } @@ -251,11 +251,11 @@ struct SplitterIsConvertibleTo // the split strings: only strings for which the predicate returns true will be // kept. A Predicate object is any unary functor that takes an y_absl::string_view // and returns bool. -// -// The StringType parameter can be either string_view or string, depending on -// whether the Splitter refers to a string stored elsewhere, or if the string -// resides inside the Splitter itself. -template <typename Delimiter, typename Predicate, typename StringType> +// +// The StringType parameter can be either string_view or string, depending on +// whether the Splitter refers to a string stored elsewhere, or if the string +// resides inside the Splitter itself. +template <typename Delimiter, typename Predicate, typename StringType> class Splitter { public: using DelimiterType = Delimiter; @@ -263,12 +263,12 @@ class Splitter { using const_iterator = strings_internal::SplitIterator<Splitter>; using value_type = typename std::iterator_traits<const_iterator>::value_type; - Splitter(StringType input_text, Delimiter d, Predicate p) + Splitter(StringType input_text, Delimiter d, Predicate p) : text_(std::move(input_text)), delimiter_(std::move(d)), predicate_(std::move(p)) {} - y_absl::string_view text() const { return text_; } + y_absl::string_view text() const { return text_; } const Delimiter& delimiter() const { return delimiter_; } const Predicate& predicate() const { return predicate_; } @@ -318,7 +318,7 @@ class Splitter { Container operator()(const Splitter& splitter) const { Container c; auto it = std::inserter(c, c.end()); - for (const auto& sp : splitter) { + for (const auto& sp : splitter) { *it++ = ValueType(sp); } return c; @@ -418,7 +418,7 @@ class Splitter { static iterator ToIter(iterator iter) { return iter; } }; - StringType text_; + StringType text_; Delimiter delimiter_; Predicate predicate_; }; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h index b18e821b49..df4fc0357e 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h @@ -1,64 +1,64 @@ -// Copyright 2020 The Abseil Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ -#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ - -#include "y_absl/meta/type_traits.h" -#include "y_absl/strings/string_view.h" - -namespace y_absl { -ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -// StringConstant<T> represents a compile time string constant. -// It can be accessed via its `y_absl::string_view value` static member. -// It is guaranteed that the `string_view` returned has constant `.data()`, -// constant `.size()` and constant `value[i]` for all `0 <= i < .size()` -// -// The `T` is an opaque type. It is guaranteed that different string constants -// will have different values of `T`. This allows users to associate the string -// constant with other static state at compile time. -// -// Instances should be made using the `MakeStringConstant()` factory function -// below. -template <typename T> -struct StringConstant { - static constexpr y_absl::string_view value = T{}(); - constexpr y_absl::string_view operator()() const { return value; } - - // Check to be sure `view` points to constant data. - // Otherwise, it can't be constant evaluated. - static_assert(value.empty() || 2 * value[0] != 1, - "The input string_view must point to constant data."); -}; - -template <typename T> -constexpr y_absl::string_view StringConstant<T>::value; // NOLINT - -// Factory function for `StringConstant` instances. -// It supports callables that have a constexpr default constructor and a -// constexpr operator(). -// It must return an `y_absl::string_view` or `const char*` pointing to constant -// data. This is validated at compile time. -template <typename T> -constexpr StringConstant<T> MakeStringConstant(T) { - return {}; -} - -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace y_absl - -#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ +// Copyright 2020 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ +#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ + +#include "y_absl/meta/type_traits.h" +#include "y_absl/strings/string_view.h" + +namespace y_absl { +ABSL_NAMESPACE_BEGIN +namespace strings_internal { + +// StringConstant<T> represents a compile time string constant. +// It can be accessed via its `y_absl::string_view value` static member. +// It is guaranteed that the `string_view` returned has constant `.data()`, +// constant `.size()` and constant `value[i]` for all `0 <= i < .size()` +// +// The `T` is an opaque type. It is guaranteed that different string constants +// will have different values of `T`. This allows users to associate the string +// constant with other static state at compile time. +// +// Instances should be made using the `MakeStringConstant()` factory function +// below. +template <typename T> +struct StringConstant { + static constexpr y_absl::string_view value = T{}(); + constexpr y_absl::string_view operator()() const { return value; } + + // Check to be sure `view` points to constant data. + // Otherwise, it can't be constant evaluated. + static_assert(value.empty() || 2 * value[0] != 1, + "The input string_view must point to constant data."); +}; + +template <typename T> +constexpr y_absl::string_view StringConstant<T>::value; // NOLINT + +// Factory function for `StringConstant` instances. +// It supports callables that have a constexpr default constructor and a +// constexpr operator(). +// It must return an `y_absl::string_view` or `const char*` pointing to constant +// data. This is validated at compile time. +template <typename T> +constexpr StringConstant<T> MakeStringConstant(T) { + return {}; +} + +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace y_absl + +#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_ diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc index 3197bdf432..d60b195954 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.cc @@ -19,22 +19,22 @@ namespace y_absl { ABSL_NAMESPACE_BEGIN -bool EqualsIgnoreCase(y_absl::string_view piece1, - y_absl::string_view piece2) noexcept { +bool EqualsIgnoreCase(y_absl::string_view piece1, + y_absl::string_view piece2) noexcept { return (piece1.size() == piece2.size() && 0 == y_absl::strings_internal::memcasecmp(piece1.data(), piece2.data(), piece1.size())); // memcasecmp uses y_absl::ascii_tolower(). } -bool StartsWithIgnoreCase(y_absl::string_view text, - y_absl::string_view prefix) noexcept { +bool StartsWithIgnoreCase(y_absl::string_view text, + y_absl::string_view prefix) noexcept { return (text.size() >= prefix.size()) && EqualsIgnoreCase(text.substr(0, prefix.size()), prefix); } -bool EndsWithIgnoreCase(y_absl::string_view text, - y_absl::string_view suffix) noexcept { +bool EndsWithIgnoreCase(y_absl::string_view text, + y_absl::string_view suffix) noexcept { return (text.size() >= suffix.size()) && EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h index 4709abc93f..65f0f439d0 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/match.h @@ -43,20 +43,20 @@ ABSL_NAMESPACE_BEGIN // StrContains() // // Returns whether a given string `haystack` contains the substring `needle`. -inline bool StrContains(y_absl::string_view haystack, - y_absl::string_view needle) noexcept { +inline bool StrContains(y_absl::string_view haystack, + y_absl::string_view needle) noexcept { return haystack.find(needle, 0) != haystack.npos; } -inline bool StrContains(y_absl::string_view haystack, char needle) noexcept { - return haystack.find(needle) != haystack.npos; -} - +inline bool StrContains(y_absl::string_view haystack, char needle) noexcept { + return haystack.find(needle) != haystack.npos; +} + // StartsWith() // // Returns whether a given string `text` begins with `prefix`. -inline bool StartsWith(y_absl::string_view text, - y_absl::string_view prefix) noexcept { +inline bool StartsWith(y_absl::string_view text, + y_absl::string_view prefix) noexcept { return prefix.empty() || (text.size() >= prefix.size() && memcmp(text.data(), prefix.data(), prefix.size()) == 0); @@ -65,8 +65,8 @@ inline bool StartsWith(y_absl::string_view text, // EndsWith() // // Returns whether a given string `text` ends with `suffix`. -inline bool EndsWith(y_absl::string_view text, - y_absl::string_view suffix) noexcept { +inline bool EndsWith(y_absl::string_view text, + y_absl::string_view suffix) noexcept { return suffix.empty() || (text.size() >= suffix.size() && memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), @@ -77,22 +77,22 @@ inline bool EndsWith(y_absl::string_view text, // // Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring // case in the comparison. -bool EqualsIgnoreCase(y_absl::string_view piece1, - y_absl::string_view piece2) noexcept; +bool EqualsIgnoreCase(y_absl::string_view piece1, + y_absl::string_view piece2) noexcept; // StartsWithIgnoreCase() // // Returns whether a given ASCII string `text` starts with `prefix`, // ignoring case in the comparison. -bool StartsWithIgnoreCase(y_absl::string_view text, - y_absl::string_view prefix) noexcept; +bool StartsWithIgnoreCase(y_absl::string_view text, + y_absl::string_view prefix) noexcept; // EndsWithIgnoreCase() // // Returns whether a given ASCII string `text` ends with `suffix`, ignoring // case in the comparison. -bool EndsWithIgnoreCase(y_absl::string_view text, - y_absl::string_view suffix) noexcept; +bool EndsWithIgnoreCase(y_absl::string_view text, + y_absl::string_view suffix) noexcept; ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc index 528d044fa6..fa7797a415 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.cc @@ -32,7 +32,7 @@ #include "y_absl/base/attributes.h" #include "y_absl/base/internal/raw_logging.h" -#include "y_absl/numeric/bits.h" +#include "y_absl/numeric/bits.h" #include "y_absl/strings/ascii.h" #include "y_absl/strings/charconv.h" #include "y_absl/strings/escaping.h" @@ -46,13 +46,13 @@ ABSL_NAMESPACE_BEGIN bool SimpleAtof(y_absl::string_view str, float* out) { *out = 0.0; str = StripAsciiWhitespace(str); - // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one - // is present, skip it, while avoiding accepting "+-0" as valid. + // std::from_chars doesn't accept an initial +, but SimpleAtof does, so if one + // is present, skip it, while avoiding accepting "+-0" as valid. if (!str.empty() && str[0] == '+') { str.remove_prefix(1); - if (!str.empty() && str[0] == '-') { - return false; - } + if (!str.empty() && str[0] == '-') { + return false; + } } auto result = y_absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { @@ -77,13 +77,13 @@ bool SimpleAtof(y_absl::string_view str, float* out) { bool SimpleAtod(y_absl::string_view str, double* out) { *out = 0.0; str = StripAsciiWhitespace(str); - // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one - // is present, skip it, while avoiding accepting "+-0" as valid. + // std::from_chars doesn't accept an initial +, but SimpleAtod does, so if one + // is present, skip it, while avoiding accepting "+-0" as valid. if (!str.empty() && str[0] == '+') { str.remove_prefix(1); - if (!str.empty() && str[0] == '-') { - return false; - } + if (!str.empty() && str[0] == '-') { + return false; + } } auto result = y_absl::from_chars(str.data(), str.data() + str.size(), *out); if (result.ec == std::errc::invalid_argument) { @@ -313,7 +313,7 @@ static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num, uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); if (bits128_up == 0) return {bits64_127, bits0_63}; - auto shift = static_cast<unsigned>(bit_width(bits128_up)); + auto shift = static_cast<unsigned>(bit_width(bits128_up)); uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); return {hi, lo}; @@ -344,7 +344,7 @@ static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) { 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; result = Mul32(result, powers_of_five[expfive & 15]); - int shift = countl_zero(result.first); + int shift = countl_zero(result.first); if (shift != 0) { result.first = (result.first << shift) + (result.second >> (64 - shift)); result.second = (result.second << shift); @@ -746,18 +746,18 @@ struct LookupTables { X / 35, X / 36, \ } -// This kVmaxOverBase is generated with -// for (int base = 2; base < 37; ++base) { -// y_absl::uint128 max = std::numeric_limits<y_absl::uint128>::max(); -// auto result = max / base; -// std::cout << " MakeUint128(" << y_absl::Uint128High64(result) << "u, " -// << y_absl::Uint128Low64(result) << "u),\n"; -// } -// See https://godbolt.org/z/aneYsb -// +// This kVmaxOverBase is generated with +// for (int base = 2; base < 37; ++base) { +// y_absl::uint128 max = std::numeric_limits<y_absl::uint128>::max(); +// auto result = max / base; +// std::cout << " MakeUint128(" << y_absl::Uint128High64(result) << "u, " +// << y_absl::Uint128Low64(result) << "u),\n"; +// } +// See https://godbolt.org/z/aneYsb +// // uint128& operator/=(uint128) is not constexpr, so hardcode the resulting // array to avoid a static initializer. -template<> +template<> const uint128 LookupTables<uint128>::kVmaxOverBase[] = { 0, 0, @@ -798,111 +798,111 @@ const uint128 LookupTables<uint128>::kVmaxOverBase[] = { MakeUint128(512409557603043100u, 8198552921648689607u), }; -// This kVmaxOverBase generated with -// for (int base = 2; base < 37; ++base) { -// y_absl::int128 max = std::numeric_limits<y_absl::int128>::max(); -// auto result = max / base; -// std::cout << "\tMakeInt128(" << y_absl::Int128High64(result) << ", " -// << y_absl::Int128Low64(result) << "u),\n"; -// } -// See https://godbolt.org/z/7djYWz -// -// int128& operator/=(int128) is not constexpr, so hardcode the resulting array -// to avoid a static initializer. -template<> -const int128 LookupTables<int128>::kVmaxOverBase[] = { - 0, - 0, - MakeInt128(4611686018427387903, 18446744073709551615u), - MakeInt128(3074457345618258602, 12297829382473034410u), - MakeInt128(2305843009213693951, 18446744073709551615u), - MakeInt128(1844674407370955161, 11068046444225730969u), - MakeInt128(1537228672809129301, 6148914691236517205u), - MakeInt128(1317624576693539401, 2635249153387078802u), - MakeInt128(1152921504606846975, 18446744073709551615u), - MakeInt128(1024819115206086200, 16397105843297379214u), - MakeInt128(922337203685477580, 14757395258967641292u), - MakeInt128(838488366986797800, 13415813871788764811u), - MakeInt128(768614336404564650, 12297829382473034410u), - MakeInt128(709490156681136600, 11351842506898185609u), - MakeInt128(658812288346769700, 10540996613548315209u), - MakeInt128(614891469123651720, 9838263505978427528u), - MakeInt128(576460752303423487, 18446744073709551615u), - MakeInt128(542551296285575047, 9765923333140350855u), - MakeInt128(512409557603043100, 8198552921648689607u), - MakeInt128(485440633518672410, 17475862806672206794u), - MakeInt128(461168601842738790, 7378697629483820646u), - MakeInt128(439208192231179800, 7027331075698876806u), - MakeInt128(419244183493398900, 6707906935894382405u), - MakeInt128(401016175515425035, 2406097053092550210u), - MakeInt128(384307168202282325, 6148914691236517205u), - MakeInt128(368934881474191032, 5902958103587056517u), - MakeInt128(354745078340568300, 5675921253449092804u), - MakeInt128(341606371735362066, 17763531330238827482u), - MakeInt128(329406144173384850, 5270498306774157604u), - MakeInt128(318047311615681924, 7633135478776366185u), - MakeInt128(307445734561825860, 4919131752989213764u), - MakeInt128(297528130221121800, 4760450083537948804u), - MakeInt128(288230376151711743, 18446744073709551615u), - MakeInt128(279496122328932600, 4471937957262921603u), - MakeInt128(271275648142787523, 14106333703424951235u), - MakeInt128(263524915338707880, 4216398645419326083u), - MakeInt128(256204778801521550, 4099276460824344803u), -}; - -// This kVminOverBase generated with -// for (int base = 2; base < 37; ++base) { -// y_absl::int128 min = std::numeric_limits<y_absl::int128>::min(); -// auto result = min / base; -// std::cout << "\tMakeInt128(" << y_absl::Int128High64(result) << ", " -// << y_absl::Int128Low64(result) << "u),\n"; -// } -// -// See https://godbolt.org/z/7djYWz -// -// int128& operator/=(int128) is not constexpr, so hardcode the resulting array -// to avoid a static initializer. -template<> -const int128 LookupTables<int128>::kVminOverBase[] = { - 0, - 0, - MakeInt128(-4611686018427387904, 0u), - MakeInt128(-3074457345618258603, 6148914691236517206u), - MakeInt128(-2305843009213693952, 0u), - MakeInt128(-1844674407370955162, 7378697629483820647u), - MakeInt128(-1537228672809129302, 12297829382473034411u), - MakeInt128(-1317624576693539402, 15811494920322472814u), - MakeInt128(-1152921504606846976, 0u), - MakeInt128(-1024819115206086201, 2049638230412172402u), - MakeInt128(-922337203685477581, 3689348814741910324u), - MakeInt128(-838488366986797801, 5030930201920786805u), - MakeInt128(-768614336404564651, 6148914691236517206u), - MakeInt128(-709490156681136601, 7094901566811366007u), - MakeInt128(-658812288346769701, 7905747460161236407u), - MakeInt128(-614891469123651721, 8608480567731124088u), - MakeInt128(-576460752303423488, 0u), - MakeInt128(-542551296285575048, 8680820740569200761u), - MakeInt128(-512409557603043101, 10248191152060862009u), - MakeInt128(-485440633518672411, 970881267037344822u), - MakeInt128(-461168601842738791, 11068046444225730970u), - MakeInt128(-439208192231179801, 11419412998010674810u), - MakeInt128(-419244183493398901, 11738837137815169211u), - MakeInt128(-401016175515425036, 16040647020617001406u), - MakeInt128(-384307168202282326, 12297829382473034411u), - MakeInt128(-368934881474191033, 12543785970122495099u), - MakeInt128(-354745078340568301, 12770822820260458812u), - MakeInt128(-341606371735362067, 683212743470724134u), - MakeInt128(-329406144173384851, 13176245766935394012u), - MakeInt128(-318047311615681925, 10813608594933185431u), - MakeInt128(-307445734561825861, 13527612320720337852u), - MakeInt128(-297528130221121801, 13686293990171602812u), - MakeInt128(-288230376151711744, 0u), - MakeInt128(-279496122328932601, 13974806116446630013u), - MakeInt128(-271275648142787524, 4340410370284600381u), - MakeInt128(-263524915338707881, 14230345428290225533u), - MakeInt128(-256204778801521551, 14347467612885206813u), -}; - +// This kVmaxOverBase generated with +// for (int base = 2; base < 37; ++base) { +// y_absl::int128 max = std::numeric_limits<y_absl::int128>::max(); +// auto result = max / base; +// std::cout << "\tMakeInt128(" << y_absl::Int128High64(result) << ", " +// << y_absl::Int128Low64(result) << "u),\n"; +// } +// See https://godbolt.org/z/7djYWz +// +// int128& operator/=(int128) is not constexpr, so hardcode the resulting array +// to avoid a static initializer. +template<> +const int128 LookupTables<int128>::kVmaxOverBase[] = { + 0, + 0, + MakeInt128(4611686018427387903, 18446744073709551615u), + MakeInt128(3074457345618258602, 12297829382473034410u), + MakeInt128(2305843009213693951, 18446744073709551615u), + MakeInt128(1844674407370955161, 11068046444225730969u), + MakeInt128(1537228672809129301, 6148914691236517205u), + MakeInt128(1317624576693539401, 2635249153387078802u), + MakeInt128(1152921504606846975, 18446744073709551615u), + MakeInt128(1024819115206086200, 16397105843297379214u), + MakeInt128(922337203685477580, 14757395258967641292u), + MakeInt128(838488366986797800, 13415813871788764811u), + MakeInt128(768614336404564650, 12297829382473034410u), + MakeInt128(709490156681136600, 11351842506898185609u), + MakeInt128(658812288346769700, 10540996613548315209u), + MakeInt128(614891469123651720, 9838263505978427528u), + MakeInt128(576460752303423487, 18446744073709551615u), + MakeInt128(542551296285575047, 9765923333140350855u), + MakeInt128(512409557603043100, 8198552921648689607u), + MakeInt128(485440633518672410, 17475862806672206794u), + MakeInt128(461168601842738790, 7378697629483820646u), + MakeInt128(439208192231179800, 7027331075698876806u), + MakeInt128(419244183493398900, 6707906935894382405u), + MakeInt128(401016175515425035, 2406097053092550210u), + MakeInt128(384307168202282325, 6148914691236517205u), + MakeInt128(368934881474191032, 5902958103587056517u), + MakeInt128(354745078340568300, 5675921253449092804u), + MakeInt128(341606371735362066, 17763531330238827482u), + MakeInt128(329406144173384850, 5270498306774157604u), + MakeInt128(318047311615681924, 7633135478776366185u), + MakeInt128(307445734561825860, 4919131752989213764u), + MakeInt128(297528130221121800, 4760450083537948804u), + MakeInt128(288230376151711743, 18446744073709551615u), + MakeInt128(279496122328932600, 4471937957262921603u), + MakeInt128(271275648142787523, 14106333703424951235u), + MakeInt128(263524915338707880, 4216398645419326083u), + MakeInt128(256204778801521550, 4099276460824344803u), +}; + +// This kVminOverBase generated with +// for (int base = 2; base < 37; ++base) { +// y_absl::int128 min = std::numeric_limits<y_absl::int128>::min(); +// auto result = min / base; +// std::cout << "\tMakeInt128(" << y_absl::Int128High64(result) << ", " +// << y_absl::Int128Low64(result) << "u),\n"; +// } +// +// See https://godbolt.org/z/7djYWz +// +// int128& operator/=(int128) is not constexpr, so hardcode the resulting array +// to avoid a static initializer. +template<> +const int128 LookupTables<int128>::kVminOverBase[] = { + 0, + 0, + MakeInt128(-4611686018427387904, 0u), + MakeInt128(-3074457345618258603, 6148914691236517206u), + MakeInt128(-2305843009213693952, 0u), + MakeInt128(-1844674407370955162, 7378697629483820647u), + MakeInt128(-1537228672809129302, 12297829382473034411u), + MakeInt128(-1317624576693539402, 15811494920322472814u), + MakeInt128(-1152921504606846976, 0u), + MakeInt128(-1024819115206086201, 2049638230412172402u), + MakeInt128(-922337203685477581, 3689348814741910324u), + MakeInt128(-838488366986797801, 5030930201920786805u), + MakeInt128(-768614336404564651, 6148914691236517206u), + MakeInt128(-709490156681136601, 7094901566811366007u), + MakeInt128(-658812288346769701, 7905747460161236407u), + MakeInt128(-614891469123651721, 8608480567731124088u), + MakeInt128(-576460752303423488, 0u), + MakeInt128(-542551296285575048, 8680820740569200761u), + MakeInt128(-512409557603043101, 10248191152060862009u), + MakeInt128(-485440633518672411, 970881267037344822u), + MakeInt128(-461168601842738791, 11068046444225730970u), + MakeInt128(-439208192231179801, 11419412998010674810u), + MakeInt128(-419244183493398901, 11738837137815169211u), + MakeInt128(-401016175515425036, 16040647020617001406u), + MakeInt128(-384307168202282326, 12297829382473034411u), + MakeInt128(-368934881474191033, 12543785970122495099u), + MakeInt128(-354745078340568301, 12770822820260458812u), + MakeInt128(-341606371735362067, 683212743470724134u), + MakeInt128(-329406144173384851, 13176245766935394012u), + MakeInt128(-318047311615681925, 10813608594933185431u), + MakeInt128(-307445734561825861, 13527612320720337852u), + MakeInt128(-297528130221121801, 13686293990171602812u), + MakeInt128(-288230376151711744, 0u), + MakeInt128(-279496122328932601, 13974806116446630013u), + MakeInt128(-271275648142787524, 4340410370284600381u), + MakeInt128(-263524915338707881, 14230345428290225533u), + MakeInt128(-256204778801521551, 14347467612885206813u), +}; + template <typename IntType> const IntType LookupTables<IntType>::kVmaxOverBase[] = X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max()); @@ -1072,10 +1072,10 @@ bool safe_strto64_base(y_absl::string_view text, int64_t* value, int base) { return safe_int_internal<int64_t>(text, value, base); } -bool safe_strto128_base(y_absl::string_view text, int128* value, int base) { - return safe_int_internal<y_absl::int128>(text, value, base); -} - +bool safe_strto128_base(y_absl::string_view text, int128* value, int base) { + return safe_int_internal<y_absl::int128>(text, value, base); +} + bool safe_strtou32_base(y_absl::string_view text, uint32_t* value, int base) { return safe_uint_internal<uint32_t>(text, value, base); } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h index ce181d8eb1..b65ab85904 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/numbers.h @@ -54,7 +54,7 @@ #endif #include "y_absl/base/macros.h" #include "y_absl/base/port.h" -#include "y_absl/numeric/bits.h" +#include "y_absl/numeric/bits.h" #include "y_absl/numeric/int128.h" #include "y_absl/strings/string_view.h" @@ -151,11 +151,11 @@ inline void PutTwoDigits(size_t i, char* buf) { } // safe_strto?() functions for implementing SimpleAtoi() - + bool safe_strto32_base(y_absl::string_view text, int32_t* value, int base); bool safe_strto64_base(y_absl::string_view text, int64_t* value, int base); -bool safe_strto128_base(y_absl::string_view text, y_absl::int128* value, - int base); +bool safe_strto128_base(y_absl::string_view text, y_absl::int128* value, + int base); bool safe_strtou32_base(y_absl::string_view text, uint32_t* value, int base); bool safe_strtou64_base(y_absl::string_view text, uint64_t* value, int base); bool safe_strtou128_base(y_absl::string_view text, y_absl::uint128* value, @@ -267,7 +267,7 @@ inline size_t FastHexToBufferZeroPad16(uint64_t val, char* out) { } #endif // | 0x1 so that even 0 has 1 digit. - return 16 - countl_zero(val | 0x1) / 4; + return 16 - countl_zero(val | 0x1) / 4; } } // namespace numbers_internal @@ -278,11 +278,11 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(y_absl::string_view str, int_type* out) { } ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, - y_absl::int128* out) { - return numbers_internal::safe_strto128_base(str, out, 10); -} - -ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, + y_absl::int128* out) { + return numbers_internal::safe_strto128_base(str, out, 10); +} + +ABSL_MUST_USE_RESULT inline bool SimpleAtoi(y_absl::string_view str, y_absl::uint128* out) { return numbers_internal::safe_strtou128_base(str, out, 10); } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc index 9e11702eae..9b154a60b8 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.cc @@ -141,12 +141,12 @@ namespace strings_internal { TString CatPieces(std::initializer_list<y_absl::string_view> pieces) { TString result; size_t total_size = 0; - for (const y_absl::string_view& piece : pieces) total_size += piece.size(); + for (const y_absl::string_view& piece : pieces) total_size += piece.size(); strings_internal::STLStringResizeUninitialized(&result, total_size); char* const begin = &result[0]; char* out = begin; - for (const y_absl::string_view& piece : pieces) { + for (const y_absl::string_view& piece : pieces) { const size_t this_size = piece.size(); if (this_size != 0) { memcpy(out, piece.data(), this_size); @@ -170,7 +170,7 @@ void AppendPieces(TString* dest, std::initializer_list<y_absl::string_view> pieces) { size_t old_size = dest->size(); size_t total_size = old_size; - for (const y_absl::string_view& piece : pieces) { + for (const y_absl::string_view& piece : pieces) { ASSERT_NO_OVERLAP(*dest, piece); total_size += piece.size(); } @@ -178,7 +178,7 @@ void AppendPieces(TString* dest, char* const begin = &(*dest)[0]; char* out = begin + old_size; - for (const y_absl::string_view& piece : pieces) { + for (const y_absl::string_view& piece : pieces) { const size_t this_size = piece.size(); if (this_size != 0) { memcpy(out, piece.data(), this_size); diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h index a77c9ae906..9322fdf3d5 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_cat.h @@ -256,7 +256,7 @@ class AlphaNum { AlphaNum(const TString& str) : piece_(str.data(), str.size()) {} - // Use string literals ":" instead of character literals ':'. + // Use string literals ":" instead of character literals ':'. AlphaNum(char c) = delete; // NOLINT(runtime/explicit) AlphaNum(const AlphaNum&) = delete; diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h index 4079f38fb4..82e9902202 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_format.h @@ -19,7 +19,7 @@ // // The `str_format` library is a typesafe replacement for the family of // `printf()` string formatting routines within the `<cstdio>` standard library -// header. Like the `printf` family, `str_format` uses a "format string" to +// header. Like the `printf` family, `str_format` uses a "format string" to // perform argument substitutions based on types. See the `FormatSpec` section // below for format string documentation. // @@ -57,7 +57,7 @@ // arbitrary sink types: // // * A generic `Format()` function to write outputs to arbitrary sink types, -// which must implement a `FormatRawSink` interface. +// which must implement a `FormatRawSink` interface. // // * A `FormatUntyped()` function that is similar to `Format()` except it is // loosely typed. `FormatUntyped()` is not a template and does not perform @@ -65,7 +65,7 @@ // boolean from a runtime check. // // In addition, the `str_format` library provides extension points for -// augmenting formatting to new types. See "StrFormat Extensions" below. +// augmenting formatting to new types. See "StrFormat Extensions" below. #ifndef ABSL_STRINGS_STR_FORMAT_H_ #define ABSL_STRINGS_STR_FORMAT_H_ @@ -253,8 +253,8 @@ class FormatCountCapture { // argument, etc. template <typename... Args> -using FormatSpec = str_format_internal::FormatSpecTemplate< - str_format_internal::ArgumentToConv<Args>()...>; +using FormatSpec = str_format_internal::FormatSpecTemplate< + str_format_internal::ArgumentToConv<Args>()...>; // ParsedFormat // @@ -281,36 +281,36 @@ using FormatSpec = str_format_internal::FormatSpecTemplate< // } else { // ... error case ... // } - -#if defined(__cpp_nontype_template_parameter_auto) -// If C++17 is available, an 'extended' format is also allowed that can specify -// multiple conversion characters per format argument, using a combination of -// `y_absl::FormatConversionCharSet` enum values (logically a set union) -// via the `|` operator. (Single character-based arguments are still accepted, -// but cannot be combined). Some common conversions also have predefined enum -// values, such as `y_absl::FormatConversionCharSet::kIntegral`. -// -// Example: -// // Extended format supports multiple conversion characters per argument, -// // specified via a combination of `FormatConversionCharSet` enums. -// using MyFormat = y_absl::ParsedFormat<y_absl::FormatConversionCharSet::d | -// y_absl::FormatConversionCharSet::x>; -// MyFormat GetFormat(bool use_hex) { -// if (use_hex) return MyFormat("foo %x bar"); -// return MyFormat("foo %d bar"); -// } -// // `format` can be used with any value that supports 'd' and 'x', -// // like `int`. -// auto format = GetFormat(use_hex); -// value = StringF(format, i); -template <auto... Conv> -using ParsedFormat = y_absl::str_format_internal::ExtendedParsedFormat< - y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; -#else + +#if defined(__cpp_nontype_template_parameter_auto) +// If C++17 is available, an 'extended' format is also allowed that can specify +// multiple conversion characters per format argument, using a combination of +// `y_absl::FormatConversionCharSet` enum values (logically a set union) +// via the `|` operator. (Single character-based arguments are still accepted, +// but cannot be combined). Some common conversions also have predefined enum +// values, such as `y_absl::FormatConversionCharSet::kIntegral`. +// +// Example: +// // Extended format supports multiple conversion characters per argument, +// // specified via a combination of `FormatConversionCharSet` enums. +// using MyFormat = y_absl::ParsedFormat<y_absl::FormatConversionCharSet::d | +// y_absl::FormatConversionCharSet::x>; +// MyFormat GetFormat(bool use_hex) { +// if (use_hex) return MyFormat("foo %x bar"); +// return MyFormat("foo %d bar"); +// } +// // `format` can be used with any value that supports 'd' and 'x', +// // like `int`. +// auto format = GetFormat(use_hex); +// value = StringF(format, i); +template <auto... Conv> +using ParsedFormat = y_absl::str_format_internal::ExtendedParsedFormat< + y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; +#else template <char... Conv> using ParsedFormat = str_format_internal::ExtendedParsedFormat< - y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; -#endif // defined(__cpp_nontype_template_parameter_auto) + y_absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; +#endif // defined(__cpp_nontype_template_parameter_auto) // StrFormat() // @@ -457,16 +457,16 @@ int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, // // FormatRawSink is a type erased wrapper around arbitrary sink objects // specifically used as an argument to `Format()`. -// -// All the object has to do define an overload of `AbslFormatFlush()` for the -// sink, usually by adding a ADL-based free function in the same namespace as -// the sink: -// -// void AbslFormatFlush(MySink* dest, y_absl::string_view part); -// -// where `dest` is the pointer passed to `y_absl::Format()`. The function should -// append `part` to `dest`. -// +// +// All the object has to do define an overload of `AbslFormatFlush()` for the +// sink, usually by adding a ADL-based free function in the same namespace as +// the sink: +// +// void AbslFormatFlush(MySink* dest, y_absl::string_view part); +// +// where `dest` is the pointer passed to `y_absl::Format()`. The function should +// append `part` to `dest`. +// // FormatRawSink does not own the passed sink object. The passed object must // outlive the FormatRawSink. class FormatRawSink { @@ -490,13 +490,13 @@ class FormatRawSink { // `y_absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // -// By default, `TString`, `std::ostream`, and `y_absl::Cord` are supported as -// destination objects. If a `TString` is used the formatted string is -// appended to it. +// By default, `TString`, `std::ostream`, and `y_absl::Cord` are supported as +// destination objects. If a `TString` is used the formatted string is +// appended to it. // -// `y_absl::Format()` is a generic version of `y_absl::StrAppendFormat()`, for -// custom sinks. The format string, like format strings for `StrFormat()`, is -// checked at compile-time. +// `y_absl::Format()` is a generic version of `y_absl::StrAppendFormat()`, for +// custom sinks. The format string, like format strings for `StrFormat()`, is +// checked at compile-time. // // On failure, this function returns `false` and the state of the sink is // unspecified. @@ -566,246 +566,246 @@ ABSL_MUST_USE_RESULT inline bool FormatUntyped( str_format_internal::UntypedFormatSpecImpl::Extract(format), args); } -//------------------------------------------------------------------------------ -// StrFormat Extensions -//------------------------------------------------------------------------------ -// -// AbslFormatConvert() -// -// The StrFormat library provides a customization API for formatting -// user-defined types using y_absl::StrFormat(). The API relies on detecting an -// overload in the user-defined type's namespace of a free (non-member) -// `AbslFormatConvert()` function, usually as a friend definition with the -// following signature: -// -// y_absl::FormatConvertResult<...> AbslFormatConvert( -// const X& value, -// const y_absl::FormatConversionSpec& spec, -// y_absl::FormatSink *sink); -// -// An `AbslFormatConvert()` overload for a type should only be declared in the -// same file and namespace as said type. -// -// The abstractions within this definition include: -// -// * An `y_absl::FormatConversionSpec` to specify the fields to pull from a -// user-defined type's format string -// * An `y_absl::FormatSink` to hold the converted string data during the -// conversion process. -// * An `y_absl::FormatConvertResult` to hold the status of the returned -// formatting operation -// -// The return type encodes all the conversion characters that your -// AbslFormatConvert() routine accepts. The return value should be {true}. -// A return value of {false} will result in `StrFormat()` returning -// an empty string. This result will be propagated to the result of -// `FormatUntyped`. -// -// Example: -// -// struct Point { -// // To add formatting support to `Point`, we simply need to add a free -// // (non-member) function `AbslFormatConvert()`. This method interprets -// // `spec` to print in the request format. The allowed conversion characters -// // can be restricted via the type of the result, in this example -// // string and integral formatting are allowed (but not, for instance -// // floating point characters like "%f"). You can add such a free function -// // using a friend declaration within the body of the class: -// friend y_absl::FormatConvertResult<y_absl::FormatConversionCharSet::kString | -// y_absl::FormatConversionCharSet::kIntegral> -// AbslFormatConvert(const Point& p, const y_absl::FormatConversionSpec& spec, -// y_absl::FormatSink* s) { -// if (spec.conversion_char() == y_absl::FormatConversionChar::s) { -// s->Append(y_absl::StrCat("x=", p.x, " y=", p.y)); -// } else { -// s->Append(y_absl::StrCat(p.x, ",", p.y)); -// } -// return {true}; -// } -// -// int x; -// int y; -// }; - -// clang-format off - -// FormatConversionChar -// -// Specifies the formatting character provided in the format string -// passed to `StrFormat()`. -enum class FormatConversionChar : uint8_t { - c, s, // text - d, i, o, u, x, X, // int - f, F, e, E, g, G, a, A, // float - n, p // misc -}; -// clang-format on - -// FormatConversionSpec -// -// Specifies modifications to the conversion of the format string, through use -// of one or more format flags in the source format string. -class FormatConversionSpec { - public: - // FormatConversionSpec::is_basic() - // - // Indicates that width and precision are not specified, and no additional - // flags are set for this conversion character in the format string. - bool is_basic() const { return impl_.is_basic(); } - - // FormatConversionSpec::has_left_flag() - // - // Indicates whether the result should be left justified for this conversion - // character in the format string. This flag is set through use of a '-' - // character in the format string. E.g. "%-s" - bool has_left_flag() const { return impl_.has_left_flag(); } - - // FormatConversionSpec::has_show_pos_flag() - // - // Indicates whether a sign column is prepended to the result for this - // conversion character in the format string, even if the result is positive. - // This flag is set through use of a '+' character in the format string. - // E.g. "%+d" - bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); } - - // FormatConversionSpec::has_sign_col_flag() - // - // Indicates whether a mandatory sign column is added to the result for this - // conversion character. This flag is set through use of a space character - // (' ') in the format string. E.g. "% i" - bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); } - - // FormatConversionSpec::has_alt_flag() - // - // Indicates whether an "alternate" format is applied to the result for this - // conversion character. Alternative forms depend on the type of conversion - // character, and unallowed alternatives are undefined. This flag is set - // through use of a '#' character in the format string. E.g. "%#h" - bool has_alt_flag() const { return impl_.has_alt_flag(); } - - // FormatConversionSpec::has_zero_flag() - // - // Indicates whether zeroes should be prepended to the result for this - // conversion character instead of spaces. This flag is set through use of the - // '0' character in the format string. E.g. "%0f" - bool has_zero_flag() const { return impl_.has_zero_flag(); } - - // FormatConversionSpec::conversion_char() - // - // Returns the underlying conversion character. - FormatConversionChar conversion_char() const { - return impl_.conversion_char(); - } - - // FormatConversionSpec::width() - // - // Returns the specified width (indicated through use of a non-zero integer - // value or '*' character) of the conversion character. If width is - // unspecified, it returns a negative value. - int width() const { return impl_.width(); } - - // FormatConversionSpec::precision() - // - // Returns the specified precision (through use of the '.' character followed - // by a non-zero integer value or '*' character) of the conversion character. - // If precision is unspecified, it returns a negative value. - int precision() const { return impl_.precision(); } - - private: - explicit FormatConversionSpec( - str_format_internal::FormatConversionSpecImpl impl) - : impl_(impl) {} - - friend str_format_internal::FormatConversionSpecImpl; - - y_absl::str_format_internal::FormatConversionSpecImpl impl_; -}; - -// Type safe OR operator for FormatConversionCharSet to allow accepting multiple -// conversion chars in custom format converters. -constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, - FormatConversionCharSet b) { - return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) | - static_cast<uint64_t>(b)); -} - -// FormatConversionCharSet -// -// Specifies the _accepted_ conversion types as a template parameter to -// FormatConvertResult for custom implementations of `AbslFormatConvert`. -// Note the helper predefined alias definitions (kIntegral, etc.) below. -enum class FormatConversionCharSet : uint64_t { - // text - c = str_format_internal::FormatConversionCharToConvInt('c'), - s = str_format_internal::FormatConversionCharToConvInt('s'), - // integer - d = str_format_internal::FormatConversionCharToConvInt('d'), - i = str_format_internal::FormatConversionCharToConvInt('i'), - o = str_format_internal::FormatConversionCharToConvInt('o'), - u = str_format_internal::FormatConversionCharToConvInt('u'), - x = str_format_internal::FormatConversionCharToConvInt('x'), - X = str_format_internal::FormatConversionCharToConvInt('X'), - // Float - f = str_format_internal::FormatConversionCharToConvInt('f'), - F = str_format_internal::FormatConversionCharToConvInt('F'), - e = str_format_internal::FormatConversionCharToConvInt('e'), - E = str_format_internal::FormatConversionCharToConvInt('E'), - g = str_format_internal::FormatConversionCharToConvInt('g'), - G = str_format_internal::FormatConversionCharToConvInt('G'), - a = str_format_internal::FormatConversionCharToConvInt('a'), - A = str_format_internal::FormatConversionCharToConvInt('A'), - // misc - n = str_format_internal::FormatConversionCharToConvInt('n'), - p = str_format_internal::FormatConversionCharToConvInt('p'), - - // Used for width/precision '*' specification. - kStar = static_cast<uint64_t>( - y_absl::str_format_internal::FormatConversionCharSetInternal::kStar), - // Some predefined values: - kIntegral = d | i | u | o | x | X, - kFloating = a | e | f | g | A | E | F | G, - kNumeric = kIntegral | kFloating, - kString = s, - kPointer = p, -}; - -// FormatSink -// -// An abstraction to which conversions write their string data. -// -class FormatSink { - public: - // Appends `count` copies of `ch`. - void Append(size_t count, char ch) { sink_->Append(count, ch); } - - void Append(string_view v) { sink_->Append(v); } - - // Appends the first `precision` bytes of `v`. If this is less than - // `width`, spaces will be appended first (if `left` is false), or - // after (if `left` is true) to ensure the total amount appended is - // at least `width`. - bool PutPaddedString(string_view v, int width, int precision, bool left) { - return sink_->PutPaddedString(v, width, precision, left); - } - - private: - friend str_format_internal::FormatSinkImpl; - explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {} - str_format_internal::FormatSinkImpl* sink_; -}; - -// FormatConvertResult -// -// Indicates whether a call to AbslFormatConvert() was successful. -// This return type informs the StrFormat extension framework (through -// ADL but using the return type) of what conversion characters are supported. -// It is strongly discouraged to return {false}, as this will result in an -// empty string in StrFormat. -template <FormatConversionCharSet C> -struct FormatConvertResult { - bool value; -}; - +//------------------------------------------------------------------------------ +// StrFormat Extensions +//------------------------------------------------------------------------------ +// +// AbslFormatConvert() +// +// The StrFormat library provides a customization API for formatting +// user-defined types using y_absl::StrFormat(). The API relies on detecting an +// overload in the user-defined type's namespace of a free (non-member) +// `AbslFormatConvert()` function, usually as a friend definition with the +// following signature: +// +// y_absl::FormatConvertResult<...> AbslFormatConvert( +// const X& value, +// const y_absl::FormatConversionSpec& spec, +// y_absl::FormatSink *sink); +// +// An `AbslFormatConvert()` overload for a type should only be declared in the +// same file and namespace as said type. +// +// The abstractions within this definition include: +// +// * An `y_absl::FormatConversionSpec` to specify the fields to pull from a +// user-defined type's format string +// * An `y_absl::FormatSink` to hold the converted string data during the +// conversion process. +// * An `y_absl::FormatConvertResult` to hold the status of the returned +// formatting operation +// +// The return type encodes all the conversion characters that your +// AbslFormatConvert() routine accepts. The return value should be {true}. +// A return value of {false} will result in `StrFormat()` returning +// an empty string. This result will be propagated to the result of +// `FormatUntyped`. +// +// Example: +// +// struct Point { +// // To add formatting support to `Point`, we simply need to add a free +// // (non-member) function `AbslFormatConvert()`. This method interprets +// // `spec` to print in the request format. The allowed conversion characters +// // can be restricted via the type of the result, in this example +// // string and integral formatting are allowed (but not, for instance +// // floating point characters like "%f"). You can add such a free function +// // using a friend declaration within the body of the class: +// friend y_absl::FormatConvertResult<y_absl::FormatConversionCharSet::kString | +// y_absl::FormatConversionCharSet::kIntegral> +// AbslFormatConvert(const Point& p, const y_absl::FormatConversionSpec& spec, +// y_absl::FormatSink* s) { +// if (spec.conversion_char() == y_absl::FormatConversionChar::s) { +// s->Append(y_absl::StrCat("x=", p.x, " y=", p.y)); +// } else { +// s->Append(y_absl::StrCat(p.x, ",", p.y)); +// } +// return {true}; +// } +// +// int x; +// int y; +// }; + +// clang-format off + +// FormatConversionChar +// +// Specifies the formatting character provided in the format string +// passed to `StrFormat()`. +enum class FormatConversionChar : uint8_t { + c, s, // text + d, i, o, u, x, X, // int + f, F, e, E, g, G, a, A, // float + n, p // misc +}; +// clang-format on + +// FormatConversionSpec +// +// Specifies modifications to the conversion of the format string, through use +// of one or more format flags in the source format string. +class FormatConversionSpec { + public: + // FormatConversionSpec::is_basic() + // + // Indicates that width and precision are not specified, and no additional + // flags are set for this conversion character in the format string. + bool is_basic() const { return impl_.is_basic(); } + + // FormatConversionSpec::has_left_flag() + // + // Indicates whether the result should be left justified for this conversion + // character in the format string. This flag is set through use of a '-' + // character in the format string. E.g. "%-s" + bool has_left_flag() const { return impl_.has_left_flag(); } + + // FormatConversionSpec::has_show_pos_flag() + // + // Indicates whether a sign column is prepended to the result for this + // conversion character in the format string, even if the result is positive. + // This flag is set through use of a '+' character in the format string. + // E.g. "%+d" + bool has_show_pos_flag() const { return impl_.has_show_pos_flag(); } + + // FormatConversionSpec::has_sign_col_flag() + // + // Indicates whether a mandatory sign column is added to the result for this + // conversion character. This flag is set through use of a space character + // (' ') in the format string. E.g. "% i" + bool has_sign_col_flag() const { return impl_.has_sign_col_flag(); } + + // FormatConversionSpec::has_alt_flag() + // + // Indicates whether an "alternate" format is applied to the result for this + // conversion character. Alternative forms depend on the type of conversion + // character, and unallowed alternatives are undefined. This flag is set + // through use of a '#' character in the format string. E.g. "%#h" + bool has_alt_flag() const { return impl_.has_alt_flag(); } + + // FormatConversionSpec::has_zero_flag() + // + // Indicates whether zeroes should be prepended to the result for this + // conversion character instead of spaces. This flag is set through use of the + // '0' character in the format string. E.g. "%0f" + bool has_zero_flag() const { return impl_.has_zero_flag(); } + + // FormatConversionSpec::conversion_char() + // + // Returns the underlying conversion character. + FormatConversionChar conversion_char() const { + return impl_.conversion_char(); + } + + // FormatConversionSpec::width() + // + // Returns the specified width (indicated through use of a non-zero integer + // value or '*' character) of the conversion character. If width is + // unspecified, it returns a negative value. + int width() const { return impl_.width(); } + + // FormatConversionSpec::precision() + // + // Returns the specified precision (through use of the '.' character followed + // by a non-zero integer value or '*' character) of the conversion character. + // If precision is unspecified, it returns a negative value. + int precision() const { return impl_.precision(); } + + private: + explicit FormatConversionSpec( + str_format_internal::FormatConversionSpecImpl impl) + : impl_(impl) {} + + friend str_format_internal::FormatConversionSpecImpl; + + y_absl::str_format_internal::FormatConversionSpecImpl impl_; +}; + +// Type safe OR operator for FormatConversionCharSet to allow accepting multiple +// conversion chars in custom format converters. +constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, + FormatConversionCharSet b) { + return static_cast<FormatConversionCharSet>(static_cast<uint64_t>(a) | + static_cast<uint64_t>(b)); +} + +// FormatConversionCharSet +// +// Specifies the _accepted_ conversion types as a template parameter to +// FormatConvertResult for custom implementations of `AbslFormatConvert`. +// Note the helper predefined alias definitions (kIntegral, etc.) below. +enum class FormatConversionCharSet : uint64_t { + // text + c = str_format_internal::FormatConversionCharToConvInt('c'), + s = str_format_internal::FormatConversionCharToConvInt('s'), + // integer + d = str_format_internal::FormatConversionCharToConvInt('d'), + i = str_format_internal::FormatConversionCharToConvInt('i'), + o = str_format_internal::FormatConversionCharToConvInt('o'), + u = str_format_internal::FormatConversionCharToConvInt('u'), + x = str_format_internal::FormatConversionCharToConvInt('x'), + X = str_format_internal::FormatConversionCharToConvInt('X'), + // Float + f = str_format_internal::FormatConversionCharToConvInt('f'), + F = str_format_internal::FormatConversionCharToConvInt('F'), + e = str_format_internal::FormatConversionCharToConvInt('e'), + E = str_format_internal::FormatConversionCharToConvInt('E'), + g = str_format_internal::FormatConversionCharToConvInt('g'), + G = str_format_internal::FormatConversionCharToConvInt('G'), + a = str_format_internal::FormatConversionCharToConvInt('a'), + A = str_format_internal::FormatConversionCharToConvInt('A'), + // misc + n = str_format_internal::FormatConversionCharToConvInt('n'), + p = str_format_internal::FormatConversionCharToConvInt('p'), + + // Used for width/precision '*' specification. + kStar = static_cast<uint64_t>( + y_absl::str_format_internal::FormatConversionCharSetInternal::kStar), + // Some predefined values: + kIntegral = d | i | u | o | x | X, + kFloating = a | e | f | g | A | E | F | G, + kNumeric = kIntegral | kFloating, + kString = s, + kPointer = p, +}; + +// FormatSink +// +// An abstraction to which conversions write their string data. +// +class FormatSink { + public: + // Appends `count` copies of `ch`. + void Append(size_t count, char ch) { sink_->Append(count, ch); } + + void Append(string_view v) { sink_->Append(v); } + + // Appends the first `precision` bytes of `v`. If this is less than + // `width`, spaces will be appended first (if `left` is false), or + // after (if `left` is true) to ensure the total amount appended is + // at least `width`. + bool PutPaddedString(string_view v, int width, int precision, bool left) { + return sink_->PutPaddedString(v, width, precision, left); + } + + private: + friend str_format_internal::FormatSinkImpl; + explicit FormatSink(str_format_internal::FormatSinkImpl* s) : sink_(s) {} + str_format_internal::FormatSinkImpl* sink_; +}; + +// FormatConvertResult +// +// Indicates whether a call to AbslFormatConvert() was successful. +// This return type informs the StrFormat extension framework (through +// ADL but using the return type) of what conversion characters are supported. +// It is strongly discouraged to return {false}, as this will result in an +// empty string in StrFormat. +template <FormatConversionCharSet C> +struct FormatConvertResult { + bool value; +}; + ABSL_NAMESPACE_END } // namespace y_absl diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h index 46a0323c6e..b362d5a24d 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_join.h @@ -144,7 +144,7 @@ strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter( std::forward<Formatter>(f)); } -// Function overload of `DereferenceFormatter()` for using a default +// Function overload of `DereferenceFormatter()` for using a default // `AlphaNumFormatter()`. inline strings_internal::DereferenceFormatterImpl< strings_internal::AlphaNumFormatterImpl> diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc index 5f9193e6ba..eb0228ac1b 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.cc @@ -42,7 +42,7 @@ y_absl::string_view GenericFind(y_absl::string_view text, y_absl::string_view delimiter, size_t pos, FindPolicy find_policy) { if (delimiter.empty() && text.length() > 0) { - // Special case for empty string delimiters: always return a zero-length + // Special case for empty string delimiters: always return a zero-length // y_absl::string_view referring to the item at position 1 past pos. return y_absl::string_view(text.data() + pos + 1, 0); } @@ -127,7 +127,7 @@ y_absl::string_view ByLength::Find(y_absl::string_view text, size_t pos) const { pos = std::min(pos, text.size()); // truncate `pos` y_absl::string_view substr = text.substr(pos); - // If the string is shorter than the chunk size we say we + // If the string is shorter than the chunk size we say we // "can't find the delimiter" so this will be the last chunk. if (substr.length() <= static_cast<size_t>(length_)) return y_absl::string_view(text.data() + text.size(), 0); diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h index d32d54813e..35df211020 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/str_split.h @@ -44,7 +44,7 @@ #include <vector> #include "y_absl/base/internal/raw_logging.h" -#include "y_absl/base/macros.h" +#include "y_absl/base/macros.h" #include "y_absl/strings/internal/str_split_internal.h" #include "y_absl/strings/string_view.h" #include "y_absl/strings/strip.h" @@ -369,12 +369,12 @@ struct SkipWhitespace { } }; -template <typename T> -using EnableSplitIfString = - typename std::enable_if<std::is_same<T, TString>::value || - std::is_same<T, const TString>::value, - int>::type; - +template <typename T> +using EnableSplitIfString = + typename std::enable_if<std::is_same<T, TString>::value || + std::is_same<T, const TString>::value, + int>::type; + //------------------------------------------------------------------------------ // StrSplit() //------------------------------------------------------------------------------ @@ -495,50 +495,50 @@ using EnableSplitIfString = // Try not to depend on this distinction because the bug may one day be fixed. template <typename Delimiter> strings_internal::Splitter< - typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty, - y_absl::string_view> + typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty, + y_absl::string_view> StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { using DelimiterType = typename strings_internal::SelectDelimiter<Delimiter>::type; - return strings_internal::Splitter<DelimiterType, AllowEmpty, - y_absl::string_view>( - text.value(), DelimiterType(d), AllowEmpty()); -} - -template <typename Delimiter, typename StringType, - EnableSplitIfString<StringType> = 0> -strings_internal::Splitter< - typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty, - TString> -StrSplit(StringType&& text, Delimiter d) { - using DelimiterType = - typename strings_internal::SelectDelimiter<Delimiter>::type; - return strings_internal::Splitter<DelimiterType, AllowEmpty, TString>( + return strings_internal::Splitter<DelimiterType, AllowEmpty, + y_absl::string_view>( + text.value(), DelimiterType(d), AllowEmpty()); +} + +template <typename Delimiter, typename StringType, + EnableSplitIfString<StringType> = 0> +strings_internal::Splitter< + typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty, + TString> +StrSplit(StringType&& text, Delimiter d) { + using DelimiterType = + typename strings_internal::SelectDelimiter<Delimiter>::type; + return strings_internal::Splitter<DelimiterType, AllowEmpty, TString>( std::move(text), DelimiterType(d), AllowEmpty()); } template <typename Delimiter, typename Predicate> strings_internal::Splitter< - typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate, - y_absl::string_view> + typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate, + y_absl::string_view> StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, Predicate p) { using DelimiterType = typename strings_internal::SelectDelimiter<Delimiter>::type; - return strings_internal::Splitter<DelimiterType, Predicate, - y_absl::string_view>( - text.value(), DelimiterType(d), std::move(p)); -} - -template <typename Delimiter, typename Predicate, typename StringType, - EnableSplitIfString<StringType> = 0> -strings_internal::Splitter< - typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate, - TString> -StrSplit(StringType&& text, Delimiter d, Predicate p) { - using DelimiterType = - typename strings_internal::SelectDelimiter<Delimiter>::type; - return strings_internal::Splitter<DelimiterType, Predicate, TString>( + return strings_internal::Splitter<DelimiterType, Predicate, + y_absl::string_view>( + text.value(), DelimiterType(d), std::move(p)); +} + +template <typename Delimiter, typename Predicate, typename StringType, + EnableSplitIfString<StringType> = 0> +strings_internal::Splitter< + typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate, + TString> +StrSplit(StringType&& text, Delimiter d, Predicate p) { + using DelimiterType = + typename strings_internal::SelectDelimiter<Delimiter>::type; + return strings_internal::Splitter<DelimiterType, Predicate, TString>( std::move(text), DelimiterType(d), std::move(p)); } diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h index c3906fe1c5..447e0f0dcd 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/string_view.h @@ -49,7 +49,7 @@ namespace y_absl { ABSL_NAMESPACE_BEGIN -using string_view = std::string_view; +using string_view = std::string_view; ABSL_NAMESPACE_END } // namespace y_absl @@ -120,11 +120,11 @@ ABSL_NAMESPACE_BEGIN // example, when splitting a string, `std::vector<y_absl::string_view>` is a // natural data type for the output. // -// For another example, a Cord is a non-contiguous, potentially very -// long string-like object. The Cord class has an interface that iteratively -// provides string_view objects that point to the successive pieces of a Cord -// object. -// +// For another example, a Cord is a non-contiguous, potentially very +// long string-like object. The Cord class has an interface that iteratively +// provides string_view objects that point to the successive pieces of a Cord +// object. +// // When constructed from a source which is NUL-terminated, the `string_view` // itself will not include the NUL-terminator unless a specific size (including // the NUL) is passed to the constructor. As a result, common idioms that work @@ -297,7 +297,7 @@ class string_view { // Returns the ith element of the `string_view` using the array operator. // Note that this operator does not perform any bounds checking. constexpr const_reference operator[](size_type i) const { - return ABSL_HARDENING_ASSERT(i < size()), ptr_[i]; + return ABSL_HARDENING_ASSERT(i < size()), ptr_[i]; } // string_view::at() @@ -317,14 +317,14 @@ class string_view { // // Returns the first element of a `string_view`. constexpr const_reference front() const { - return ABSL_HARDENING_ASSERT(!empty()), ptr_[0]; + return ABSL_HARDENING_ASSERT(!empty()), ptr_[0]; } // string_view::back() // // Returns the last element of a `string_view`. constexpr const_reference back() const { - return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1]; + return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1]; } // string_view::data() @@ -333,7 +333,7 @@ class string_view { // stored elsewhere). Note that `string_view::data()` may contain embedded nul // characters, but the returned buffer may or may not be NUL-terminated; // therefore, do not pass `data()` to a routine that expects a NUL-terminated - // string. + // string. constexpr const_pointer data() const noexcept { return ptr_; } // Modifiers @@ -341,9 +341,9 @@ class string_view { // string_view::remove_prefix() // // Removes the first `n` characters from the `string_view`. Note that the - // underlying string is not changed, only the view. + // underlying string is not changed, only the view. ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_prefix(size_type n) { - ABSL_HARDENING_ASSERT(n <= length_); + ABSL_HARDENING_ASSERT(n <= length_); ptr_ += n; length_ -= n; } @@ -351,9 +351,9 @@ class string_view { // string_view::remove_suffix() // // Removes the last `n` characters from the `string_view`. Note that the - // underlying string is not changed, only the view. + // underlying string is not changed, only the view. ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR void remove_suffix(size_type n) { - ABSL_HARDENING_ASSERT(n <= length_); + ABSL_HARDENING_ASSERT(n <= length_); length_ -= n; } @@ -396,13 +396,13 @@ class string_view { // Returns a "substring" of the `string_view` (at offset `pos` and length // `n`) as another string_view. This function throws `std::out_of_bounds` if // `pos > size`. - // Use y_absl::ClippedSubstr if you need a truncating substr operation. + // Use y_absl::ClippedSubstr if you need a truncating substr operation. constexpr string_view substr(size_type pos = 0, size_type n = npos) const { - return ABSL_PREDICT_FALSE(pos > length_) - ? (base_internal::ThrowStdOutOfRange( - "y_absl::string_view::substr"), - string_view()) - : string_view(ptr_ + pos, Min(n, length_ - pos)); + return ABSL_PREDICT_FALSE(pos > length_) + ? (base_internal::ThrowStdOutOfRange( + "y_absl::string_view::substr"), + string_view()) + : string_view(ptr_ + pos, Min(n, length_ - pos)); } // string_view::compare() @@ -437,13 +437,13 @@ class string_view { constexpr int compare(const char* s) const { return compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the - // `string_view` and a different string C-style string `s`. + // `string_view` and a different string C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s) const { return substr(pos1, count1).compare(string_view(s)); } // Overload of `string_view::compare()` for comparing a substring of the - // `string_view` and a substring of a different C-style string `s`. + // `string_view` and a substring of a different C-style string `s`. constexpr int compare(size_type pos1, size_type count1, const char* s, size_type count2) const { return substr(pos1, count1).compare(string_view(s, count2)); @@ -608,7 +608,7 @@ class string_view { (std::numeric_limits<difference_type>::max)(); static constexpr size_type CheckLengthInternal(size_type len) { - return ABSL_HARDENING_ASSERT(len <= kMaxSize), len; + return ABSL_HARDENING_ASSERT(len <= kMaxSize), len; } static constexpr size_type StrlenInternal(const char* str) { diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc index 177fba8cbe..75035a5706 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.cc @@ -36,7 +36,7 @@ void SubstituteAndAppendArray(TString* output, y_absl::string_view format, if (i + 1 >= format.size()) { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, - "Invalid y_absl::Substitute() format string: \"%s\".", + "Invalid y_absl::Substitute() format string: \"%s\".", y_absl::CEscape(format).c_str()); #endif return; @@ -46,8 +46,8 @@ void SubstituteAndAppendArray(TString* output, y_absl::string_view format, #ifndef NDEBUG ABSL_RAW_LOG( FATAL, - "Invalid y_absl::Substitute() format string: asked for \"$" - "%d\", but only %d args were given. Full format string was: " + "Invalid y_absl::Substitute() format string: asked for \"$" + "%d\", but only %d args were given. Full format string was: " "\"%s\".", index, static_cast<int>(num_args), y_absl::CEscape(format).c_str()); #endif @@ -61,7 +61,7 @@ void SubstituteAndAppendArray(TString* output, y_absl::string_view format, } else { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, - "Invalid y_absl::Substitute() format string: \"%s\".", + "Invalid y_absl::Substitute() format string: \"%s\".", y_absl::CEscape(format).c_str()); #endif return; @@ -73,7 +73,7 @@ void SubstituteAndAppendArray(TString* output, y_absl::string_view format, if (size == 0) return; - // Build the string. + // Build the string. size_t original_size = output->size(); strings_internal::STLStringResizeUninitializedAmortized(output, original_size + size); diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h index c31191fbda..8b750f9787 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/substitute.h @@ -50,7 +50,7 @@ // // Supported types: // * y_absl::string_view, TString, const char* (null is equivalent to "") -// * int32_t, int64_t, uint32_t, uint64_t +// * int32_t, int64_t, uint32_t, uint64_t // * float, double // * bool (Printed as "true" or "false") // * pointer types other than char* (Printed as "0x<lower case hex string>", @@ -99,7 +99,7 @@ namespace substitute_internal { // This class has implicit constructors. class Arg { public: - // Overloads for string-y things + // Overloads for string-y things // // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. Arg(const char* value) // NOLINT(runtime/explicit) @@ -122,9 +122,9 @@ class Arg { // representation. However, we can't really know, so we make the caller decide // what to do. Arg(char value) // NOLINT(runtime/explicit) - : piece_(scratch_, 1) { - scratch_[0] = value; - } + : piece_(scratch_, 1) { + scratch_[0] = value; + } Arg(short value) // NOLINT(*) : piece_(scratch_, numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} @@ -207,11 +207,11 @@ constexpr const char* SkipNumber(const char* format) { } constexpr int PlaceholderBitmask(const char* format) { - return !*format - ? 0 - : *format != '$' ? PlaceholderBitmask(format + 1) - : (CalculateOneBit(format + 1) | - PlaceholderBitmask(SkipNumber(format + 1))); + return !*format + ? 0 + : *format != '$' ? PlaceholderBitmask(format + 1) + : (CalculateOneBit(format + 1) | + PlaceholderBitmask(SkipNumber(format + 1))); } #endif // ABSL_BAD_CALL_IF diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make index 77c5a47dc9..bc65e01f18 100644 --- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make +++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/ya.make @@ -2,15 +2,15 @@ LIBRARY() -OWNER( - somov - g:cpp-contrib -) +OWNER( + somov + g:cpp-contrib +) LICENSE(Apache-2.0) -LICENSE_TEXTS(.yandex_meta/licenses.list.txt) - +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + PEERDIR( contrib/restricted/abseil-cpp-tstring/y_absl/base contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging |