diff options
author | ayles <ayles@yandex-team.ru> | 2022-02-10 16:46:11 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:11 +0300 |
commit | d55028e9d9708f94c2d0d35b54ed50d4d7af0456 (patch) | |
tree | d69fdff3b2be7d190a1efa078721d25139d0b030 /contrib/restricted/abseil-cpp/absl/strings | |
parent | baa58daefa91fde4b4769facdbd2903763b9c6a8 (diff) | |
download | ydb-d55028e9d9708f94c2d0d35b54ed50d4d7af0456.tar.gz |
Restoring authorship annotation for <ayles@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp/absl/strings')
63 files changed, 5539 insertions, 5539 deletions
diff --git a/contrib/restricted/abseil-cpp/absl/strings/ascii.cc b/contrib/restricted/abseil-cpp/absl/strings/ascii.cc index 93bb03e958..facfb50bc0 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/ascii.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/ascii.cc @@ -15,7 +15,7 @@ #include "absl/strings/ascii.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace ascii_internal { // # Table generated by this Python code (bit 0x02 is currently unused): @@ -57,7 +57,7 @@ namespace ascii_internal { // of these bits is tightly coupled to this implementation, the individual bits // are not named. Note that bitfields for all characters above ASCII 127 are // zero-initialized. -ABSL_DLL const unsigned char kPropertyBits[256] = { +ABSL_DLL const unsigned char kPropertyBits[256] = { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 @@ -79,7 +79,7 @@ ABSL_DLL const unsigned char kPropertyBits[256] = { // Array of characters for the ascii_tolower() function. For values 'A' // through 'Z', return the lower-case character; otherwise, return the // identity of the passed character. -ABSL_DLL const char kToLower[256] = { +ABSL_DLL const char kToLower[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', @@ -117,7 +117,7 @@ ABSL_DLL const char kToLower[256] = { // Array of characters for the ascii_toupper() function. For values 'a' // through 'z', return the upper-case character; otherwise, return the // identity of the passed character. -ABSL_DLL const char kToUpper[256] = { +ABSL_DLL const char kToUpper[256] = { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', @@ -196,5 +196,5 @@ void RemoveExtraAsciiWhitespace(std::string* str) { str->erase(output_it - &(*str)[0]); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/ascii.h b/contrib/restricted/abseil-cpp/absl/strings/ascii.h index b46bc71f35..699c209c9d 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/ascii.h +++ b/contrib/restricted/abseil-cpp/absl/strings/ascii.h @@ -56,21 +56,21 @@ #include <string> #include "absl/base/attributes.h" -#include "absl/base/config.h" +#include "absl/base/config.h" #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace ascii_internal { // Declaration for an array of bitfields holding character information. -ABSL_DLL extern const unsigned char kPropertyBits[256]; +ABSL_DLL extern const unsigned char kPropertyBits[256]; // Declaration for the array of characters to upper-case characters. -ABSL_DLL extern const char kToUpper[256]; +ABSL_DLL extern const char kToUpper[256]; // Declaration for the array of characters to lower-case characters. -ABSL_DLL extern const char kToLower[256]; +ABSL_DLL extern const char kToLower[256]; } // namespace ascii_internal @@ -236,7 +236,7 @@ inline void StripAsciiWhitespace(std::string* str) { // Removes leading, trailing, and consecutive internal whitespace. void RemoveExtraAsciiWhitespace(std::string*); -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_ASCII_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/charconv.cc b/contrib/restricted/abseil-cpp/absl/strings/charconv.cc index fefcfc90a5..870461ce96 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/charconv.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/charconv.cc @@ -57,7 +57,7 @@ // narrower mantissas. namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace { template <typename FloatType> @@ -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 { @@ -980,5 +980,5 @@ const int16_t kPower10ExponentTable[] = { }; } // namespace -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/charconv.h b/contrib/restricted/abseil-cpp/absl/strings/charconv.h index 7c50981245..be05e34d08 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/charconv.h +++ b/contrib/restricted/abseil-cpp/absl/strings/charconv.h @@ -17,10 +17,10 @@ #include <system_error> // NOLINT(build/c++11) -#include "absl/base/config.h" - +#include "absl/base/config.h" + namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // Workalike compatibilty version of std::chars_format from C++17. // @@ -114,7 +114,7 @@ inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { return lhs; } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_CHARCONV_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/cord.cc b/contrib/restricted/abseil-cpp/absl/strings/cord.cc index 854047ca98..a353a9facf 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/cord.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/cord.cc @@ -1,209 +1,209 @@ -// 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 "absl/strings/cord.h" - -#include <algorithm> -#include <atomic> -#include <cstddef> -#include <cstdio> -#include <cstdlib> -#include <iomanip> -#include <iostream> -#include <limits> -#include <ostream> -#include <sstream> -#include <type_traits> -#include <unordered_set> -#include <vector> - -#include "absl/base/casts.h" -#include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" -#include "absl/base/port.h" -#include "absl/container/fixed_array.h" -#include "absl/container/inlined_vector.h" -#include "absl/strings/escaping.h" -#include "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 "absl/strings/cord.h" + +#include <algorithm> +#include <atomic> +#include <cstddef> +#include <cstdio> +#include <cstdlib> +#include <iomanip> +#include <iostream> +#include <limits> +#include <ostream> +#include <sstream> +#include <type_traits> +#include <unordered_set> +#include <vector> + +#include "absl/base/casts.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/base/macros.h" +#include "absl/base/port.h" +#include "absl/container/fixed_array.h" +#include "absl/container/inlined_vector.h" +#include "absl/strings/escaping.h" +#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_tracker.h" -#include "absl/strings/internal/resize_uninitialized.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "absl/strings/str_join.h" -#include "absl/strings/string_view.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - -using ::absl::cord_internal::CordRep; +#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +using ::absl::cord_internal::CordRep; using ::absl::cord_internal::CordRepBtree; -using ::absl::cord_internal::CordRepConcat; -using ::absl::cord_internal::CordRepExternal; +using ::absl::cord_internal::CordRepConcat; +using ::absl::cord_internal::CordRepExternal; using ::absl::cord_internal::CordRepFlat; -using ::absl::cord_internal::CordRepSubstring; +using ::absl::cord_internal::CordRepSubstring; using ::absl::cord_internal::CordzUpdateTracker; using ::absl::cord_internal::InlineData; using ::absl::cord_internal::kMaxFlatLength; using ::absl::cord_internal::kMinFlatLength; - + using ::absl::cord_internal::kInlinedVectorSize; using ::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); -} - -static_assert(Fibonacci(63) == 6557470319842, - "Fibonacci values computed incorrectly"); - -// Minimum length required for a given depth tree -- a tree is considered -// balanced if -// length(t) >= min_length[depth(t)] -// 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), - 0xffffffffffffffffull, // Avoid overflow -}; - -static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length); - + +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); +} + +static_assert(Fibonacci(63) == 6557470319842, + "Fibonacci values computed incorrectly"); + +// Minimum length required for a given depth tree -- a tree is considered +// balanced if +// length(t) >= min_length[depth(t)] +// 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), + 0xffffffffffffffffull, // Avoid overflow +}; + +static const int kMinLengthSize = ABSL_ARRAYSIZE(min_length); + static inline bool btree_enabled() { return cord_internal::cord_btree_enabled.load( std::memory_order_relaxed); } - -static inline bool IsRootBalanced(CordRep* node) { + +static inline bool IsRootBalanced(CordRep* node) { if (!node->IsConcat()) { - return true; - } else if (node->concat()->depth() <= 15) { - return true; - } else if (node->concat()->depth() > kMinLengthSize) { - return false; - } else { - // Allow depth to become twice as large as implied by fibonacci rule to - // reduce rebalancing for larger strings. - return (node->length >= min_length[node->concat()->depth() / 2]); - } -} - -static CordRep* Rebalance(CordRep* node); + return true; + } else if (node->concat()->depth() <= 15) { + return true; + } else if (node->concat()->depth() > kMinLengthSize) { + return false; + } else { + // Allow depth to become twice as large as implied by fibonacci rule to + // reduce rebalancing for larger strings. + return (node->length >= min_length[node->concat()->depth() / 2]); + } +} + +static CordRep* Rebalance(CordRep* node); 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); - -static inline CordRep* VerifyTree(CordRep* node) { - // Verification is expensive, so only do it in debug mode. - // Even in debug mode we normally do only light validation. - // If you are debugging Cord itself, you should define the - // macro EXTRA_CORD_VALIDATION, e.g. by adding - // --copt=-DEXTRA_CORD_VALIDATION to the blaze line. -#ifdef EXTRA_CORD_VALIDATION - assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true)); -#else // EXTRA_CORD_VALIDATION - assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false)); -#endif // EXTRA_CORD_VALIDATION - static_cast<void>(&VerifyNode); - - return node; -} - -// Return the depth of a node -static int Depth(const CordRep* rep) { +static bool VerifyNode(CordRep* root, CordRep* start_node, + bool full_validation); + +static inline CordRep* VerifyTree(CordRep* node) { + // Verification is expensive, so only do it in debug mode. + // Even in debug mode we normally do only light validation. + // If you are debugging Cord itself, you should define the + // macro EXTRA_CORD_VALIDATION, e.g. by adding + // --copt=-DEXTRA_CORD_VALIDATION to the blaze line. +#ifdef EXTRA_CORD_VALIDATION + assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/true)); +#else // EXTRA_CORD_VALIDATION + assert(node == nullptr || VerifyNode(node, node, /*full_validation=*/false)); +#endif // EXTRA_CORD_VALIDATION + static_cast<void>(&VerifyNode); + + return node; +} + +// Return the depth of a node +static int Depth(const CordRep* rep) { if (rep->IsConcat()) { - return rep->concat()->depth(); - } else { - return 0; - } -} - -static void SetConcatChildren(CordRepConcat* concat, CordRep* left, - CordRep* right) { - concat->left = left; - concat->right = right; - - concat->length = left->length + right->length; - concat->set_depth(1 + std::max(Depth(left), Depth(right))); -} - -// Create a concatenation of the specified nodes. -// Does not change the refcounts of "left" and "right". -// The returned node has a refcount of 1. -static CordRep* RawConcat(CordRep* left, CordRep* right) { - // Avoid making degenerate concat nodes (one child is empty) + return rep->concat()->depth(); + } else { + return 0; + } +} + +static void SetConcatChildren(CordRepConcat* concat, CordRep* left, + CordRep* right) { + concat->left = left; + concat->right = right; + + concat->length = left->length + right->length; + concat->set_depth(1 + std::max(Depth(left), Depth(right))); +} + +// Create a concatenation of the specified nodes. +// Does not change the refcounts of "left" and "right". +// 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); - return right; - } + return right; + } if (right->length == 0) { CordRep::Unref(right); - return left; - } - - CordRepConcat* rep = new CordRepConcat(); + return left; + } + + CordRepConcat* rep = new CordRepConcat(); rep->tag = cord_internal::CONCAT; - SetConcatChildren(rep, left, right); - - return rep; -} - -static CordRep* Concat(CordRep* left, CordRep* right) { - CordRep* rep = RawConcat(left, right); - if (rep != nullptr && !IsRootBalanced(rep)) { - rep = Rebalance(rep); - } - return VerifyTree(rep); -} - -// Make a balanced tree out of an array of leaf nodes. -static CordRep* MakeBalancedTree(CordRep** reps, size_t n) { - // Make repeated passes over the array, merging adjacent pairs - // until we are left with just a single node. - while (n > 1) { - size_t dst = 0; - for (size_t src = 0; src < n; src += 2) { - if (src + 1 < n) { - reps[dst] = Concat(reps[src], reps[src + 1]); - } else { - reps[dst] = reps[src]; - } - dst++; - } - n = dst; - } - - return reps[0]; -} - + SetConcatChildren(rep, left, right); + + return rep; +} + +static CordRep* Concat(CordRep* left, CordRep* right) { + CordRep* rep = RawConcat(left, right); + if (rep != nullptr && !IsRootBalanced(rep)) { + rep = Rebalance(rep); + } + return VerifyTree(rep); +} + +// Make a balanced tree out of an array of leaf nodes. +static CordRep* MakeBalancedTree(CordRep** reps, size_t n) { + // Make repeated passes over the array, merging adjacent pairs + // until we are left with just a single node. + while (n > 1) { + size_t dst = 0; + for (size_t src = 0; src < n; src += 2) { + if (src + 1 < n) { + reps[dst] = Concat(reps[src], reps[src + 1]); + } else { + reps[dst] = reps[src]; + } + dst++; + } + n = dst; + } + + return reps[0]; +} + static CordRepFlat* CreateFlat(const char* data, size_t length, size_t alloc_hint) { CordRepFlat* flat = CordRepFlat::New(length + alloc_hint); @@ -217,63 +217,63 @@ static CordRepFlat* CreateFlat(const char* data, size_t length, static CordRep* NewBtree(const char* data, size_t length, size_t alloc_hint) { if (length <= kMaxFlatLength) { return CreateFlat(data, length, alloc_hint); - } + } CordRepFlat* flat = CreateFlat(data, kMaxFlatLength, 0); data += kMaxFlatLength; length -= kMaxFlatLength; auto* root = CordRepBtree::Create(flat); return CordRepBtree::Append(root, {data, length}, alloc_hint); -} - -// Create a new tree out of the specified array. -// The returned node has a refcount of 1. +} + +// Create a new tree out of the specified array. +// The returned node has a refcount of 1. static CordRep* NewTree(const char* data, size_t length, size_t alloc_hint) { - if (length == 0) return nullptr; + if (length == 0) return nullptr; if (btree_enabled()) { return NewBtree(data, length, alloc_hint); } - absl::FixedArray<CordRep*> reps((length - 1) / kMaxFlatLength + 1); - size_t n = 0; - do { - const size_t len = std::min(length, kMaxFlatLength); + 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); - rep->length = len; + rep->length = len; memcpy(rep->Data(), data, len); - reps[n++] = VerifyTree(rep); - data += len; - length -= len; - } while (length != 0); - return MakeBalancedTree(reps.data(), n); -} - -namespace cord_internal { - -void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) { - assert(!data.empty()); - rep->length = data.size(); - rep->tag = EXTERNAL; - rep->base = data.data(); - VerifyTree(rep); -} - -} // namespace cord_internal - -static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) { - // Never create empty substring nodes - if (length == 0) { + reps[n++] = VerifyTree(rep); + data += len; + length -= len; + } while (length != 0); + return MakeBalancedTree(reps.data(), n); +} + +namespace cord_internal { + +void InitializeCordRepExternal(absl::string_view data, CordRepExternal* rep) { + assert(!data.empty()); + rep->length = data.size(); + rep->tag = EXTERNAL; + rep->base = data.data(); + VerifyTree(rep); +} + +} // namespace cord_internal + +static CordRep* NewSubstring(CordRep* child, size_t offset, size_t length) { + // Never create empty substring nodes + if (length == 0) { CordRep::Unref(child); - return nullptr; - } else { - CordRepSubstring* rep = new CordRepSubstring(); - assert((offset + length) <= child->length); - rep->length = length; + return nullptr; + } else { + CordRepSubstring* rep = new CordRepSubstring(); + assert((offset + length) <= child->length); + rep->length = length; rep->tag = cord_internal::SUBSTRING; - rep->start = offset; - rep->child = child; - return VerifyTree(rep); - } -} - + rep->start = offset; + rep->child = child; + return VerifyTree(rep); + } +} + // Creates a CordRep from the provided string. If the string is large enough, // and not wasteful, we move the string into an external cord rep, preserving // the already allocated string contents. @@ -303,41 +303,41 @@ static CordRep* CordRepFromString(std::string&& src) { return rep; } -// -------------------------------------------------------------------- -// Cord::InlineRep functions - -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::InlineRep functions + +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); -} - -inline char* Cord::InlineRep::set_data(size_t n) { - assert(n <= kMaxInline); - ResetToEmpty(); +} + +inline char* Cord::InlineRep::set_data(size_t n) { + assert(n <= kMaxInline); + ResetToEmpty(); set_inline_size(n); return data_.as_chars(); -} - -inline void Cord::InlineRep::reduce_size(size_t n) { +} + +inline void Cord::InlineRep::reduce_size(size_t n) { size_t tag = inline_size(); - assert(tag <= kMaxInline); - assert(tag >= n); - tag -= n; + assert(tag <= kMaxInline); + assert(tag >= n); + tag -= n; memset(data_.as_chars() + tag, 0, n); set_inline_size(static_cast<char>(tag)); -} - -inline void Cord::InlineRep::remove_prefix(size_t n) { +} + +inline void Cord::InlineRep::remove_prefix(size_t n) { cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n, inline_size() - n); - reduce_size(n); -} - + reduce_size(n); +} + // Returns `rep` converted into a CordRepBtree. // Directly returns `rep` if `rep` is already a CordRepBtree. static CordRepBtree* ForceBtree(CordRep* rep) { @@ -370,14 +370,14 @@ void Cord::InlineRep::AppendTreeToTree(CordRep* tree, MethodIdentifier method) { } void Cord::InlineRep::AppendTree(CordRep* tree, MethodIdentifier method) { - if (tree == nullptr) return; + if (tree == nullptr) return; if (data_.is_tree()) { AppendTreeToTree(tree, method); - } else { + } else { AppendTreeToInlined(tree, method); - } -} - + } +} + void Cord::InlineRep::PrependTreeToInlined(CordRep* tree, MethodIdentifier method) { assert(!is_tree()); @@ -405,20 +405,20 @@ 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 { + } else { PrependTreeToInlined(tree, method); - } -} - -// Searches for a non-full flat node at the rightmost leaf of the tree. If a -// suitable leaf is found, the function will update the length field for all -// nodes to account for the size increase. The append region address will be -// written to region and the actual size increase will be written to size. -static inline bool PrepareAppendRegion(CordRep* root, char** region, - size_t* size, size_t max_length) { + } +} + +// Searches for a non-full flat node at the rightmost leaf of the tree. If a +// suitable leaf is found, the function will update the length field for all +// nodes to account for the size increase. The append region address will be +// written to region and the actual size increase will be written to size. +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()) { @@ -428,44 +428,44 @@ static inline bool PrepareAppendRegion(CordRep* root, char** region, } } - // Search down the right-hand path for a non-full FLAT node. - CordRep* dst = root; + // Search down the right-hand path for a non-full FLAT node. + CordRep* dst = root; while (dst->IsConcat() && dst->refcount.IsMutable()) { - dst = dst->concat()->right; - } - + dst = dst->concat()->right; + } + if (!dst->IsFlat() || !dst->refcount.IsMutable()) { - *region = nullptr; - *size = 0; - return false; - } - - const size_t in_use = dst->length; + *region = nullptr; + *size = 0; + return false; + } + + const size_t in_use = dst->length; const size_t capacity = dst->flat()->Capacity(); - if (in_use == capacity) { - *region = nullptr; - *size = 0; - return false; - } - - size_t size_increase = std::min(capacity - in_use, max_length); - - // We need to update the length fields for all nodes, including the leaf node. - for (CordRep* rep = root; rep != dst; rep = rep->concat()->right) { - rep->length += size_increase; - } - dst->length += size_increase; - + if (in_use == capacity) { + *region = nullptr; + *size = 0; + return false; + } + + size_t size_increase = std::min(capacity - in_use, max_length); + + // We need to update the length fields for all nodes, including the leaf node. + for (CordRep* rep = root; rep != dst; rep = rep->concat()->right) { + rep->length += size_increase; + } + dst->length += size_increase; + *region = dst->flat()->Data() + in_use; - *size = size_increase; - return true; -} - + *size = size_increase; + return true; +} + template <bool has_length> -void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, +void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, size_t length) { auto constexpr method = CordzUpdateTracker::kGetAppendRegion; - + CordRep* root = tree(); size_t sz = root ? root->length : inline_size(); if (root == nullptr) { @@ -476,21 +476,21 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, set_inline_size(has_length ? sz + length : kMaxInline); return; } - } - + } + size_t extra = has_length ? length : (std::max)(sz, kMinFlatLength); CordRep* rep = root ? root : MakeFlatWithExtraCapacity(extra); CordzUpdateScope scope(root ? data_.cordz_info() : nullptr, method); if (PrepareAppendRegion(rep, region, size, length)) { CommitTree(root, rep, scope, method); - return; - } - - // Allocate new node. + return; + } + + // Allocate new node. CordRepFlat* new_node = CordRepFlat::New(extra); new_node->length = std::min(new_node->Capacity(), length); *region = new_node->Data(); - *size = new_node->length; + *size = new_node->length; if (btree_enabled()) { rep = CordRepBtree::Append(ForceBtree(rep), new_node); @@ -498,8 +498,8 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, rep = Concat(rep, new_node); } CommitTree(root, rep, scope, method); -} - +} + // Computes the memory side of the provided edge which must be a valid data edge // for a btrtee, i.e., a FLAT, EXTERNAL or SUBSTRING of a FLAT or EXTERNAL node. static bool RepMemoryUsageDataEdge(const CordRep* rep, @@ -508,11 +508,11 @@ static bool RepMemoryUsageDataEdge(const CordRep* rep, if (ABSL_PREDICT_FALSE(rep->IsSubstring())) { maybe_sub_size = sizeof(cord_internal::CordRepSubstring); rep = rep->substring()->child; - } + } if (rep->IsFlat()) { *total_mem_usage += maybe_sub_size + rep->flat()->AllocatedSize(); return true; - } + } if (rep->IsExternal()) { // We don't know anything about the embedded / bound data, but we can safely // assume it is 'at least' a word / pointer to data. In the future we may @@ -524,15 +524,15 @@ static bool RepMemoryUsageDataEdge(const CordRep* rep, return true; } return false; -} - -// If the rep is a leaf, this will increment the value at total_mem_usage and -// will return true. -static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) { +} + +// If the rep is a leaf, this will increment the value at total_mem_usage and +// will return true. +static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) { if (rep->IsFlat()) { *total_mem_usage += rep->flat()->AllocatedSize(); - return true; - } + return true; + } if (rep->IsExternal()) { // We don't know anything about the embedded / bound data, but we can safely // assume it is 'at least' a word / pointer to data. In the future we may @@ -540,12 +540,12 @@ static bool RepMemoryUsageLeaf(const CordRep* rep, size_t* total_mem_usage) { // well-known externals, such as a std::string instance. *total_mem_usage += sizeof(cord_internal::CordRepExternalImpl<intptr_t>) + rep->length; - return true; - } - return false; -} - -void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { + return true; + } + return false; +} + +void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { assert(&src != this); assert(is_tree() || src.is_tree()); auto constexpr method = CordzUpdateTracker::kAssignCord; @@ -553,7 +553,7 @@ void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { EmplaceTree(CordRep::Ref(src.as_tree()), src.data_, method); return; } - + CordRep* tree = as_tree(); if (CordRep* src_tree = src.tree()) { // Leave any existing `cordz_info` in place, and let MaybeTrackCord() @@ -563,60 +563,60 @@ void Cord::InlineRep::AssignSlow(const Cord::InlineRep& src) { } else { CordzInfo::MaybeUntrackCord(data_.cordz_info()); data_ = src.data_; - } + } CordRep::Unref(tree); -} - +} + void Cord::InlineRep::UnrefTree() { - if (is_tree()) { + if (is_tree()) { CordzInfo::MaybeUntrackCord(data_.cordz_info()); CordRep::Unref(tree()); - } -} - -// -------------------------------------------------------------------- -// Constructors and destructors - + } +} + +// -------------------------------------------------------------------- +// Constructors and destructors + Cord::Cord(absl::string_view src, MethodIdentifier method) : contents_(InlineData::kDefaultInit) { - const size_t n = src.size(); - if (n <= InlineRep::kMaxInline) { + const size_t n = src.size(); + if (n <= InlineRep::kMaxInline) { contents_.set_data(src.data(), n, true); - } else { + } else { CordRep* rep = NewTree(src.data(), n, 0); contents_.EmplaceTree(rep, 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(std::string&& 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() { + } +} + +template Cord::Cord(std::string&& 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() { assert(contents_.is_tree()); CordzInfo::MaybeUntrackCord(contents_.cordz_info()); CordRep::Unref(VerifyTree(contents_.as_tree())); -} - -// -------------------------------------------------------------------- -// Mutators - -void Cord::Clear() { +} + +// -------------------------------------------------------------------- +// Mutators + +void Cord::Clear() { if (CordRep* tree = contents_.clear()) { CordRep::Unref(tree); } -} - +} + Cord& Cord::AssignLargeString(std::string&& src) { auto constexpr method = CordzUpdateTracker::kAssignString; assert(src.size() > kMaxBytesToCopy); @@ -631,21 +631,21 @@ Cord& Cord::AssignLargeString(std::string&& src) { return *this; } -Cord& Cord::operator=(absl::string_view src) { +Cord& Cord::operator=(absl::string_view src) { auto constexpr method = CordzUpdateTracker::kAssignString; - const char* data = src.data(); - size_t length = src.size(); - CordRep* tree = contents_.tree(); - if (length <= InlineRep::kMaxInline) { + const char* data = src.data(); + size_t length = src.size(); + CordRep* tree = contents_.tree(); + if (length <= InlineRep::kMaxInline) { // Embed into this->contents_, which is somewhat subtle: // - MaybeUntrackCord must be called before Unref(tree). // - MaybeUntrackCord must be called before set_data() clobbers cordz_info. // - set_data() must be called before Unref(tree) as it may reference tree. if (tree != nullptr) CordzInfo::MaybeUntrackCord(contents_.cordz_info()); - contents_.set_data(data, length, true); + contents_.set_data(data, length, true); if (tree != nullptr) CordRep::Unref(tree); - return *this; - } + return *this; + } if (tree != nullptr) { CordzUpdateScope scope(contents_.cordz_info(), method); if (tree->IsFlat() && tree->flat()->Capacity() >= length && @@ -658,28 +658,28 @@ Cord& Cord::operator=(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; -} - -// TODO(sanjay): Move to Cord::InlineRep section of file. For now, -// we keep it here to make diffs easier. + } + 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(absl::string_view src, MethodIdentifier method) { if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. - - size_t appended = 0; + + size_t appended = 0; CordRep* rep = tree(); const CordRep* const root = rep; CordzUpdateScope scope(root ? cordz_info() : nullptr, method); if (root != nullptr) { - char* region; + char* region; if (PrepareAppendRegion(rep, ®ion, &appended, src.size())) { memcpy(region, src.data(), appended); - } - } else { + } + } else { // Try to fit in the inline buffer if possible. size_t inline_length = inline_size(); if (src.size() <= kMaxInline - inline_length) { @@ -697,14 +697,14 @@ void Cord::InlineRep::AppendArray(absl::string_view src, memcpy(rep->flat()->Data(), data_.as_chars(), inline_length); memcpy(rep->flat()->Data() + inline_length, src.data(), appended); rep->length = inline_length + appended; - } - + } + src.remove_prefix(appended); if (src.empty()) { CommitTree(root, rep, scope, method); - return; - } - + return; + } + if (btree_enabled()) { // TODO(b/192061034): keep legacy 10% growth rate: consider other rates. rep = ForceBtree(rep); @@ -727,22 +727,22 @@ void Cord::InlineRep::AppendArray(absl::string_view src, rep = Concat(rep, NewTree(src.data(), src.size(), length - src.size())); } CommitTree(root, rep, scope, method); -} - -inline CordRep* Cord::TakeRep() const& { +} + +inline CordRep* Cord::TakeRep() const& { return CordRep::Ref(contents_.tree()); -} - -inline CordRep* Cord::TakeRep() && { - CordRep* rep = contents_.tree(); - contents_.clear(); - return rep; -} - -template <typename C> -inline void Cord::AppendImpl(C&& src) { +} + +inline CordRep* Cord::TakeRep() && { + CordRep* rep = contents_.tree(); + contents_.clear(); + return rep; +} + +template <typename C> +inline void Cord::AppendImpl(C&& src) { auto constexpr method = CordzUpdateTracker::kAppendCord; - if (empty()) { + if (empty()) { // Since destination is empty, we can avoid allocating a node, if (src.contents_.is_tree()) { // by taking the tree directly @@ -752,75 +752,75 @@ inline void Cord::AppendImpl(C&& src) { // or copying over inline data contents_.data_ = src.contents_.data_; } - return; - } - - // For short cords, it is faster to copy data if there is room in dst. - const size_t src_size = src.contents_.size(); - if (src_size <= kMaxBytesToCopy) { - CordRep* src_tree = src.contents_.tree(); - if (src_tree == nullptr) { - // src has embedded data. + return; + } + + // For short cords, it is faster to copy data if there is room in dst. + const size_t src_size = src.contents_.size(); + if (src_size <= kMaxBytesToCopy) { + CordRep* src_tree = src.contents_.tree(); + if (src_tree == nullptr) { + // src has embedded data. contents_.AppendArray({src.contents_.data(), src_size}, method); - return; - } + return; + } if (src_tree->IsFlat()) { - // src tree just has one flat node. + // src tree just has one flat node. contents_.AppendArray({src_tree->flat()->Data(), src_size}, method); - return; - } - if (&src == this) { - // ChunkIterator below assumes that src is not modified during traversal. - Append(Cord(src)); - return; - } - // TODO(mec): Should we only do this if "dst" has space? - for (absl::string_view chunk : src.Chunks()) { - Append(chunk); - } - return; - } - + return; + } + if (&src == this) { + // ChunkIterator below assumes that src is not modified during traversal. + Append(Cord(src)); + return; + } + // TODO(mec): Should we only do this if "dst" has space? + for (absl::string_view chunk : src.Chunks()) { + Append(chunk); + } + return; + } + // Guaranteed to be a tree (kMaxBytesToCopy > kInlinedSize) CordRep* rep = std::forward<C>(src).TakeRep(); contents_.AppendTree(rep, CordzUpdateTracker::kAppendCord); -} - +} + void Cord::Append(const Cord& src) { AppendImpl(src); } - + 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(absl::string_view(src)); - } else { + +template <typename T, Cord::EnableIfString<T>> +void Cord::Append(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Append(absl::string_view(src)); + } else { CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.AppendTree(rep, CordzUpdateTracker::kAppendString); - } -} - -template void Cord::Append(std::string&& src); - -void Cord::Prepend(const Cord& src) { - CordRep* src_tree = src.contents_.tree(); - if (src_tree != nullptr) { + } +} + +template void Cord::Append(std::string&& src); + +void Cord::Prepend(const Cord& src) { + CordRep* src_tree = src.contents_.tree(); + if (src_tree != nullptr) { CordRep::Ref(src_tree); contents_.PrependTree(src_tree, CordzUpdateTracker::kPrependCord); - return; - } - - // `src` cord is inlined. - absl::string_view src_contents(src.contents_.data(), src.contents_.size()); - return Prepend(src_contents); -} - + return; + } + + // `src` cord is inlined. + absl::string_view src_contents(src.contents_.data(), src.contents_.size()); + return Prepend(src_contents); +} + void Cord::PrependArray(absl::string_view src, MethodIdentifier method) { - if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. + 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) { @@ -832,116 +832,116 @@ void Cord::PrependArray(absl::string_view src, MethodIdentifier method) { 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(absl::string_view(src)); - } else { +} + +template <typename T, Cord::EnableIfString<T>> +inline void Cord::Prepend(T&& src) { + if (src.size() <= kMaxBytesToCopy) { + Prepend(absl::string_view(src)); + } else { CordRep* rep = CordRepFromString(std::forward<T>(src)); contents_.PrependTree(rep, CordzUpdateTracker::kPrependString); - } -} - -template void Cord::Prepend(std::string&& src); - -static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { - if (n >= node->length) return nullptr; + } +} + +template void Cord::Prepend(std::string&& src); + +static CordRep* RemovePrefixFrom(CordRep* node, size_t n) { + if (n >= node->length) return nullptr; if (n == 0) return CordRep::Ref(node); - absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack; - + absl::InlinedVector<CordRep*, kInlinedVectorSize> rhs_stack; + while (node->IsConcat()) { - assert(n <= node->length); - if (n < node->concat()->left->length) { - // Push right to stack, descend left. - rhs_stack.push_back(node->concat()->right); - node = node->concat()->left; - } else { - // Drop left, descend right. - n -= node->concat()->left->length; - node = node->concat()->right; - } - } - assert(n <= node->length); - - if (n == 0) { + assert(n <= node->length); + if (n < node->concat()->left->length) { + // Push right to stack, descend left. + rhs_stack.push_back(node->concat()->right); + node = node->concat()->left; + } else { + // Drop left, descend right. + n -= node->concat()->left->length; + node = node->concat()->right; + } + } + assert(n <= node->length); + + if (n == 0) { CordRep::Ref(node); - } else { - size_t start = n; - size_t len = node->length - n; + } else { + size_t start = n; + size_t len = node->length - n; if (node->IsSubstring()) { - // Consider in-place update of node, similar to in RemoveSuffixFrom(). - start += node->substring()->start; - node = node->substring()->child; - } + // Consider in-place update of node, similar to in RemoveSuffixFrom(). + start += node->substring()->start; + node = node->substring()->child; + } node = NewSubstring(CordRep::Ref(node), start, len); - } - while (!rhs_stack.empty()) { + } + while (!rhs_stack.empty()) { node = Concat(node, CordRep::Ref(rhs_stack.back())); - rhs_stack.pop_back(); - } - return node; -} - -// RemoveSuffixFrom() is very similar to RemovePrefixFrom(), with the -// exception that removing a suffix has an optimization where a node may be -// 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; + rhs_stack.pop_back(); + } + return node; +} + +// RemoveSuffixFrom() is very similar to RemovePrefixFrom(), with the +// exception that removing a suffix has an optimization where a node may be +// 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); - absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack; + absl::InlinedVector<CordRep*, kInlinedVectorSize> lhs_stack; bool inplace_ok = node->refcount.IsMutable(); - + while (node->IsConcat()) { - assert(n <= node->length); - if (n < node->concat()->right->length) { - // Push left to stack, descend right. - lhs_stack.push_back(node->concat()->left); - node = node->concat()->right; - } else { - // Drop right, descend left. - n -= node->concat()->right->length; - node = node->concat()->left; - } + assert(n <= node->length); + if (n < node->concat()->right->length) { + // Push left to stack, descend right. + lhs_stack.push_back(node->concat()->left); + node = node->concat()->right; + } else { + // Drop right, descend left. + n -= node->concat()->right->length; + node = node->concat()->left; + } inplace_ok = inplace_ok && node->refcount.IsMutable(); - } - assert(n <= node->length); - - if (n == 0) { + } + assert(n <= node->length); + + if (n == 0) { 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. + // Consider making a new buffer if the current node capacity is much + // larger than the new length. CordRep::Ref(node); - node->length -= n; - } else { - size_t start = 0; - size_t len = node->length - n; + node->length -= n; + } else { + size_t start = 0; + size_t len = node->length - n; if (node->IsSubstring()) { - start = node->substring()->start; - node = node->substring()->child; - } + start = node->substring()->start; + node = node->substring()->child; + } node = NewSubstring(CordRep::Ref(node), start, len); - } - while (!lhs_stack.empty()) { + } + while (!lhs_stack.empty()) { node = Concat(CordRep::Ref(lhs_stack.back()), node); - lhs_stack.pop_back(); - } - return node; -} - -void Cord::RemovePrefix(size_t n) { - ABSL_INTERNAL_CHECK(n <= size(), - absl::StrCat("Requested prefix size ", n, - " exceeds Cord's size ", size())); - CordRep* tree = contents_.tree(); - if (tree == nullptr) { - contents_.remove_prefix(n); - } else { + lhs_stack.pop_back(); + } + return node; +} + +void Cord::RemovePrefix(size_t n) { + ABSL_INTERNAL_CHECK(n <= size(), + absl::StrCat("Requested prefix size ", n, + " exceeds Cord's size ", size())); + CordRep* tree = contents_.tree(); + if (tree == nullptr) { + contents_.remove_prefix(n); + } else { auto constexpr method = CordzUpdateTracker::kRemovePrefix; CordzUpdateScope scope(contents_.cordz_info(), method); if (tree->IsBtree()) { @@ -954,17 +954,17 @@ void Cord::RemovePrefix(size_t n) { tree = VerifyTree(newrep); } contents_.SetTreeOrEmpty(tree, scope); - } -} - -void Cord::RemoveSuffix(size_t n) { - ABSL_INTERNAL_CHECK(n <= size(), - absl::StrCat("Requested suffix size ", n, - " exceeds Cord's size ", size())); - CordRep* tree = contents_.tree(); - if (tree == nullptr) { - contents_.reduce_size(n); - } else { + } +} + +void Cord::RemoveSuffix(size_t n) { + ABSL_INTERNAL_CHECK(n <= size(), + absl::StrCat("Requested suffix size ", n, + " exceeds Cord's size ", size())); + CordRep* tree = contents_.tree(); + if (tree == nullptr) { + contents_.reduce_size(n); + } else { auto constexpr method = CordzUpdateTracker::kRemoveSuffix; CordzUpdateScope scope(contents_.cordz_info(), method); if (tree->IsBtree()) { @@ -975,296 +975,296 @@ void Cord::RemoveSuffix(size_t n) { tree = VerifyTree(newrep); } contents_.SetTreeOrEmpty(tree, scope); - } -} - -// Work item for NewSubRange(). -struct SubRange { - SubRange(CordRep* a_node, size_t a_pos, size_t a_n) - : node(a_node), pos(a_pos), n(a_n) {} - CordRep* node; // nullptr means concat last 2 results. - size_t pos; - size_t n; -}; - -static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) { - absl::InlinedVector<CordRep*, kInlinedVectorSize> results; - absl::InlinedVector<SubRange, kInlinedVectorSize> todo; - todo.push_back(SubRange(node, pos, n)); - do { - const SubRange& sr = todo.back(); - node = sr.node; - pos = sr.pos; - n = sr.n; - todo.pop_back(); - - if (node == nullptr) { - assert(results.size() >= 2); - CordRep* right = results.back(); - results.pop_back(); - CordRep* left = results.back(); - results.pop_back(); - results.push_back(Concat(left, right)); - } else if (pos == 0 && n == node->length) { + } +} + +// Work item for NewSubRange(). +struct SubRange { + SubRange(CordRep* a_node, size_t a_pos, size_t a_n) + : node(a_node), pos(a_pos), n(a_n) {} + CordRep* node; // nullptr means concat last 2 results. + size_t pos; + size_t n; +}; + +static CordRep* NewSubRange(CordRep* node, size_t pos, size_t n) { + absl::InlinedVector<CordRep*, kInlinedVectorSize> results; + absl::InlinedVector<SubRange, kInlinedVectorSize> todo; + todo.push_back(SubRange(node, pos, n)); + do { + const SubRange& sr = todo.back(); + node = sr.node; + pos = sr.pos; + n = sr.n; + todo.pop_back(); + + if (node == nullptr) { + assert(results.size() >= 2); + CordRep* right = results.back(); + results.pop_back(); + CordRep* left = results.back(); + results.pop_back(); + results.push_back(Concat(left, right)); + } else if (pos == 0 && n == node->length) { results.push_back(CordRep::Ref(node)); } else if (!node->IsConcat()) { if (node->IsSubstring()) { - pos += node->substring()->start; - node = node->substring()->child; - } + pos += node->substring()->start; + node = node->substring()->child; + } 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) { - pos -= node->concat()->left->length; - todo.push_back(SubRange(node->concat()->right, pos, n)); - } else { - size_t left_n = node->concat()->left->length - pos; - todo.push_back(SubRange(nullptr, 0, 0)); // Concat() - todo.push_back(SubRange(node->concat()->right, 0, n - left_n)); - todo.push_back(SubRange(node->concat()->left, pos, left_n)); - } - } while (!todo.empty()); - assert(results.size() == 1); - return results[0]; -} - -Cord Cord::Subcord(size_t pos, size_t new_size) const { - Cord sub_cord; - size_t length = size(); - if (pos > length) pos = length; - if (new_size > length - pos) new_size = length - pos; + } else if (pos + n <= node->concat()->left->length) { + todo.push_back(SubRange(node->concat()->left, pos, n)); + } else if (pos >= node->concat()->left->length) { + pos -= node->concat()->left->length; + todo.push_back(SubRange(node->concat()->right, pos, n)); + } else { + size_t left_n = node->concat()->left->length - pos; + todo.push_back(SubRange(nullptr, 0, 0)); // Concat() + todo.push_back(SubRange(node->concat()->right, 0, n - left_n)); + todo.push_back(SubRange(node->concat()->left, pos, left_n)); + } + } while (!todo.empty()); + assert(results.size() == 1); + return results[0]; +} + +Cord Cord::Subcord(size_t pos, size_t new_size) const { + Cord sub_cord; + size_t length = size(); + if (pos > length) pos = length; + if (new_size > length - pos) new_size = length - pos; if (new_size == 0) return sub_cord; - CordRep* tree = contents_.tree(); - if (tree == nullptr) { - // sub_cord is newly constructed, no need to re-zero-out the tail of - // contents_ memory. - sub_cord.contents_.set_data(contents_.data() + pos, new_size, false); + CordRep* tree = contents_.tree(); + if (tree == nullptr) { + // sub_cord is newly constructed, no need to re-zero-out the tail of + // contents_ memory. + sub_cord.contents_.set_data(contents_.data() + pos, new_size, false); return sub_cord; } if (new_size <= InlineRep::kMaxInline) { char* dest = sub_cord.contents_.data_.as_chars(); - Cord::ChunkIterator it = chunk_begin(); - it.AdvanceBytes(pos); - size_t remaining_size = new_size; - while (remaining_size > it->size()) { - cord_internal::SmallMemmove(dest, it->data(), it->size()); - remaining_size -= it->size(); - dest += it->size(); - ++it; - } - cord_internal::SmallMemmove(dest, it->data(), remaining_size); + Cord::ChunkIterator it = chunk_begin(); + it.AdvanceBytes(pos); + size_t remaining_size = new_size; + while (remaining_size > it->size()) { + cord_internal::SmallMemmove(dest, it->data(), it->size()); + remaining_size -= it->size(); + dest += it->size(); + ++it; + } + cord_internal::SmallMemmove(dest, it->data(), remaining_size); sub_cord.contents_.set_inline_size(new_size); return sub_cord; } if (tree->IsBtree()) { tree = tree->btree()->SubTree(pos, new_size); - } else { + } else { tree = NewSubRange(tree, pos, new_size); - } + } sub_cord.contents_.EmplaceTree(tree, contents_.data_, CordzUpdateTracker::kSubCord); - return sub_cord; -} - -// -------------------------------------------------------------------- -// Balancing - -class CordForest { - public: - explicit CordForest(size_t length) - : root_length_(length), trees_(kMinLengthSize, nullptr) {} - - void Build(CordRep* cord_root) { - std::vector<CordRep*> pending = {cord_root}; - - while (!pending.empty()) { - CordRep* node = pending.back(); - pending.pop_back(); - CheckNode(node); + return sub_cord; +} + +// -------------------------------------------------------------------- +// Balancing + +class CordForest { + public: + explicit CordForest(size_t length) + : root_length_(length), trees_(kMinLengthSize, nullptr) {} + + void Build(CordRep* cord_root) { + std::vector<CordRep*> pending = {cord_root}; + + while (!pending.empty()) { + CordRep* node = pending.back(); + pending.pop_back(); + CheckNode(node); if (ABSL_PREDICT_FALSE(!node->IsConcat())) { - AddNode(node); - continue; - } - - CordRepConcat* concat_node = node->concat(); - if (concat_node->depth() >= kMinLengthSize || - concat_node->length < min_length[concat_node->depth()]) { - pending.push_back(concat_node->right); - pending.push_back(concat_node->left); - - if (concat_node->refcount.IsOne()) { - concat_node->left = concat_freelist_; - concat_freelist_ = concat_node; - } else { + AddNode(node); + continue; + } + + CordRepConcat* concat_node = node->concat(); + if (concat_node->depth() >= kMinLengthSize || + concat_node->length < min_length[concat_node->depth()]) { + pending.push_back(concat_node->right); + pending.push_back(concat_node->left); + + if (concat_node->refcount.IsOne()) { + concat_node->left = concat_freelist_; + concat_freelist_ = concat_node; + } else { CordRep::Ref(concat_node->right); CordRep::Ref(concat_node->left); CordRep::Unref(concat_node); - } - } else { - AddNode(node); - } - } - } - - CordRep* ConcatNodes() { - CordRep* sum = nullptr; - for (auto* node : trees_) { - if (node == nullptr) continue; - - sum = PrependNode(node, sum); - root_length_ -= node->length; - if (root_length_ == 0) break; - } - ABSL_INTERNAL_CHECK(sum != nullptr, "Failed to locate sum node"); - return VerifyTree(sum); - } - - private: - CordRep* AppendNode(CordRep* node, CordRep* sum) { - return (sum == nullptr) ? node : MakeConcat(sum, node); - } - - CordRep* PrependNode(CordRep* node, CordRep* sum) { - return (sum == nullptr) ? node : MakeConcat(node, sum); - } - - void AddNode(CordRep* node) { - CordRep* sum = nullptr; - - // 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]; - - if (tree_at_i == nullptr) continue; - sum = PrependNode(tree_at_i, sum); - tree_at_i = nullptr; - } - - sum = AppendNode(node, sum); - - // Insert sum into appropriate place in the forest - for (; sum->length >= min_length[i]; ++i) { - auto& tree_at_i = trees_[i]; - if (tree_at_i == nullptr) continue; - - sum = MakeConcat(tree_at_i, sum); - tree_at_i = nullptr; - } - - // min_length[0] == 1, which means sum->length >= min_length[0] - assert(i > 0); - trees_[i - 1] = sum; - } - - // Make concat node trying to resue existing CordRepConcat nodes we - // already collected in the concat_freelist_. - CordRep* MakeConcat(CordRep* left, CordRep* right) { - if (concat_freelist_ == nullptr) return RawConcat(left, right); - - CordRepConcat* rep = concat_freelist_; - if (concat_freelist_->left == nullptr) { - concat_freelist_ = nullptr; - } else { - concat_freelist_ = concat_freelist_->left->concat(); - } - SetConcatChildren(rep, left, right); - - return rep; - } - - static void CheckNode(CordRep* node) { - ABSL_INTERNAL_CHECK(node->length != 0u, ""); + } + } else { + AddNode(node); + } + } + } + + CordRep* ConcatNodes() { + CordRep* sum = nullptr; + for (auto* node : trees_) { + if (node == nullptr) continue; + + sum = PrependNode(node, sum); + root_length_ -= node->length; + if (root_length_ == 0) break; + } + ABSL_INTERNAL_CHECK(sum != nullptr, "Failed to locate sum node"); + return VerifyTree(sum); + } + + private: + CordRep* AppendNode(CordRep* node, CordRep* sum) { + return (sum == nullptr) ? node : MakeConcat(sum, node); + } + + CordRep* PrependNode(CordRep* node, CordRep* sum) { + return (sum == nullptr) ? node : MakeConcat(node, sum); + } + + void AddNode(CordRep* node) { + CordRep* sum = nullptr; + + // 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]; + + if (tree_at_i == nullptr) continue; + sum = PrependNode(tree_at_i, sum); + tree_at_i = nullptr; + } + + sum = AppendNode(node, sum); + + // Insert sum into appropriate place in the forest + for (; sum->length >= min_length[i]; ++i) { + auto& tree_at_i = trees_[i]; + if (tree_at_i == nullptr) continue; + + sum = MakeConcat(tree_at_i, sum); + tree_at_i = nullptr; + } + + // min_length[0] == 1, which means sum->length >= min_length[0] + assert(i > 0); + trees_[i - 1] = sum; + } + + // Make concat node trying to resue existing CordRepConcat nodes we + // already collected in the concat_freelist_. + CordRep* MakeConcat(CordRep* left, CordRep* right) { + if (concat_freelist_ == nullptr) return RawConcat(left, right); + + CordRepConcat* rep = concat_freelist_; + if (concat_freelist_->left == nullptr) { + concat_freelist_ = nullptr; + } else { + concat_freelist_ = concat_freelist_->left->concat(); + } + SetConcatChildren(rep, left, right); + + return rep; + } + + static void CheckNode(CordRep* node) { + ABSL_INTERNAL_CHECK(node->length != 0u, ""); if (node->IsConcat()) { - ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, ""); - ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, ""); - ABSL_INTERNAL_CHECK(node->length == (node->concat()->left->length + - node->concat()->right->length), - ""); - } - } - - size_t root_length_; - - // use an inlined vector instead of a flat array to get bounds checking - absl::InlinedVector<CordRep*, kInlinedVectorSize> trees_; - - // List of concat nodes we can re-use for Cord balancing. - CordRepConcat* concat_freelist_ = nullptr; -}; - -static CordRep* Rebalance(CordRep* node) { - VerifyTree(node); + ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, ""); + ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, ""); + ABSL_INTERNAL_CHECK(node->length == (node->concat()->left->length + + node->concat()->right->length), + ""); + } + } + + size_t root_length_; + + // use an inlined vector instead of a flat array to get bounds checking + absl::InlinedVector<CordRep*, kInlinedVectorSize> trees_; + + // List of concat nodes we can re-use for Cord balancing. + CordRepConcat* concat_freelist_ = nullptr; +}; + +static CordRep* Rebalance(CordRep* node) { + VerifyTree(node); assert(node->IsConcat()); - - if (node->length == 0) { - return nullptr; - } - - CordForest forest(node->length); - forest.Build(node); - return forest.ConcatNodes(); -} - -// -------------------------------------------------------------------- -// Comparators - -namespace { - -int ClampResult(int memcmp_res) { - return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0); -} - -int CompareChunks(absl::string_view* lhs, absl::string_view* rhs, - size_t* size_to_compare) { - size_t compared_size = std::min(lhs->size(), rhs->size()); - assert(*size_to_compare >= compared_size); - *size_to_compare -= compared_size; - - int memcmp_res = ::memcmp(lhs->data(), rhs->data(), compared_size); - if (memcmp_res != 0) return memcmp_res; - - lhs->remove_prefix(compared_size); - rhs->remove_prefix(compared_size); - - return 0; -} - -// This overload set computes comparison results from memcmp result. This -// interface is used inside GenericCompare below. Differet implementations -// are specialized for int and bool. For int we clamp result to {-1, 0, 1} -// set. For bool we just interested in "value == 0". -template <typename ResultType> -ResultType ComputeCompareResult(int memcmp_res) { - return ClampResult(memcmp_res); -} -template <> -bool ComputeCompareResult<bool>(int memcmp_res) { - return memcmp_res == 0; -} - -} // namespace - + + if (node->length == 0) { + return nullptr; + } + + CordForest forest(node->length); + forest.Build(node); + return forest.ConcatNodes(); +} + +// -------------------------------------------------------------------- +// Comparators + +namespace { + +int ClampResult(int memcmp_res) { + return static_cast<int>(memcmp_res > 0) - static_cast<int>(memcmp_res < 0); +} + +int CompareChunks(absl::string_view* lhs, absl::string_view* rhs, + size_t* size_to_compare) { + size_t compared_size = std::min(lhs->size(), rhs->size()); + assert(*size_to_compare >= compared_size); + *size_to_compare -= compared_size; + + int memcmp_res = ::memcmp(lhs->data(), rhs->data(), compared_size); + if (memcmp_res != 0) return memcmp_res; + + lhs->remove_prefix(compared_size); + rhs->remove_prefix(compared_size); + + return 0; +} + +// This overload set computes comparison results from memcmp result. This +// interface is used inside GenericCompare below. Differet implementations +// are specialized for int and bool. For int we clamp result to {-1, 0, 1} +// set. For bool we just interested in "value == 0". +template <typename ResultType> +ResultType ComputeCompareResult(int memcmp_res) { + return ClampResult(memcmp_res); +} +template <> +bool ComputeCompareResult<bool>(int memcmp_res) { + return memcmp_res == 0; +} + +} // namespace + // 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 absl::string_view Cord::InlineRep::FindFlatStartPiece() const { +inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const { if (!is_tree()) { return absl::string_view(data_.as_chars(), data_.inline_size()); - } - - CordRep* node = tree(); + } + + CordRep* node = tree(); if (node->IsFlat()) { return absl::string_view(node->flat()->Data(), node->length); - } - + } + if (node->IsExternal()) { - return absl::string_view(node->external()->base, node->length); - } - + return absl::string_view(node->external()->base, node->length); + } + if (node->IsBtree()) { CordRepBtree* tree = node->btree(); int height = tree->height(); @@ -1274,264 +1274,264 @@ inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const { return tree->Data(tree->begin()); } - // Walk down the left branches until we hit a non-CONCAT node. + // Walk down the left branches until we hit a non-CONCAT node. while (node->IsConcat()) { - node = node->concat()->left; - } - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; - assert(length != 0); - + node = node->concat()->left; + } + + // Get the child node if we encounter a SUBSTRING. + size_t offset = 0; + size_t length = node->length; + assert(length != 0); + if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - + offset = node->substring()->start; + node = node->substring()->child; + } + if (node->IsFlat()) { return absl::string_view(node->flat()->Data() + offset, length); - } - + } + assert(node->IsExternal() && "Expect FLAT or EXTERNAL node here"); - - return absl::string_view(node->external()->base + offset, length); -} - -inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size, - size_t size_to_compare) const { - auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { - if (!chunk->empty()) return true; - ++*it; - if (it->bytes_remaining_ == 0) return false; - *chunk = **it; - return true; - }; - - Cord::ChunkIterator lhs_it = chunk_begin(); - - // compared_size is inside first chunk. - absl::string_view lhs_chunk = - (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); - assert(compared_size <= lhs_chunk.size()); - assert(compared_size <= rhs.size()); - lhs_chunk.remove_prefix(compared_size); - rhs.remove_prefix(compared_size); - size_to_compare -= compared_size; // skip already compared size. - - while (advance(&lhs_it, &lhs_chunk) && !rhs.empty()) { - int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare); - if (comparison_result != 0) return comparison_result; - if (size_to_compare == 0) return 0; - } - - return static_cast<int>(rhs.empty()) - static_cast<int>(lhs_chunk.empty()); -} - -inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size, - size_t size_to_compare) const { - auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { - if (!chunk->empty()) return true; - ++*it; - if (it->bytes_remaining_ == 0) return false; - *chunk = **it; - return true; - }; - - Cord::ChunkIterator lhs_it = chunk_begin(); - Cord::ChunkIterator rhs_it = rhs.chunk_begin(); - - // compared_size is inside both first chunks. - absl::string_view lhs_chunk = - (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); - absl::string_view rhs_chunk = - (rhs_it.bytes_remaining_ != 0) ? *rhs_it : absl::string_view(); - assert(compared_size <= lhs_chunk.size()); - assert(compared_size <= rhs_chunk.size()); - lhs_chunk.remove_prefix(compared_size); - rhs_chunk.remove_prefix(compared_size); - size_to_compare -= compared_size; // skip already compared size. - - while (advance(&lhs_it, &lhs_chunk) && advance(&rhs_it, &rhs_chunk)) { - int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare); - if (memcmp_res != 0) return memcmp_res; - if (size_to_compare == 0) return 0; - } - - return static_cast<int>(rhs_chunk.empty()) - - static_cast<int>(lhs_chunk.empty()); -} - -inline absl::string_view Cord::GetFirstChunk(const Cord& c) { - return c.contents_.FindFlatStartPiece(); -} -inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) { - return sv; -} - -// Compares up to 'size_to_compare' bytes of 'lhs' with 'rhs'. It is assumed -// that 'size_to_compare' is greater that size of smallest of first chunks. -template <typename ResultType, typename RHS> -ResultType GenericCompare(const Cord& lhs, const RHS& rhs, - size_t size_to_compare) { - absl::string_view lhs_chunk = Cord::GetFirstChunk(lhs); - absl::string_view rhs_chunk = Cord::GetFirstChunk(rhs); - - size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size()); - assert(size_to_compare >= compared_size); - int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size); - if (compared_size == size_to_compare || memcmp_res != 0) { - return ComputeCompareResult<ResultType>(memcmp_res); - } - - return ComputeCompareResult<ResultType>( - lhs.CompareSlowPath(rhs, compared_size, size_to_compare)); -} - -bool Cord::EqualsImpl(absl::string_view rhs, size_t size_to_compare) const { - return GenericCompare<bool>(*this, rhs, size_to_compare); -} - -bool Cord::EqualsImpl(const Cord& rhs, size_t size_to_compare) const { - return GenericCompare<bool>(*this, rhs, size_to_compare); -} - -template <typename RHS> -inline int SharedCompareImpl(const Cord& lhs, const RHS& rhs) { - size_t lhs_size = lhs.size(); - size_t rhs_size = rhs.size(); - if (lhs_size == rhs_size) { - return GenericCompare<int>(lhs, rhs, lhs_size); - } - if (lhs_size < rhs_size) { - auto data_comp_res = GenericCompare<int>(lhs, rhs, lhs_size); - return data_comp_res == 0 ? -1 : data_comp_res; - } - - auto data_comp_res = GenericCompare<int>(lhs, rhs, rhs_size); - return data_comp_res == 0 ? +1 : data_comp_res; -} - -int Cord::Compare(absl::string_view rhs) const { - return SharedCompareImpl(*this, rhs); -} - -int Cord::CompareImpl(const Cord& rhs) const { - return SharedCompareImpl(*this, rhs); -} - -bool Cord::EndsWith(absl::string_view rhs) const { - size_t my_size = size(); - size_t rhs_size = rhs.size(); - - if (my_size < rhs_size) return false; - - Cord tmp(*this); - tmp.RemovePrefix(my_size - rhs_size); - return tmp.EqualsImpl(rhs, rhs_size); -} - -bool Cord::EndsWith(const Cord& rhs) const { - size_t my_size = size(); - size_t rhs_size = rhs.size(); - - if (my_size < rhs_size) return false; - - Cord tmp(*this); - tmp.RemovePrefix(my_size - rhs_size); - return tmp.EqualsImpl(rhs, rhs_size); -} - -// -------------------------------------------------------------------- -// Misc. - -Cord::operator std::string() const { - std::string s; - absl::CopyCordToString(*this, &s); - return s; -} - -void CopyCordToString(const Cord& src, std::string* dst) { - if (!src.contents_.is_tree()) { - src.contents_.CopyTo(dst); - } else { - absl::strings_internal::STLStringResizeUninitialized(dst, src.size()); - src.CopyToArraySlowPath(&(*dst)[0]); - } -} - -void Cord::CopyToArraySlowPath(char* dst) const { - assert(contents_.is_tree()); - absl::string_view fragment; - if (GetFlatAux(contents_.tree(), &fragment)) { - memcpy(dst, fragment.data(), fragment.size()); - return; - } - for (absl::string_view chunk : Chunks()) { - memcpy(dst, chunk.data(), chunk.size()); - dst += chunk.size(); - } -} - + + return absl::string_view(node->external()->base + offset, length); +} + +inline int Cord::CompareSlowPath(absl::string_view rhs, size_t compared_size, + size_t size_to_compare) const { + auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { + if (!chunk->empty()) return true; + ++*it; + if (it->bytes_remaining_ == 0) return false; + *chunk = **it; + return true; + }; + + Cord::ChunkIterator lhs_it = chunk_begin(); + + // compared_size is inside first chunk. + absl::string_view lhs_chunk = + (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); + assert(compared_size <= lhs_chunk.size()); + assert(compared_size <= rhs.size()); + lhs_chunk.remove_prefix(compared_size); + rhs.remove_prefix(compared_size); + size_to_compare -= compared_size; // skip already compared size. + + while (advance(&lhs_it, &lhs_chunk) && !rhs.empty()) { + int comparison_result = CompareChunks(&lhs_chunk, &rhs, &size_to_compare); + if (comparison_result != 0) return comparison_result; + if (size_to_compare == 0) return 0; + } + + return static_cast<int>(rhs.empty()) - static_cast<int>(lhs_chunk.empty()); +} + +inline int Cord::CompareSlowPath(const Cord& rhs, size_t compared_size, + size_t size_to_compare) const { + auto advance = [](Cord::ChunkIterator* it, absl::string_view* chunk) { + if (!chunk->empty()) return true; + ++*it; + if (it->bytes_remaining_ == 0) return false; + *chunk = **it; + return true; + }; + + Cord::ChunkIterator lhs_it = chunk_begin(); + Cord::ChunkIterator rhs_it = rhs.chunk_begin(); + + // compared_size is inside both first chunks. + absl::string_view lhs_chunk = + (lhs_it.bytes_remaining_ != 0) ? *lhs_it : absl::string_view(); + absl::string_view rhs_chunk = + (rhs_it.bytes_remaining_ != 0) ? *rhs_it : absl::string_view(); + assert(compared_size <= lhs_chunk.size()); + assert(compared_size <= rhs_chunk.size()); + lhs_chunk.remove_prefix(compared_size); + rhs_chunk.remove_prefix(compared_size); + size_to_compare -= compared_size; // skip already compared size. + + while (advance(&lhs_it, &lhs_chunk) && advance(&rhs_it, &rhs_chunk)) { + int memcmp_res = CompareChunks(&lhs_chunk, &rhs_chunk, &size_to_compare); + if (memcmp_res != 0) return memcmp_res; + if (size_to_compare == 0) return 0; + } + + return static_cast<int>(rhs_chunk.empty()) - + static_cast<int>(lhs_chunk.empty()); +} + +inline absl::string_view Cord::GetFirstChunk(const Cord& c) { + return c.contents_.FindFlatStartPiece(); +} +inline absl::string_view Cord::GetFirstChunk(absl::string_view sv) { + return sv; +} + +// Compares up to 'size_to_compare' bytes of 'lhs' with 'rhs'. It is assumed +// that 'size_to_compare' is greater that size of smallest of first chunks. +template <typename ResultType, typename RHS> +ResultType GenericCompare(const Cord& lhs, const RHS& rhs, + size_t size_to_compare) { + absl::string_view lhs_chunk = Cord::GetFirstChunk(lhs); + absl::string_view rhs_chunk = Cord::GetFirstChunk(rhs); + + size_t compared_size = std::min(lhs_chunk.size(), rhs_chunk.size()); + assert(size_to_compare >= compared_size); + int memcmp_res = ::memcmp(lhs_chunk.data(), rhs_chunk.data(), compared_size); + if (compared_size == size_to_compare || memcmp_res != 0) { + return ComputeCompareResult<ResultType>(memcmp_res); + } + + return ComputeCompareResult<ResultType>( + lhs.CompareSlowPath(rhs, compared_size, size_to_compare)); +} + +bool Cord::EqualsImpl(absl::string_view rhs, size_t size_to_compare) const { + return GenericCompare<bool>(*this, rhs, size_to_compare); +} + +bool Cord::EqualsImpl(const Cord& rhs, size_t size_to_compare) const { + return GenericCompare<bool>(*this, rhs, size_to_compare); +} + +template <typename RHS> +inline int SharedCompareImpl(const Cord& lhs, const RHS& rhs) { + size_t lhs_size = lhs.size(); + size_t rhs_size = rhs.size(); + if (lhs_size == rhs_size) { + return GenericCompare<int>(lhs, rhs, lhs_size); + } + if (lhs_size < rhs_size) { + auto data_comp_res = GenericCompare<int>(lhs, rhs, lhs_size); + return data_comp_res == 0 ? -1 : data_comp_res; + } + + auto data_comp_res = GenericCompare<int>(lhs, rhs, rhs_size); + return data_comp_res == 0 ? +1 : data_comp_res; +} + +int Cord::Compare(absl::string_view rhs) const { + return SharedCompareImpl(*this, rhs); +} + +int Cord::CompareImpl(const Cord& rhs) const { + return SharedCompareImpl(*this, rhs); +} + +bool Cord::EndsWith(absl::string_view rhs) const { + size_t my_size = size(); + size_t rhs_size = rhs.size(); + + if (my_size < rhs_size) return false; + + Cord tmp(*this); + tmp.RemovePrefix(my_size - rhs_size); + return tmp.EqualsImpl(rhs, rhs_size); +} + +bool Cord::EndsWith(const Cord& rhs) const { + size_t my_size = size(); + size_t rhs_size = rhs.size(); + + if (my_size < rhs_size) return false; + + Cord tmp(*this); + tmp.RemovePrefix(my_size - rhs_size); + return tmp.EqualsImpl(rhs, rhs_size); +} + +// -------------------------------------------------------------------- +// Misc. + +Cord::operator std::string() const { + std::string s; + absl::CopyCordToString(*this, &s); + return s; +} + +void CopyCordToString(const Cord& src, std::string* dst) { + if (!src.contents_.is_tree()) { + src.contents_.CopyTo(dst); + } else { + absl::strings_internal::STLStringResizeUninitialized(dst, src.size()); + src.CopyToArraySlowPath(&(*dst)[0]); + } +} + +void Cord::CopyToArraySlowPath(char* dst) const { + assert(contents_.is_tree()); + absl::string_view fragment; + if (GetFlatAux(contents_.tree(), &fragment)) { + memcpy(dst, fragment.data(), fragment.size()); + return; + } + for (absl::string_view chunk : Chunks()) { + memcpy(dst, chunk.data(), chunk.size()); + dst += chunk.size(); + } +} + 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. + 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(); - - // Walk down the left branches until we hit a non-CONCAT node. Save the - // right children to the stack for subsequent traversal. + + // 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); - node = node->concat()->left; - } - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; + node = node->concat()->left; + } + + // Get the child node if we encounter a SUBSTRING. + size_t offset = 0; + size_t length = node->length; if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - + offset = node->substring()->start; + node = node->substring()->child; + } + assert(node->IsExternal() || node->IsFlat()); - assert(length != 0); - const char* data = + assert(length != 0); + const char* data = node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset, length); - current_leaf_ = node; - return *this; -} - -Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { - ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && - "Attempted to iterate past `end()`"); - Cord subcord; + current_chunk_ = absl::string_view(data + offset, length); + current_leaf_ = node; + return *this; +} + +Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { + ABSL_HARDENING_ASSERT(bytes_remaining_ >= n && + "Attempted to iterate past `end()`"); + Cord subcord; auto constexpr method = CordzUpdateTracker::kCordReader; - - if (n <= InlineRep::kMaxInline) { - // Range to read fits in inline data. Flatten it. - char* data = subcord.contents_.set_data(n); - while (n > current_chunk_.size()) { - memcpy(data, current_chunk_.data(), current_chunk_.size()); - data += current_chunk_.size(); - n -= current_chunk_.size(); - ++*this; - } - memcpy(data, current_chunk_.data(), n); - if (n < current_chunk_.size()) { - RemoveChunkPrefix(n); - } else if (n > 0) { - ++*this; - } - return subcord; - } + + if (n <= InlineRep::kMaxInline) { + // Range to read fits in inline data. Flatten it. + char* data = subcord.contents_.set_data(n); + while (n > current_chunk_.size()) { + memcpy(data, current_chunk_.data(), current_chunk_.size()); + data += current_chunk_.size(); + n -= current_chunk_.size(); + ++*this; + } + memcpy(data, current_chunk_.data(), n); + if (n < current_chunk_.size()) { + RemoveChunkPrefix(n); + } else if (n > 0) { + ++*this; + } + return subcord; + } if (btree_reader_) { size_t chunk_size = current_chunk_.size(); @@ -1552,261 +1552,261 @@ Cord Cord::ChunkIterator::AdvanceAndReadBytes(size_t n) { } 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); + 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_); const char* data = subnode->IsExternal() ? subnode->external()->base : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, n); + subnode = NewSubstring(subnode, current_chunk_.data() - data, n); subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - RemoveChunkPrefix(n); - return subcord; - } - - // Range to read begins with a proper subrange of the current chunk. - assert(!current_chunk_.empty()); - assert(current_leaf_ != nullptr); + RemoveChunkPrefix(n); + return subcord; + } + + // 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_); - if (current_chunk_.size() < subnode->length) { + if (current_chunk_.size() < subnode->length) { const char* data = subnode->IsExternal() ? subnode->external()->base : subnode->flat()->Data(); - subnode = NewSubstring(subnode, current_chunk_.data() - data, - current_chunk_.size()); - } - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - - // 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; + subnode = NewSubstring(subnode, current_chunk_.data() - data, + current_chunk_.size()); + } + n -= current_chunk_.size(); + bytes_remaining_ -= current_chunk_.size(); + + // 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(); - if (node->length > n) break; - // TODO(qrczak): This might unnecessarily recreate existing concat nodes. - // Avoiding that would need pretty complicated logic (instead of + 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 - // 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). + // 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)); - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); + n -= node->length; + bytes_remaining_ -= node->length; + node = nullptr; + } + + if (node == nullptr) { + // We have reached the end of the Cord. + assert(bytes_remaining_ == 0); subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - return subcord; - } - - // Walk down the appropriate branches until we hit a non-CONCAT node. Save the - // right children to the stack for subsequent traversal. + return subcord; + } + + // Walk down the appropriate branches until we hit a non-CONCAT node. Save the + // right children to the stack for subsequent traversal. while (node->IsConcat()) { - if (node->concat()->left->length > n) { - // Push right, descend left. + if (node->concat()->left->length > n) { + // Push right, descend left. stack_of_right_children.push_back(node->concat()->right); - node = node->concat()->left; - } else { - // Read left, descend right. + node = node->concat()->left; + } else { + // Read left, descend right. subnode = Concat(subnode, CordRep::Ref(node->concat()->left)); - n -= node->concat()->left->length; - bytes_remaining_ -= node->concat()->left->length; - node = node->concat()->right; - } - } - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; + n -= node->concat()->left->length; + bytes_remaining_ -= node->concat()->left->length; + node = node->concat()->right; + } + } + + // Get the child node if we encounter a SUBSTRING. + size_t offset = 0; + size_t length = node->length; if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - - // Range to read ends with a proper (possibly empty) subrange of the current - // chunk. + offset = node->substring()->start; + node = node->substring()->child; + } + + // Range to read ends with a proper (possibly empty) subrange of the current + // chunk. assert(node->IsExternal() || node->IsFlat()); - assert(length > n); + assert(length > n); if (n > 0) { subnode = Concat(subnode, NewSubstring(CordRep::Ref(node), offset, n)); } - const char* data = + const char* data = node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; - bytes_remaining_ -= n; + current_chunk_ = absl::string_view(data + offset + n, length - n); + current_leaf_ = node; + bytes_remaining_ -= n; subcord.contents_.EmplaceTree(VerifyTree(subnode), method); - return subcord; -} - -void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { - assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); - assert(n >= current_chunk_.size()); // This should only be called when - // iterating to a new node. - - n -= current_chunk_.size(); - bytes_remaining_ -= current_chunk_.size(); - + return subcord; +} + +void Cord::ChunkIterator::AdvanceBytesSlowPath(size_t n) { + assert(bytes_remaining_ >= n && "Attempted to iterate past `end()`"); + assert(n >= current_chunk_.size()); // This should only be called when + // iterating to a new node. + + 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; } - // 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; + // 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(); - if (node->length > n) break; - n -= node->length; - bytes_remaining_ -= node->length; - node = nullptr; - } - - if (node == nullptr) { - // We have reached the end of the Cord. - assert(bytes_remaining_ == 0); - return; - } - - // Walk down the appropriate branches until we hit a non-CONCAT node. Save the - // right children to the stack for subsequent traversal. + if (node->length > n) break; + n -= node->length; + bytes_remaining_ -= node->length; + node = nullptr; + } + + if (node == nullptr) { + // We have reached the end of the Cord. + assert(bytes_remaining_ == 0); + return; + } + + // Walk down the appropriate branches until we hit a non-CONCAT node. Save the + // right children to the stack for subsequent traversal. while (node->IsConcat()) { - if (node->concat()->left->length > n) { - // Push right, descend left. + if (node->concat()->left->length > n) { + // Push right, descend left. stack_of_right_children.push_back(node->concat()->right); - node = node->concat()->left; - } else { - // Skip left, descend right. - n -= node->concat()->left->length; - bytes_remaining_ -= node->concat()->left->length; - node = node->concat()->right; - } - } - - // Get the child node if we encounter a SUBSTRING. - size_t offset = 0; - size_t length = node->length; + node = node->concat()->left; + } else { + // Skip left, descend right. + n -= node->concat()->left->length; + bytes_remaining_ -= node->concat()->left->length; + node = node->concat()->right; + } + } + + // Get the child node if we encounter a SUBSTRING. + size_t offset = 0; + size_t length = node->length; if (node->IsSubstring()) { - offset = node->substring()->start; - node = node->substring()->child; - } - + offset = node->substring()->start; + node = node->substring()->child; + } + assert(node->IsExternal() || node->IsFlat()); - assert(length > n); - const char* data = + assert(length > n); + const char* data = node->IsExternal() ? node->external()->base : node->flat()->Data(); - current_chunk_ = absl::string_view(data + offset + n, length - n); - current_leaf_ = node; - bytes_remaining_ -= n; -} - -char Cord::operator[](size_t i) const { - ABSL_HARDENING_ASSERT(i < size()); - size_t offset = i; - const CordRep* rep = contents_.tree(); - if (rep == nullptr) { - return contents_.data()[i]; - } - while (true) { - assert(rep != nullptr); - assert(offset < rep->length); + current_chunk_ = absl::string_view(data + offset + n, length - n); + current_leaf_ = node; + bytes_remaining_ -= n; +} + +char Cord::operator[](size_t i) const { + ABSL_HARDENING_ASSERT(i < size()); + size_t offset = i; + const CordRep* rep = contents_.tree(); + if (rep == nullptr) { + return contents_.data()[i]; + } + while (true) { + assert(rep != nullptr); + assert(offset < rep->length); if (rep->IsFlat()) { - // Get the "i"th character directly from the flat array. + // Get the "i"th character directly from the flat array. return rep->flat()->Data()[offset]; } else if (rep->IsBtree()) { return rep->btree()->GetCharacter(offset); } else if (rep->IsExternal()) { - // Get the "i"th character from the external array. - return rep->external()->base[offset]; + // Get the "i"th character from the external array. + return rep->external()->base[offset]; } else if (rep->IsConcat()) { - // Recursively branch to the side of the concatenation that the "i"th - // character is on. - size_t left_length = rep->concat()->left->length; - if (offset < left_length) { - rep = rep->concat()->left; - } else { - offset -= left_length; - rep = rep->concat()->right; - } - } else { - // This must be a substring a node, so bypass it to get to the child. + // Recursively branch to the side of the concatenation that the "i"th + // character is on. + size_t left_length = rep->concat()->left->length; + if (offset < left_length) { + rep = rep->concat()->left; + } else { + offset -= left_length; + rep = rep->concat()->right; + } + } else { + // This must be a substring a node, so bypass it to get to the child. assert(rep->IsSubstring()); - offset += rep->substring()->start; - rep = rep->substring()->child; - } - } -} - -absl::string_view Cord::FlattenSlowPath() { + offset += rep->substring()->start; + rep = rep->substring()->child; + } + } +} + +absl::string_view Cord::FlattenSlowPath() { assert(contents_.is_tree()); - size_t total_size = size(); - CordRep* new_rep; - char* new_buffer; - - // 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) { + size_t total_size = size(); + CordRep* new_rep; + char* new_buffer; + + // 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->length = total_size; + new_rep->length = total_size; new_buffer = new_rep->flat()->Data(); - CopyToArraySlowPath(new_buffer); - } else { - new_buffer = std::allocator<char>().allocate(total_size); - CopyToArraySlowPath(new_buffer); - new_rep = absl::cord_internal::NewExternalRep( - absl::string_view(new_buffer, total_size), [](absl::string_view s) { - std::allocator<char>().deallocate(const_cast<char*>(s.data()), - s.size()); - }); - } + CopyToArraySlowPath(new_buffer); + } else { + new_buffer = std::allocator<char>().allocate(total_size); + CopyToArraySlowPath(new_buffer); + new_rep = absl::cord_internal::NewExternalRep( + absl::string_view(new_buffer, total_size), [](absl::string_view s) { + std::allocator<char>().deallocate(const_cast<char*>(s.data()), + s.size()); + }); + } CordzUpdateScope scope(contents_.cordz_info(), CordzUpdateTracker::kFlatten); CordRep::Unref(contents_.as_tree()); contents_.SetTree(new_rep, scope); - return absl::string_view(new_buffer, total_size); -} - -/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) { - assert(rep != nullptr); + return absl::string_view(new_buffer, total_size); +} + +/* static */ bool Cord::GetFlatAux(CordRep* rep, absl::string_view* fragment) { + assert(rep != nullptr); if (rep->IsFlat()) { *fragment = absl::string_view(rep->flat()->Data(), rep->length); - return true; + return true; } else if (rep->IsExternal()) { - *fragment = absl::string_view(rep->external()->base, rep->length); - return true; + *fragment = absl::string_view(rep->external()->base, rep->length); + return true; } else if (rep->IsBtree()) { return rep->btree()->IsFlat(fragment); } else if (rep->IsSubstring()) { - CordRep* child = rep->substring()->child; + CordRep* child = rep->substring()->child; if (child->IsFlat()) { *fragment = absl::string_view( child->flat()->Data() + rep->substring()->start, rep->length); - return true; + return true; } else if (child->IsExternal()) { - *fragment = absl::string_view( - child->external()->base + rep->substring()->start, rep->length); - return true; + *fragment = absl::string_view( + child->external()->base + rep->substring()->start, rep->length); + return true; } else if (child->IsBtree()) { return child->btree()->IsFlat(rep->substring()->start, rep->length, fragment); - } - } - return false; -} - -/* static */ void Cord::ForEachChunkAux( - absl::cord_internal::CordRep* rep, - absl::FunctionRef<void(absl::string_view)> callback) { + } + } + return false; +} + +/* static */ void Cord::ForEachChunkAux( + absl::cord_internal::CordRep* rep, + absl::FunctionRef<void(absl::string_view)> callback) { if (rep->IsBtree()) { ChunkIterator it(rep), end; while (it != end) { @@ -1816,175 +1816,175 @@ absl::string_view Cord::FlattenSlowPath() { return; } - assert(rep != nullptr); - int stack_pos = 0; - constexpr int stack_max = 128; - // Stack of right branches for tree traversal - absl::cord_internal::CordRep* stack[stack_max]; - absl::cord_internal::CordRep* current_node = rep; - while (true) { + assert(rep != nullptr); + int stack_pos = 0; + constexpr int stack_max = 128; + // Stack of right branches for tree traversal + absl::cord_internal::CordRep* stack[stack_max]; + absl::cord_internal::CordRep* current_node = rep; + while (true) { if (current_node->IsConcat()) { - if (stack_pos == stack_max) { - // There's no more room on our stack array to add another right branch, - // and the idea is to avoid allocations, so call this function - // recursively to navigate this subtree further. (This is not something - // we expect to happen in practice). - ForEachChunkAux(current_node, callback); - - // Pop the next right branch and iterate. - current_node = stack[--stack_pos]; - continue; - } else { - // Save the right branch for later traversal and continue down the left - // branch. - stack[stack_pos++] = current_node->concat()->right; - current_node = current_node->concat()->left; - continue; - } - } - // This is a leaf node, so invoke our callback. - absl::string_view chunk; - bool success = GetFlatAux(current_node, &chunk); - assert(success); - if (success) { - callback(chunk); - } - if (stack_pos == 0) { - // end of traversal - return; - } - current_node = stack[--stack_pos]; - } -} - + if (stack_pos == stack_max) { + // There's no more room on our stack array to add another right branch, + // and the idea is to avoid allocations, so call this function + // recursively to navigate this subtree further. (This is not something + // we expect to happen in practice). + ForEachChunkAux(current_node, callback); + + // Pop the next right branch and iterate. + current_node = stack[--stack_pos]; + continue; + } else { + // Save the right branch for later traversal and continue down the left + // branch. + stack[stack_pos++] = current_node->concat()->right; + current_node = current_node->concat()->left; + continue; + } + } + // This is a leaf node, so invoke our callback. + absl::string_view chunk; + bool success = GetFlatAux(current_node, &chunk); + assert(success); + if (success) { + callback(chunk); + } + if (stack_pos == 0) { + // end of traversal + return; + } + current_node = stack[--stack_pos]; + } +} + static void DumpNode(CordRep* rep, bool include_data, std::ostream* os, int indent) { - const int kIndentStep = 1; - absl::InlinedVector<CordRep*, kInlinedVectorSize> stack; - absl::InlinedVector<int, kInlinedVectorSize> indents; - for (;;) { - *os << std::setw(3) << rep->refcount.Get(); - *os << " " << std::setw(7) << rep->length; - *os << " ["; - if (include_data) *os << static_cast<void*>(rep); - *os << "]"; - *os << " " << (IsRootBalanced(rep) ? 'b' : 'u'); - *os << " " << std::setw(indent) << ""; + const int kIndentStep = 1; + absl::InlinedVector<CordRep*, kInlinedVectorSize> stack; + absl::InlinedVector<int, kInlinedVectorSize> indents; + for (;;) { + *os << std::setw(3) << rep->refcount.Get(); + *os << " " << std::setw(7) << rep->length; + *os << " ["; + if (include_data) *os << static_cast<void*>(rep); + *os << "]"; + *os << " " << (IsRootBalanced(rep) ? 'b' : 'u'); + *os << " " << std::setw(indent) << ""; if (rep->IsConcat()) { - *os << "CONCAT depth=" << Depth(rep) << "\n"; - indent += kIndentStep; - indents.push_back(indent); - stack.push_back(rep->concat()->right); - rep = rep->concat()->left; + *os << "CONCAT depth=" << Depth(rep) << "\n"; + indent += kIndentStep; + indents.push_back(indent); + stack.push_back(rep->concat()->right); + rep = rep->concat()->left; } else if (rep->IsSubstring()) { - *os << "SUBSTRING @ " << rep->substring()->start << "\n"; - indent += kIndentStep; - rep = rep->substring()->child; + *os << "SUBSTRING @ " << rep->substring()->start << "\n"; + indent += kIndentStep; + rep = rep->substring()->child; } else { // Leaf or ring if (rep->IsExternal()) { - *os << "EXTERNAL ["; - if (include_data) - *os << absl::CEscape(std::string(rep->external()->base, rep->length)); - *os << "]\n"; + *os << "EXTERNAL ["; + if (include_data) + *os << absl::CEscape(std::string(rep->external()->base, rep->length)); + *os << "]\n"; } else if (rep->IsFlat()) { *os << "FLAT cap=" << rep->flat()->Capacity() << " ["; - if (include_data) + if (include_data) *os << absl::CEscape(std::string(rep->flat()->Data(), rep->length)); - *os << "]\n"; + *os << "]\n"; } else { CordRepBtree::Dump(rep, /*label=*/ "", include_data, *os); - } - if (stack.empty()) break; - rep = stack.back(); - stack.pop_back(); - indent = indents.back(); - indents.pop_back(); - } - } - ABSL_INTERNAL_CHECK(indents.empty(), ""); -} - -static std::string ReportError(CordRep* root, CordRep* node) { - std::ostringstream buf; - buf << "Error at node " << node << " in:"; - DumpNode(root, true, &buf); - return buf.str(); -} - -static bool VerifyNode(CordRep* root, CordRep* start_node, - bool full_validation) { - absl::InlinedVector<CordRep*, 2> worklist; - worklist.push_back(start_node); - do { - CordRep* node = worklist.back(); - worklist.pop_back(); - - ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node)); - if (node != root) { - ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node)); - } - + } + if (stack.empty()) break; + rep = stack.back(); + stack.pop_back(); + indent = indents.back(); + indents.pop_back(); + } + } + ABSL_INTERNAL_CHECK(indents.empty(), ""); +} + +static std::string ReportError(CordRep* root, CordRep* node) { + std::ostringstream buf; + buf << "Error at node " << node << " in:"; + DumpNode(root, true, &buf); + return buf.str(); +} + +static bool VerifyNode(CordRep* root, CordRep* start_node, + bool full_validation) { + absl::InlinedVector<CordRep*, 2> worklist; + worklist.push_back(start_node); + do { + CordRep* node = worklist.back(); + worklist.pop_back(); + + ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node)); + if (node != root) { + ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node)); + } + if (node->IsConcat()) { - ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, - ReportError(root, node)); - ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, - ReportError(root, node)); - ABSL_INTERNAL_CHECK((node->length == node->concat()->left->length + - node->concat()->right->length), - ReportError(root, node)); - if (full_validation) { - worklist.push_back(node->concat()->right); - worklist.push_back(node->concat()->left); - } + ABSL_INTERNAL_CHECK(node->concat()->left != nullptr, + ReportError(root, node)); + ABSL_INTERNAL_CHECK(node->concat()->right != nullptr, + ReportError(root, node)); + ABSL_INTERNAL_CHECK((node->length == node->concat()->left->length + + node->concat()->right->length), + ReportError(root, node)); + if (full_validation) { + worklist.push_back(node->concat()->right); + worklist.push_back(node->concat()->left); + } } else if (node->IsFlat()) { ABSL_INTERNAL_CHECK(node->length <= node->flat()->Capacity(), ReportError(root, node)); } else if (node->IsExternal()) { - ABSL_INTERNAL_CHECK(node->external()->base != nullptr, - ReportError(root, node)); + ABSL_INTERNAL_CHECK(node->external()->base != nullptr, + ReportError(root, node)); } else if (node->IsSubstring()) { - ABSL_INTERNAL_CHECK( - node->substring()->start < node->substring()->child->length, - ReportError(root, node)); - ABSL_INTERNAL_CHECK(node->substring()->start + node->length <= - node->substring()->child->length, - ReportError(root, node)); - } - } while (!worklist.empty()); - return true; -} - -// Traverses the tree and computes the total memory allocated. -/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) { - size_t total_mem_usage = 0; - - // Allow a quick exit for the common case that the root is a leaf. - if (RepMemoryUsageLeaf(rep, &total_mem_usage)) { - return total_mem_usage; - } - - // Iterate over the tree. cur_node is never a leaf node and leaf nodes will - // never be appended to tree_stack. This reduces overhead from manipulating - // tree_stack. - absl::InlinedVector<const CordRep*, kInlinedVectorSize> tree_stack; - const CordRep* cur_node = rep; - while (true) { - const CordRep* next_node = nullptr; - + ABSL_INTERNAL_CHECK( + node->substring()->start < node->substring()->child->length, + ReportError(root, node)); + ABSL_INTERNAL_CHECK(node->substring()->start + node->length <= + node->substring()->child->length, + ReportError(root, node)); + } + } while (!worklist.empty()); + return true; +} + +// Traverses the tree and computes the total memory allocated. +/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) { + size_t total_mem_usage = 0; + + // Allow a quick exit for the common case that the root is a leaf. + if (RepMemoryUsageLeaf(rep, &total_mem_usage)) { + return total_mem_usage; + } + + // Iterate over the tree. cur_node is never a leaf node and leaf nodes will + // never be appended to tree_stack. This reduces overhead from manipulating + // tree_stack. + absl::InlinedVector<const CordRep*, kInlinedVectorSize> tree_stack; + const CordRep* cur_node = rep; + while (true) { + const CordRep* next_node = nullptr; + if (cur_node->IsConcat()) { - total_mem_usage += sizeof(CordRepConcat); - const CordRep* left = cur_node->concat()->left; - if (!RepMemoryUsageLeaf(left, &total_mem_usage)) { - next_node = left; - } - - const CordRep* right = cur_node->concat()->right; - if (!RepMemoryUsageLeaf(right, &total_mem_usage)) { - if (next_node) { - tree_stack.push_back(next_node); - } - next_node = right; - } + total_mem_usage += sizeof(CordRepConcat); + const CordRep* left = cur_node->concat()->left; + if (!RepMemoryUsageLeaf(left, &total_mem_usage)) { + next_node = left; + } + + const CordRep* right = cur_node->concat()->right; + if (!RepMemoryUsageLeaf(right, &total_mem_usage)) { + if (next_node) { + tree_stack.push_back(next_node); + } + next_node = right; + } } else if (cur_node->IsBtree()) { total_mem_usage += sizeof(CordRepBtree); const CordRepBtree* node = cur_node->btree(); @@ -1997,51 +1997,51 @@ static bool VerifyNode(CordRep* root, CordRep* start_node, tree_stack.push_back(edge); } } - } else { - // Since cur_node is not a leaf or a concat node it must be a substring. + } else { + // Since cur_node is not a leaf or a concat node it must be a substring. assert(cur_node->IsSubstring()); - total_mem_usage += sizeof(CordRepSubstring); - next_node = cur_node->substring()->child; - if (RepMemoryUsageLeaf(next_node, &total_mem_usage)) { - next_node = nullptr; - } - } - - if (!next_node) { - if (tree_stack.empty()) { - return total_mem_usage; - } - next_node = tree_stack.back(); - tree_stack.pop_back(); - } - cur_node = next_node; - } -} - -std::ostream& operator<<(std::ostream& out, const Cord& cord) { - for (absl::string_view chunk : cord.Chunks()) { - out.write(chunk.data(), chunk.size()); - } - return out; -} - -namespace strings_internal { + total_mem_usage += sizeof(CordRepSubstring); + next_node = cur_node->substring()->child; + if (RepMemoryUsageLeaf(next_node, &total_mem_usage)) { + next_node = nullptr; + } + } + + if (!next_node) { + if (tree_stack.empty()) { + return total_mem_usage; + } + next_node = tree_stack.back(); + tree_stack.pop_back(); + } + cur_node = next_node; + } +} + +std::ostream& operator<<(std::ostream& out, const Cord& cord) { + for (absl::string_view chunk : cord.Chunks()) { + out.write(chunk.data(), chunk.size()); + } + return out; +} + +namespace strings_internal { size_t CordTestAccess::FlatOverhead() { return cord_internal::kFlatOverhead; } size_t CordTestAccess::MaxFlatLength() { return cord_internal::kMaxFlatLength; } -size_t CordTestAccess::FlatTagToLength(uint8_t tag) { +size_t CordTestAccess::FlatTagToLength(uint8_t tag) { return cord_internal::TagToLength(tag); -} -uint8_t CordTestAccess::LengthToTag(size_t s) { - ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s)); +} +uint8_t CordTestAccess::LengthToTag(size_t s) { + ABSL_INTERNAL_CHECK(s <= kMaxFlatLength, absl::StrCat("Invalid length ", s)); return cord_internal::AllocatedSizeToTag(s + cord_internal::kFlatOverhead); -} -size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); } -size_t CordTestAccess::SizeofCordRepExternal() { - return sizeof(CordRepExternal); -} -size_t CordTestAccess::SizeofCordRepSubstring() { - return sizeof(CordRepSubstring); -} -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl +} +size_t CordTestAccess::SizeofCordRepConcat() { return sizeof(CordRepConcat); } +size_t CordTestAccess::SizeofCordRepExternal() { + return sizeof(CordRepExternal); +} +size_t CordTestAccess::SizeofCordRepSubstring() { + return sizeof(CordRepSubstring); +} +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/cord.h b/contrib/restricted/abseil-cpp/absl/strings/cord.h index f0a1991471..d5753e5839 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/cord.h +++ b/contrib/restricted/abseil-cpp/absl/strings/cord.h @@ -1,84 +1,84 @@ -// 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. -// -// ----------------------------------------------------------------------------- -// File: cord.h -// ----------------------------------------------------------------------------- -// -// This file defines the `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 `std::string`, 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 +// 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. +// +// ----------------------------------------------------------------------------- +// File: cord.h +// ----------------------------------------------------------------------------- +// +// This file defines the `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 `std::string`, 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 // `std::string`, 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 `std::string` 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 `std::string`. -// -// Thread Safety -// -// Cord has the same thread-safety properties as many other types like -// std::string, 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. - -#ifndef ABSL_STRINGS_CORD_H_ -#define ABSL_STRINGS_CORD_H_ - -#include <algorithm> -#include <cstddef> -#include <cstdint> -#include <cstring> -#include <iosfwd> -#include <iterator> -#include <string> -#include <type_traits> - +// 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 `std::string` 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 `std::string`. +// +// Thread Safety +// +// Cord has the same thread-safety properties as many other types like +// std::string, 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. + +#ifndef ABSL_STRINGS_CORD_H_ +#define ABSL_STRINGS_CORD_H_ + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <iosfwd> +#include <iterator> +#include <string> +#include <type_traits> + #include "absl/base/config.h" -#include "absl/base/internal/endian.h" -#include "absl/base/internal/per_thread_tls.h" -#include "absl/base/macros.h" -#include "absl/base/port.h" -#include "absl/container/inlined_vector.h" -#include "absl/functional/function_ref.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/internal/cord_internal.h" +#include "absl/base/internal/endian.h" +#include "absl/base/internal/per_thread_tls.h" +#include "absl/base/macros.h" +#include "absl/base/port.h" +#include "absl/container/inlined_vector.h" +#include "absl/functional/function_ref.h" +#include "absl/meta/type_traits.h" +#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree_reader.h" #include "absl/strings/internal/cord_rep_ring.h" @@ -87,287 +87,287 @@ #include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_tracker.h" -#include "absl/strings/internal/resize_uninitialized.h" +#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/string_constant.h" -#include "absl/strings/string_view.h" -#include "absl/types/optional.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -class Cord; -class CordTestPeer; -template <typename Releaser> -Cord MakeCordFromExternal(absl::string_view, Releaser&&); -void CopyCordToString(const Cord& src, std::string* dst); - -// Cord -// -// A Cord is a sequence of characters, designed to be more efficient than a -// `std::string` 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 `std::string` -// -// Additionally, the API provides iterator utilities to iterate through Cord -// data via chunks or character bytes. -// -class Cord { - private: - template <typename T> - using EnableIfString = - absl::enable_if_t<std::is_same<T, std::string>::value, int>; - - public: - // Cord::Cord() Constructors. - - // 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. - 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 - // `absl::string_view`. - explicit Cord(absl::string_view src); - Cord& operator=(absl::string_view src); - - // Creates a Cord from a `std::string&&` rvalue. These constructors are - // templated to avoid ambiguities for types that are convertible to both - // `absl::string_view` and `std::string`, such as `const char*`. - template <typename T, EnableIfString<T> = 0> - explicit Cord(T&& src); - template <typename T, EnableIfString<T> = 0> - Cord& operator=(T&& src); - - // 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()(absl::string_view) const` or `void operator()` - // - // Example: - // - // Cord MakeCord(BlockPool* pool) { - // Block* block = pool->NewBlock(); - // FillBlock(block); - // return absl::MakeCordFromExternal( - // block->ToStringView(), - // [pool, block](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: - // - // void Foo(const char* buffer, int len) { - // auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len), - // [](absl::string_view) {}); - // - // // BUG: If Bar() copies its cord for any reason, including keeping a - // // substring of it, the lifetime of buffer might be extended beyond - // // when Foo() returns. - // Bar(c); - // } - template <typename Releaser> - friend Cord MakeCordFromExternal(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. - void Clear(); - - // 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(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. - void Prepend(const Cord& src); - void Prepend(absl::string_view src); - template <typename T, EnableIfString<T> = 0> - void Prepend(T&& src); - - // 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 - // *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; - - // swap() - // - // Swaps the contents of two Cords. +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +class Cord; +class CordTestPeer; +template <typename Releaser> +Cord MakeCordFromExternal(absl::string_view, Releaser&&); +void CopyCordToString(const Cord& src, std::string* dst); + +// Cord +// +// A Cord is a sequence of characters, designed to be more efficient than a +// `std::string` 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 `std::string` +// +// Additionally, the API provides iterator utilities to iterate through Cord +// data via chunks or character bytes. +// +class Cord { + private: + template <typename T> + using EnableIfString = + absl::enable_if_t<std::is_same<T, std::string>::value, int>; + + public: + // Cord::Cord() Constructors. + + // 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. + 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 + // `absl::string_view`. + explicit Cord(absl::string_view src); + Cord& operator=(absl::string_view src); + + // Creates a Cord from a `std::string&&` rvalue. These constructors are + // templated to avoid ambiguities for types that are convertible to both + // `absl::string_view` and `std::string`, such as `const char*`. + template <typename T, EnableIfString<T> = 0> + explicit Cord(T&& src); + template <typename T, EnableIfString<T> = 0> + Cord& operator=(T&& src); + + // 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()(absl::string_view) const` or `void operator()` + // + // Example: + // + // Cord MakeCord(BlockPool* pool) { + // Block* block = pool->NewBlock(); + // FillBlock(block); + // return absl::MakeCordFromExternal( + // block->ToStringView(), + // [pool, block](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: + // + // void Foo(const char* buffer, int len) { + // auto c = absl::MakeCordFromExternal(absl::string_view(buffer, len), + // [](absl::string_view) {}); + // + // // BUG: If Bar() copies its cord for any reason, including keeping a + // // substring of it, the lifetime of buffer might be extended beyond + // // when Foo() returns. + // Bar(c); + // } + template <typename Releaser> + friend Cord MakeCordFromExternal(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. + void Clear(); + + // 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(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. + void Prepend(const Cord& src); + void Prepend(absl::string_view src); + template <typename T, EnableIfString<T> = 0> + void Prepend(T&& src); + + // 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 + // *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; + + // 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. - size_t size() const; - - // 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. - 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: - // - // -1 'this' Cord is smaller - // 0 two Cords are equal - // 1 'this' Cord is larger - int Compare(absl::string_view rhs) const; - int Compare(const Cord& rhs) const; - - // Cord::StartsWith() - // - // Determines whether the Cord starts with the passed string data `rhs`. - bool StartsWith(const Cord& rhs) const; - bool StartsWith(absl::string_view rhs) const; - + + // 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. + 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. + 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: + // + // -1 'this' Cord is smaller + // 0 two Cords are equal + // 1 'this' Cord is larger + int Compare(absl::string_view rhs) const; + int Compare(const Cord& rhs) const; + + // Cord::StartsWith() + // + // Determines whether the Cord starts with the passed string data `rhs`. + bool StartsWith(const Cord& rhs) const; + bool StartsWith(absl::string_view rhs) const; + // Cord::EndsWith() - // - // Determines whether the Cord ends with the passed string data `rhs`. - bool EndsWith(absl::string_view rhs) const; - bool EndsWith(const Cord& rhs) const; - - // Cord::operator std::string() - // - // Converts a Cord into a `std::string()`. This operator is marked explicit to - // prevent unintended Cord usage in functions that take a string. - explicit operator std::string() const; - - // CopyCordToString() - // - // 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 - // object, prefer to simply use the conversion operator to `std::string`. - friend void CopyCordToString(const Cord& src, std::string* dst); - - 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. - // * 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 - // nodes and are imbalanced due to sharing. Prefer to pass this type by - // const reference instead of by value. - class ChunkIterator { - public: - using iterator_category = std::input_iterator_tag; - using value_type = absl::string_view; - using difference_type = ptrdiff_t; - using pointer = const value_type*; - using reference = value_type; - - ChunkIterator() = default; - - ChunkIterator& operator++(); - ChunkIterator operator++(int); - bool operator==(const ChunkIterator& other) const; - bool operator!=(const ChunkIterator& other) const; - reference operator*() const; - pointer operator->() const; - - friend class Cord; - friend class CharIterator; - - private: + // + // Determines whether the Cord ends with the passed string data `rhs`. + bool EndsWith(absl::string_view rhs) const; + bool EndsWith(const Cord& rhs) const; + + // Cord::operator std::string() + // + // Converts a Cord into a `std::string()`. This operator is marked explicit to + // prevent unintended Cord usage in functions that take a string. + explicit operator std::string() const; + + // CopyCordToString() + // + // 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 + // object, prefer to simply use the conversion operator to `std::string`. + friend void CopyCordToString(const Cord& src, std::string* dst); + + 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. + // * 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 + // nodes and are imbalanced due to sharing. Prefer to pass this type by + // const reference instead of by value. + class ChunkIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = absl::string_view; + using difference_type = ptrdiff_t; + using pointer = const value_type*; + using reference = value_type; + + ChunkIterator() = default; + + ChunkIterator& operator++(); + ChunkIterator operator++(int); + bool operator==(const ChunkIterator& other) const; + bool operator!=(const ChunkIterator& other) const; + reference operator*() const; + pointer operator->() const; + + friend class Cord; + friend class CharIterator; + + private: using CordRep = absl::cord_internal::CordRep; using CordRepBtree = absl::cord_internal::CordRepBtree; using CordRepBtreeReader = absl::cord_internal::CordRepBtreeReader; @@ -381,17 +381,17 @@ class Cord { // 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); - + // 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); - // 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); + // 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(); @@ -400,66 +400,66 @@ class Cord { 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); - - // A view into bytes of the current `CordRep`. It may only be a view to a - // suffix of bytes if this is being used by `CharIterator`. - absl::string_view current_chunk_; - // The current leaf, or `nullptr` if the iterator points to short data. - // If the current chunk is a substring node, current_leaf_ points to the - // underlying flat or external node. - absl::cord_internal::CordRep* current_leaf_ = nullptr; - // The number of bytes left in the `Cord` over which we are iterating. - size_t bytes_remaining_ = 0; + // Iterates `n` bytes, where `n` is expected to be greater than or equal to + // `current_chunk_.size()`. + void AdvanceBytesSlowPath(size_t n); + + // A view into bytes of the current `CordRep`. It may only be a view to a + // suffix of bytes if this is being used by `CharIterator`. + absl::string_view current_chunk_; + // The current leaf, or `nullptr` if the iterator points to short data. + // If the current chunk is a substring node, current_leaf_ points to the + // underlying flat or external node. + absl::cord_internal::CordRep* current_leaf_ = nullptr; + // 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_; - }; - - // 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. - // - // Example: - // - // absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c, - // absl::string_view s) { - // return std::find(c.chunk_begin(), c.chunk_end(), s); - // } - ChunkIterator chunk_begin() const; - - // 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. - 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()`. - class ChunkRange { - public: + }; + + // 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. + // + // Example: + // + // absl::Cord::ChunkIterator FindAsChunk(const absl::Cord& c, + // absl::string_view s) { + // return std::find(c.chunk_begin(), c.chunk_end(), s); + // } + ChunkIterator chunk_begin() const; + + // 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. + 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()`. + class ChunkRange { + public: // Fulfill minimum c++ container requirements [container.requirements] // Theses (partial) container type definitions allow ChunkRange to be used // in various utilities expecting a subset of [container.requirements]. @@ -470,137 +470,137 @@ class Cord { using iterator = ChunkIterator; using const_iterator = ChunkIterator; - explicit ChunkRange(const Cord* cord) : cord_(cord) {} - - ChunkIterator begin() const; - ChunkIterator end() const; - - private: - 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. - // - // Example: - // - // void ProcessChunks(const Cord& cord) { - // for (absl::string_view chunk : cord.Chunks()) { ... } - // } - // - // Note that the ordinary caveats of temporary lifetime extension apply: - // - // void Process() { - // for (absl::string_view chunk : CordFactory().Chunks()) { - // // The temporary Cord returned by CordFactory has been destroyed! - // } - // } - 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 - // 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. - class CharIterator { - public: - using iterator_category = std::input_iterator_tag; - using value_type = char; - using difference_type = ptrdiff_t; - using pointer = const char*; - using reference = const char&; - - CharIterator() = default; - - CharIterator& operator++(); - CharIterator operator++(int); - bool operator==(const CharIterator& other) const; - bool operator!=(const CharIterator& other) const; - reference operator*() const; - pointer operator->() const; - - friend Cord; - - private: - explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {} - - ChunkIterator chunk_iterator_; - }; - - // 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`. - static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes); - - // 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`. - static void Advance(CharIterator* it, size_t n_bytes); - - // Cord::CharIterator::ChunkRemaining() - // - // Returns the longest contiguous view starting at the iterator's position. - // - // `it` must be dereferenceable. - static absl::string_view ChunkRemaining(const CharIterator& it); - - // 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. - CharIterator char_begin() const; - - // 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. - 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. - // - // Implementation note: `CharRange` is simply a convenience wrapper over - // `Cord::char_begin()` and `Cord::char_end()`. - class CharRange { - public: + explicit ChunkRange(const Cord* cord) : cord_(cord) {} + + ChunkIterator begin() const; + ChunkIterator end() const; + + private: + 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. + // + // Example: + // + // void ProcessChunks(const Cord& cord) { + // for (absl::string_view chunk : cord.Chunks()) { ... } + // } + // + // Note that the ordinary caveats of temporary lifetime extension apply: + // + // void Process() { + // for (absl::string_view chunk : CordFactory().Chunks()) { + // // The temporary Cord returned by CordFactory has been destroyed! + // } + // } + 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 + // 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. + class CharIterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = char; + using difference_type = ptrdiff_t; + using pointer = const char*; + using reference = const char&; + + CharIterator() = default; + + CharIterator& operator++(); + CharIterator operator++(int); + bool operator==(const CharIterator& other) const; + bool operator!=(const CharIterator& other) const; + reference operator*() const; + pointer operator->() const; + + friend Cord; + + private: + explicit CharIterator(const Cord* cord) : chunk_iterator_(cord) {} + + ChunkIterator chunk_iterator_; + }; + + // 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`. + static Cord AdvanceAndRead(CharIterator* it, size_t n_bytes); + + // 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`. + static void Advance(CharIterator* it, size_t n_bytes); + + // Cord::CharIterator::ChunkRemaining() + // + // Returns the longest contiguous view starting at the iterator's position. + // + // `it` must be dereferenceable. + static absl::string_view ChunkRemaining(const CharIterator& it); + + // 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. + CharIterator char_begin() const; + + // 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. + 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. + // + // 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] // Theses (partial) container type definitions allow CharRange to be used // in various utilities expecting a subset of [container.requirements]. @@ -611,75 +611,75 @@ class Cord { using iterator = CharIterator; using const_iterator = CharIterator; - explicit CharRange(const Cord* cord) : cord_(cord) {} - - CharIterator begin() const; - CharIterator end() const; - - private: - 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. - // - // Example: - // - // void ProcessCord(const Cord& cord) { - // for (char c : cord.Chars()) { ... } - // } - // - // Note that the ordinary caveats of temporary lifetime extension apply: - // - // void Process() { - // for (char c : CordFactory().Chars()) { - // // The temporary Cord returned by CordFactory has been destroyed! - // } - // } - 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, - // 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. - 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. - absl::optional<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. - absl::string_view Flatten(); - - // Supports absl::Cord as a sink object for absl::Format(). - friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { - cord->Append(part); - } - - template <typename H> - friend H AbslHashValue(H hash_state, const absl::Cord& c) { - absl::optional<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)); - } - + explicit CharRange(const Cord* cord) : cord_(cord) {} + + CharIterator begin() const; + CharIterator end() const; + + private: + 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. + // + // Example: + // + // void ProcessCord(const Cord& cord) { + // for (char c : cord.Chars()) { ... } + // } + // + // Note that the ordinary caveats of temporary lifetime extension apply: + // + // void Process() { + // for (char c : CordFactory().Chars()) { + // // The temporary Cord returned by CordFactory has been destroyed! + // } + // } + 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, + // 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. + 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. + absl::optional<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. + absl::string_view Flatten(); + + // Supports absl::Cord as a sink object for absl::Format(). + friend void AbslFormatFlush(absl::Cord* cord, absl::string_view part) { + cord->Append(part); + } + + template <typename H> + friend H AbslHashValue(H hash_state, const absl::Cord& c) { + absl::optional<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 @@ -688,7 +688,7 @@ class Cord { template <typename T> explicit constexpr Cord(strings_internal::StringConstant<T>); - private: + private: using CordRep = absl::cord_internal::CordRep; using CordRepFlat = absl::cord_internal::CordRepFlat; using CordzInfo = cord_internal::CordzInfo; @@ -701,56 +701,56 @@ class Cord { // public API call causing the cord to be created. explicit Cord(absl::string_view src, MethodIdentifier method); - friend class CordTestPeer; - friend bool operator==(const Cord& lhs, const Cord& rhs); - friend bool operator==(const Cord& lhs, absl::string_view rhs); - + friend class CordTestPeer; + friend bool operator==(const Cord& lhs, const Cord& rhs); + friend bool operator==(const Cord& lhs, absl::string_view rhs); + friend const CordzInfo* GetCordzInfoForTesting(const Cord& cord); - // Calls the provided function once for each cord chunk, in order. Unlike - // Chunks(), this API will not allocate memory. - void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const; - - // Allocates new contiguous storage for the contents of the cord. This is - // called by Flatten() when the cord was not already flat. - absl::string_view FlattenSlowPath(); - - // Actual cord contents are hidden inside the following simple - // 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. - class InlineRep { - public: - static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; - static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), ""); - - constexpr InlineRep() : data_() {} + // Calls the provided function once for each cord chunk, in order. Unlike + // Chunks(), this API will not allocate memory. + void ForEachChunk(absl::FunctionRef<void(absl::string_view)>) const; + + // Allocates new contiguous storage for the contents of the cord. This is + // called by Flatten() when the cord was not already flat. + absl::string_view FlattenSlowPath(); + + // Actual cord contents are hidden inside the following simple + // 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. + class InlineRep { + public: + static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; + static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), ""); + + 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; - + InlineRep(const InlineRep& src); + InlineRep(InlineRep&& src); + InlineRep& operator=(const InlineRep& src); + InlineRep& operator=(InlineRep&& src) noexcept; + explicit constexpr InlineRep(cord_internal::InlineData data); - void Swap(InlineRep* rhs); - bool empty() const; - size_t size() const; - const char* data() const; // Returns nullptr if holding pointer - void set_data(const char* data, size_t n, - bool nullify_tail); // Discards pointer, if any + void Swap(InlineRep* rhs); + bool empty() const; + size_t size() const; + const char* data() const; // Returns nullptr if holding pointer + void set_data(const char* data, size_t n, + bool nullify_tail); // Discards pointer, if any char* set_data(size_t n); // Write data to the result - // Returns nullptr if holding bytes - absl::cord_internal::CordRep* tree() const; + // Returns nullptr if holding bytes + absl::cord_internal::CordRep* tree() const; absl::cord_internal::CordRep* as_tree() const; - // Returns non-null iff was holding a pointer - absl::cord_internal::CordRep* clear(); - // Converts to pointer if necessary. + // Returns non-null iff was holding a pointer + absl::cord_internal::CordRep* clear(); + // Converts to pointer if necessary. void reduce_size(size_t n); // REQUIRES: holding data - void remove_prefix(size_t n); // REQUIRES: holding data + void remove_prefix(size_t n); // REQUIRES: holding data void AppendArray(absl::string_view src, MethodIdentifier method); - absl::string_view FindFlatStartPiece() const; + absl::string_view FindFlatStartPiece() const; // Creates a CordRepFlat instance from the current inlined data with `extra' // bytes of desired additional capacity. @@ -794,40 +794,40 @@ class Cord { template <bool has_length> void GetAppendRegion(char** region, size_t* size, size_t length); - bool IsSame(const InlineRep& other) const { - 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)); - if (x == 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 absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y) - ? -1 - : 1; - } - void CopyTo(std::string* dst) const { - // memcpy is much faster when operating on a known size. On most supported - // platforms, the small string optimization is large enough that resizing - // to 15 bytes does not cause a memory allocation. - absl::strings_internal::STLStringResizeUninitialized(dst, - sizeof(data_) - 1); - memcpy(&(*dst)[0], &data_, sizeof(data_) - 1); - // erase is faster than resize because the logic for memory allocation is - // not needed. + bool IsSame(const InlineRep& other) const { + 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)); + if (x == 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 absl::big_endian::FromHost64(x) < absl::big_endian::FromHost64(y) + ? -1 + : 1; + } + void CopyTo(std::string* dst) const { + // memcpy is much faster when operating on a known size. On most supported + // platforms, the small string optimization is large enough that resizing + // to 15 bytes does not cause a memory allocation. + absl::strings_internal::STLStringResizeUninitialized(dst, + 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()); - } - - // Copies the inline contents into `dst`. Assumes the cord is not empty. - void CopyToArray(char* dst) const; - + } + + // 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(); } @@ -845,62 +845,62 @@ class Cord { // Resets the current cordz_info to null / empty. void clear_cordz_info() { data_.clear_cordz_info(); } - private: - friend class Cord; - - void AssignSlow(const InlineRep& src); + private: + friend class Cord; + + void AssignSlow(const InlineRep& src); // Unrefs the tree and stops profiling. void UnrefTree(); - - void ResetToEmpty() { 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(). - static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep); - - // Helper for GetFlat() and TryFlat(). - static bool GetFlatAux(absl::cord_internal::CordRep* rep, - absl::string_view* fragment); - - // Helper for ForEachChunk(). - static void ForEachChunkAux( - absl::cord_internal::CordRep* rep, - absl::FunctionRef<void(absl::string_view)> callback); - - // The destructor for non-empty Cords. - void DestroyCordSlow(); - - // Out-of-line implementation of slower parts of logic. - void CopyToArraySlowPath(char* dst) const; - int CompareSlowPath(absl::string_view rhs, size_t compared_size, - size_t size_to_compare) const; - int CompareSlowPath(const Cord& rhs, size_t compared_size, - size_t size_to_compare) const; - bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const; - bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const; - int CompareImpl(const Cord& rhs) const; - - template <typename ResultType, typename RHS> - friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs, - size_t size_to_compare); - static absl::string_view GetFirstChunk(const Cord& c); - static absl::string_view GetFirstChunk(absl::string_view sv); - - // Returns a new reference to contents_.tree(), or steals an existing - // reference if called on an rvalue. - absl::cord_internal::CordRep* TakeRep() const&; - absl::cord_internal::CordRep* TakeRep() &&; - - // Helper for Append(). - template <typename C> - void AppendImpl(C&& src); - + + cord_internal::InlineData data_; + }; + InlineRep contents_; + + // Helper for MemoryUsage(). + static size_t MemoryUsageAux(const absl::cord_internal::CordRep* rep); + + // Helper for GetFlat() and TryFlat(). + static bool GetFlatAux(absl::cord_internal::CordRep* rep, + absl::string_view* fragment); + + // Helper for ForEachChunk(). + static void ForEachChunkAux( + absl::cord_internal::CordRep* rep, + absl::FunctionRef<void(absl::string_view)> callback); + + // The destructor for non-empty Cords. + void DestroyCordSlow(); + + // Out-of-line implementation of slower parts of logic. + void CopyToArraySlowPath(char* dst) const; + int CompareSlowPath(absl::string_view rhs, size_t compared_size, + size_t size_to_compare) const; + int CompareSlowPath(const Cord& rhs, size_t compared_size, + size_t size_to_compare) const; + bool EqualsImpl(absl::string_view rhs, size_t size_to_compare) const; + bool EqualsImpl(const Cord& rhs, size_t size_to_compare) const; + int CompareImpl(const Cord& rhs) const; + + template <typename ResultType, typename RHS> + friend ResultType GenericCompare(const Cord& lhs, const RHS& rhs, + size_t size_to_compare); + static absl::string_view GetFirstChunk(const Cord& c); + static absl::string_view GetFirstChunk(absl::string_view sv); + + // Returns a new reference to contents_.tree(), or steals an existing + // reference if called on an rvalue. + absl::cord_internal::CordRep* TakeRep() const&; + absl::cord_internal::CordRep* TakeRep() &&; + + // 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(absl::string_view src, MethodIdentifier method); @@ -909,116 +909,116 @@ class Cord { // Requires src.length() > kMaxBytesToCopy. Cord& AssignLargeString(std::string&& src); - // Helper for AbslHashValue(). - template <typename H> - H HashFragmented(H hash_state) const { - typename H::AbslInternalPiecewiseCombiner combiner; - ForEachChunk([&combiner, &hash_state](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 -} // namespace absl - -namespace absl { -ABSL_NAMESPACE_BEGIN - -// allow a Cord to be logged -extern std::ostream& operator<<(std::ostream& out, const Cord& cord); - -// ------------------------------------------------------------------ -// Internal details follow. Clients should ignore. - -namespace cord_internal { - -// Fast implementation of memmove for up to 15 bytes. This implementation is -// safe for overlapping regions. If nullify_tail is true, the destination is -// padded with '\0' up to 16 bytes. -inline void SmallMemmove(char* dst, const char* src, size_t n, - bool nullify_tail = false) { - if (n >= 8) { - assert(n <= 16); - uint64_t buf1; - uint64_t buf2; - memcpy(&buf1, src, 8); - memcpy(&buf2, src + n - 8, 8); - if (nullify_tail) { - memset(dst + 8, 0, 8); - } - memcpy(dst, &buf1, 8); - memcpy(dst + n - 8, &buf2, 8); - } else if (n >= 4) { - uint32_t buf1; - uint32_t buf2; - memcpy(&buf1, src, 4); - memcpy(&buf2, src + n - 4, 4); - if (nullify_tail) { - memset(dst + 4, 0, 4); - memset(dst + 8, 0, 8); - } - memcpy(dst, &buf1, 4); - memcpy(dst + n - 4, &buf2, 4); - } else { - if (n != 0) { - dst[0] = src[0]; - dst[n / 2] = src[n / 2]; - dst[n - 1] = src[n - 1]; - } - if (nullify_tail) { - memset(dst + 8, 0, 8); - memset(dst + n, 0, 8); - } - } -} - -// Does non-template-specific `CordRepExternal` initialization. -// Expects `data` to be non-empty. -void InitializeCordRepExternal(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. -template <typename Releaser> -// NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { - using ReleaserType = absl::decay_t<Releaser>; - if (data.empty()) { - // Never create empty external nodes. - 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; -} - -// Overload for function reference types that dispatches using a function -// pointer because there are no `alignof()` or `sizeof()` a function reference. -// NOLINTNEXTLINE - suppress clang-tidy raw pointer return. -inline CordRep* NewExternalRep(absl::string_view data, - void (&releaser)(absl::string_view)) { - return NewExternalRep(data, &releaser); -} - -} // namespace cord_internal - -template <typename Releaser> -Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { - Cord cord; + // Helper for AbslHashValue(). + template <typename H> + H HashFragmented(H hash_state) const { + typename H::AbslInternalPiecewiseCombiner combiner; + ForEachChunk([&combiner, &hash_state](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 +} // namespace absl + +namespace absl { +ABSL_NAMESPACE_BEGIN + +// allow a Cord to be logged +extern std::ostream& operator<<(std::ostream& out, const Cord& cord); + +// ------------------------------------------------------------------ +// Internal details follow. Clients should ignore. + +namespace cord_internal { + +// Fast implementation of memmove for up to 15 bytes. This implementation is +// safe for overlapping regions. If nullify_tail is true, the destination is +// padded with '\0' up to 16 bytes. +inline void SmallMemmove(char* dst, const char* src, size_t n, + bool nullify_tail = false) { + if (n >= 8) { + assert(n <= 16); + uint64_t buf1; + uint64_t buf2; + memcpy(&buf1, src, 8); + memcpy(&buf2, src + n - 8, 8); + if (nullify_tail) { + memset(dst + 8, 0, 8); + } + memcpy(dst, &buf1, 8); + memcpy(dst + n - 8, &buf2, 8); + } else if (n >= 4) { + uint32_t buf1; + uint32_t buf2; + memcpy(&buf1, src, 4); + memcpy(&buf2, src + n - 4, 4); + if (nullify_tail) { + memset(dst + 4, 0, 4); + memset(dst + 8, 0, 8); + } + memcpy(dst, &buf1, 4); + memcpy(dst + n - 4, &buf2, 4); + } else { + if (n != 0) { + dst[0] = src[0]; + dst[n / 2] = src[n / 2]; + dst[n - 1] = src[n - 1]; + } + if (nullify_tail) { + memset(dst + 8, 0, 8); + memset(dst + n, 0, 8); + } + } +} + +// Does non-template-specific `CordRepExternal` initialization. +// Expects `data` to be non-empty. +void InitializeCordRepExternal(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. +template <typename Releaser> +// NOLINTNEXTLINE - suppress clang-tidy raw pointer return. +CordRep* NewExternalRep(absl::string_view data, Releaser&& releaser) { + using ReleaserType = absl::decay_t<Releaser>; + if (data.empty()) { + // Never create empty external nodes. + 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; +} + +// Overload for function reference types that dispatches using a function +// pointer because there are no `alignof()` or `sizeof()` a function reference. +// NOLINTNEXTLINE - suppress clang-tidy raw pointer return. +inline CordRep* NewExternalRep(absl::string_view data, + void (&releaser)(absl::string_view)) { + return NewExternalRep(data, &releaser); +} + +} // namespace cord_internal + +template <typename Releaser> +Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) { + Cord cord; if (auto* rep = ::absl::cord_internal::NewExternalRep( data, std::forward<Releaser>(releaser))) { cord.contents_.EmplaceTree(rep, Cord::MethodIdentifier::kMakeCordFromExternal); } - return cord; -} - + return cord; +} + constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data) : data_(data) {} @@ -1030,64 +1030,64 @@ inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) } else { data_ = src.data_; } -} - +} + inline Cord::InlineRep::InlineRep(Cord::InlineRep&& src) : data_(src.data_) { - src.ResetToEmpty(); -} - -inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { - if (this == &src) { - return *this; - } - if (!is_tree() && !src.is_tree()) { - data_ = src.data_; - return *this; - } - AssignSlow(src); - return *this; -} - -inline Cord::InlineRep& Cord::InlineRep::operator=( - Cord::InlineRep&& src) noexcept { - if (is_tree()) { + src.ResetToEmpty(); +} + +inline Cord::InlineRep& Cord::InlineRep::operator=(const Cord::InlineRep& src) { + if (this == &src) { + return *this; + } + if (!is_tree() && !src.is_tree()) { + data_ = src.data_; + return *this; + } + AssignSlow(src); + return *this; +} + +inline Cord::InlineRep& Cord::InlineRep::operator=( + Cord::InlineRep&& src) noexcept { + if (is_tree()) { UnrefTree(); - } - data_ = src.data_; - src.ResetToEmpty(); - return *this; -} - -inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { - if (rhs == this) { - return; - } - std::swap(data_, rhs->data_); -} - -inline const char* Cord::InlineRep::data() const { + } + data_ = src.data_; + src.ResetToEmpty(); + return *this; +} + +inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { + if (rhs == this) { + return; + } + std::swap(data_, rhs->data_); +} + +inline const char* Cord::InlineRep::data() const { return is_tree() ? nullptr : data_.as_chars(); -} - +} + inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const { assert(data_.is_tree()); return data_.as_tree(); } -inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { - if (is_tree()) { +inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { + if (is_tree()) { return as_tree(); - } else { - return nullptr; - } -} - + } else { + return nullptr; + } +} + inline bool Cord::InlineRep::empty() const { return data_.is_empty(); } - -inline size_t Cord::InlineRep::size() const { + +inline size_t Cord::InlineRep::size() const { return is_tree() ? as_tree()->length : inline_size(); -} - +} + inline cord_internal::CordRepFlat* Cord::InlineRep::MakeFlatWithExtraCapacity( size_t extra) { static_assert(cord_internal::kMinFlatLength >= sizeof(data_), ""); @@ -1124,12 +1124,12 @@ inline void Cord::InlineRep::SetTreeOrEmpty(CordRep* rep, assert(data_.is_tree()); if (rep) { data_.set_tree(rep); - } else { + } else { data_ = {}; - } + } scope.SetCordRep(rep); -} - +} + inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, const CordzUpdateScope& scope, MethodIdentifier method) { @@ -1137,27 +1137,27 @@ inline void Cord::InlineRep::CommitTree(const CordRep* old_rep, CordRep* rep, SetTree(rep, scope); } else { EmplaceTree(rep, method); - } -} - -inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { + } +} + +inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { if (is_tree()) { CordzInfo::MaybeUntrackCord(cordz_info()); } - absl::cord_internal::CordRep* result = tree(); - ResetToEmpty(); - return result; -} - -inline void Cord::InlineRep::CopyToArray(char* dst) const { - assert(!is_tree()); + 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(); - assert(n != 0); + assert(n != 0); cord_internal::SmallMemmove(dst, data_.as_chars(), n); -} - -constexpr inline Cord::Cord() noexcept {} - +} + +constexpr inline Cord::Cord() noexcept {} + inline Cord::Cord(absl::string_view src) : Cord(src, CordzUpdateTracker::kConstructorString) {} @@ -1171,11 +1171,11 @@ constexpr Cord::Cord(strings_internal::StringConstant<T>) &cord_internal::ConstInitExternalStorage< strings_internal::StringConstant<T>>::value)) {} -inline Cord& Cord::operator=(const Cord& x) { - contents_ = x.contents_; - return *this; -} - +inline Cord& Cord::operator=(const Cord& x) { + contents_ = x.contents_; + return *this; +} + template <typename T, Cord::EnableIfString<T>> Cord& Cord::operator=(T&& src) { if (src.size() <= cord_internal::kMaxBytesToCopy) { @@ -1187,92 +1187,92 @@ Cord& Cord::operator=(T&& src) { 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 Cord& Cord::operator=(Cord&& x) noexcept { - contents_ = std::move(x.contents_); - return *this; -} - -extern template Cord::Cord(std::string&& src); - -inline size_t Cord::size() const { - // Length is 1st field in str.rep_ - return contents_.size(); -} - -inline bool Cord::empty() const { return contents_.empty(); } - -inline size_t Cord::EstimatedMemoryUsage() const { - size_t result = sizeof(Cord); - if (const absl::cord_internal::CordRep* rep = contents_.tree()) { - result += MemoryUsageAux(rep); - } - return result; -} - -inline absl::optional<absl::string_view> Cord::TryFlat() const { - absl::cord_internal::CordRep* rep = contents_.tree(); - if (rep == nullptr) { - return absl::string_view(contents_.data(), contents_.size()); - } - absl::string_view fragment; - if (GetFlatAux(rep, &fragment)) { - return fragment; - } - return absl::nullopt; -} - -inline absl::string_view Cord::Flatten() { - absl::cord_internal::CordRep* rep = contents_.tree(); - if (rep == nullptr) { - return absl::string_view(contents_.data(), contents_.size()); - } else { - absl::string_view already_flat_contents; - if (GetFlatAux(rep, &already_flat_contents)) { - return already_flat_contents; - } - } - return FlattenSlowPath(); -} - -inline void Cord::Append(absl::string_view src) { +inline Cord::Cord(Cord&& src) noexcept : contents_(std::move(src.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(std::string&& src); + +inline size_t Cord::size() const { + // Length is 1st field in str.rep_ + return contents_.size(); +} + +inline bool Cord::empty() const { return contents_.empty(); } + +inline size_t Cord::EstimatedMemoryUsage() const { + size_t result = sizeof(Cord); + if (const absl::cord_internal::CordRep* rep = contents_.tree()) { + result += MemoryUsageAux(rep); + } + return result; +} + +inline absl::optional<absl::string_view> Cord::TryFlat() const { + absl::cord_internal::CordRep* rep = contents_.tree(); + if (rep == nullptr) { + return absl::string_view(contents_.data(), contents_.size()); + } + absl::string_view fragment; + if (GetFlatAux(rep, &fragment)) { + return fragment; + } + return absl::nullopt; +} + +inline absl::string_view Cord::Flatten() { + absl::cord_internal::CordRep* rep = contents_.tree(); + if (rep == nullptr) { + return absl::string_view(contents_.data(), contents_.size()); + } else { + absl::string_view already_flat_contents; + if (GetFlatAux(rep, &already_flat_contents)) { + return already_flat_contents; + } + } + return FlattenSlowPath(); +} + +inline void Cord::Append(absl::string_view src) { contents_.AppendArray(src, CordzUpdateTracker::kAppendString); -} - +} + inline void Cord::Prepend(absl::string_view src) { PrependArray(src, CordzUpdateTracker::kPrependString); } -extern template void Cord::Append(std::string&& src); -extern template void Cord::Prepend(std::string&& src); - -inline int Cord::Compare(const Cord& rhs) const { - if (!contents_.is_tree() && !rhs.contents_.is_tree()) { - return contents_.BitwiseCompare(rhs.contents_); - } - - return CompareImpl(rhs); -} - -// Does 'this' cord start/end with rhs -inline bool Cord::StartsWith(const Cord& rhs) const { - if (contents_.IsSame(rhs.contents_)) return true; - size_t rhs_size = rhs.size(); - if (size() < rhs_size) return false; - return EqualsImpl(rhs, rhs_size); -} - -inline bool Cord::StartsWith(absl::string_view rhs) const { - size_t rhs_size = rhs.size(); - if (size() < rhs_size) return false; - return EqualsImpl(rhs, rhs_size); -} - +extern template void Cord::Append(std::string&& src); +extern template void Cord::Prepend(std::string&& src); + +inline int Cord::Compare(const Cord& rhs) const { + if (!contents_.is_tree() && !rhs.contents_.is_tree()) { + return contents_.BitwiseCompare(rhs.contents_); + } + + return CompareImpl(rhs); +} + +// Does 'this' cord start/end with rhs +inline bool Cord::StartsWith(const Cord& rhs) const { + if (contents_.IsSame(rhs.contents_)) return true; + size_t rhs_size = rhs.size(); + if (size() < rhs_size) return false; + return EqualsImpl(rhs, rhs_size); +} + +inline bool Cord::StartsWith(absl::string_view rhs) const { + size_t rhs_size = rhs.size(); + if (size() < rhs_size) return false; + return EqualsImpl(rhs, rhs_size); +} + inline void Cord::ChunkIterator::InitTree(cord_internal::CordRep* tree) { if (tree->tag == cord_internal::BTREE) { current_chunk_ = btree_reader_.Init(tree->btree()); @@ -1288,16 +1288,16 @@ inline Cord::ChunkIterator::ChunkIterator(cord_internal::CordRep* tree) InitTree(tree); } -inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) - : bytes_remaining_(cord->size()) { - if (cord->contents_.is_tree()) { +inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) + : bytes_remaining_(cord->size()) { + if (cord->contents_.is_tree()) { InitTree(cord->contents_.as_tree()); - } else { + } else { current_chunk_ = absl::string_view(cord->contents_.data(), bytes_remaining_); - } -} - + } +} + inline Cord::ChunkIterator& Cord::ChunkIterator::AdvanceBtree() { current_chunk_ = btree_reader_.Next(); return *this; @@ -1331,191 +1331,191 @@ inline Cord::ChunkIterator& Cord::ChunkIterator::operator++() { return *this; } -inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) { - ChunkIterator tmp(*this); - operator++(); - return tmp; -} - -inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const { - return bytes_remaining_ == other.bytes_remaining_; -} - -inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const { - return !(*this == other); -} - -inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const { - ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); - return current_chunk_; -} - -inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const { - ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); - return ¤t_chunk_; -} - -inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) { - assert(n < current_chunk_.size()); - current_chunk_.remove_prefix(n); - bytes_remaining_ -= n; -} - -inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { +inline Cord::ChunkIterator Cord::ChunkIterator::operator++(int) { + ChunkIterator tmp(*this); + operator++(); + return tmp; +} + +inline bool Cord::ChunkIterator::operator==(const ChunkIterator& other) const { + return bytes_remaining_ == other.bytes_remaining_; +} + +inline bool Cord::ChunkIterator::operator!=(const ChunkIterator& other) const { + return !(*this == other); +} + +inline Cord::ChunkIterator::reference Cord::ChunkIterator::operator*() const { + ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); + return current_chunk_; +} + +inline Cord::ChunkIterator::pointer Cord::ChunkIterator::operator->() const { + ABSL_HARDENING_ASSERT(bytes_remaining_ != 0); + return ¤t_chunk_; +} + +inline void Cord::ChunkIterator::RemoveChunkPrefix(size_t n) { + assert(n < current_chunk_.size()); + current_chunk_.remove_prefix(n); + bytes_remaining_ -= n; +} + +inline void Cord::ChunkIterator::AdvanceBytes(size_t n) { assert(bytes_remaining_ >= n); - if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { - RemoveChunkPrefix(n); - } else if (n != 0) { + if (ABSL_PREDICT_TRUE(n < current_chunk_.size())) { + RemoveChunkPrefix(n); + } else if (n != 0) { btree_reader_ ? AdvanceBytesBtree(n) : AdvanceBytesSlowPath(n); - } -} - -inline Cord::ChunkIterator Cord::chunk_begin() const { - return ChunkIterator(this); -} - -inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); } - -inline Cord::ChunkIterator Cord::ChunkRange::begin() const { - return cord_->chunk_begin(); -} - -inline Cord::ChunkIterator Cord::ChunkRange::end() const { - return cord_->chunk_end(); -} - -inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); } - -inline Cord::CharIterator& Cord::CharIterator::operator++() { - if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) { - chunk_iterator_.RemoveChunkPrefix(1); - } else { - ++chunk_iterator_; - } - return *this; -} - -inline Cord::CharIterator Cord::CharIterator::operator++(int) { - CharIterator tmp(*this); - operator++(); - return tmp; -} - -inline bool Cord::CharIterator::operator==(const CharIterator& other) const { - return chunk_iterator_ == other.chunk_iterator_; -} - -inline bool Cord::CharIterator::operator!=(const CharIterator& other) const { - return !(*this == other); -} - -inline Cord::CharIterator::reference Cord::CharIterator::operator*() const { - return *chunk_iterator_->data(); -} - -inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const { - return chunk_iterator_->data(); -} - -inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) { - assert(it != nullptr); - return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); -} - -inline void Cord::Advance(CharIterator* it, size_t n_bytes) { - assert(it != nullptr); - it->chunk_iterator_.AdvanceBytes(n_bytes); -} - -inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) { - return *it.chunk_iterator_; -} - -inline Cord::CharIterator Cord::char_begin() const { - return CharIterator(this); -} - -inline Cord::CharIterator Cord::char_end() const { return CharIterator(); } - -inline Cord::CharIterator Cord::CharRange::begin() const { - return cord_->char_begin(); -} - -inline Cord::CharIterator Cord::CharRange::end() const { - return cord_->char_end(); -} - -inline Cord::CharRange Cord::Chars() const { return CharRange(this); } - -inline void Cord::ForEachChunk( - absl::FunctionRef<void(absl::string_view)> callback) const { - absl::cord_internal::CordRep* rep = contents_.tree(); - if (rep == nullptr) { - callback(absl::string_view(contents_.data(), contents_.size())); - } else { - return ForEachChunkAux(rep, callback); - } -} - -// Nonmember Cord-to-Cord relational operarators. -inline bool operator==(const Cord& lhs, const Cord& rhs) { - if (lhs.contents_.IsSame(rhs.contents_)) return true; - size_t rhs_size = rhs.size(); - if (lhs.size() != rhs_size) return false; - return lhs.EqualsImpl(rhs, rhs_size); -} - -inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); } + } +} + +inline Cord::ChunkIterator Cord::chunk_begin() const { + return ChunkIterator(this); +} + +inline Cord::ChunkIterator Cord::chunk_end() const { return ChunkIterator(); } + +inline Cord::ChunkIterator Cord::ChunkRange::begin() const { + return cord_->chunk_begin(); +} + +inline Cord::ChunkIterator Cord::ChunkRange::end() const { + return cord_->chunk_end(); +} + +inline Cord::ChunkRange Cord::Chunks() const { return ChunkRange(this); } + +inline Cord::CharIterator& Cord::CharIterator::operator++() { + if (ABSL_PREDICT_TRUE(chunk_iterator_->size() > 1)) { + chunk_iterator_.RemoveChunkPrefix(1); + } else { + ++chunk_iterator_; + } + return *this; +} + +inline Cord::CharIterator Cord::CharIterator::operator++(int) { + CharIterator tmp(*this); + operator++(); + return tmp; +} + +inline bool Cord::CharIterator::operator==(const CharIterator& other) const { + return chunk_iterator_ == other.chunk_iterator_; +} + +inline bool Cord::CharIterator::operator!=(const CharIterator& other) const { + return !(*this == other); +} + +inline Cord::CharIterator::reference Cord::CharIterator::operator*() const { + return *chunk_iterator_->data(); +} + +inline Cord::CharIterator::pointer Cord::CharIterator::operator->() const { + return chunk_iterator_->data(); +} + +inline Cord Cord::AdvanceAndRead(CharIterator* it, size_t n_bytes) { + assert(it != nullptr); + return it->chunk_iterator_.AdvanceAndReadBytes(n_bytes); +} + +inline void Cord::Advance(CharIterator* it, size_t n_bytes) { + assert(it != nullptr); + it->chunk_iterator_.AdvanceBytes(n_bytes); +} + +inline absl::string_view Cord::ChunkRemaining(const CharIterator& it) { + return *it.chunk_iterator_; +} + +inline Cord::CharIterator Cord::char_begin() const { + return CharIterator(this); +} + +inline Cord::CharIterator Cord::char_end() const { return CharIterator(); } + +inline Cord::CharIterator Cord::CharRange::begin() const { + return cord_->char_begin(); +} + +inline Cord::CharIterator Cord::CharRange::end() const { + return cord_->char_end(); +} + +inline Cord::CharRange Cord::Chars() const { return CharRange(this); } + +inline void Cord::ForEachChunk( + absl::FunctionRef<void(absl::string_view)> callback) const { + absl::cord_internal::CordRep* rep = contents_.tree(); + if (rep == nullptr) { + callback(absl::string_view(contents_.data(), contents_.size())); + } else { + return ForEachChunkAux(rep, callback); + } +} + +// Nonmember Cord-to-Cord relational operarators. +inline bool operator==(const Cord& lhs, const Cord& rhs) { + if (lhs.contents_.IsSame(rhs.contents_)) return true; + size_t rhs_size = rhs.size(); + if (lhs.size() != rhs_size) return false; + return lhs.EqualsImpl(rhs, rhs_size); +} + +inline bool operator!=(const Cord& x, const Cord& y) { return !(x == y); } inline bool operator<(const Cord& x, const Cord& y) { return x.Compare(y) < 0; } inline bool operator>(const Cord& x, const Cord& y) { return x.Compare(y) > 0; } -inline bool operator<=(const Cord& x, const Cord& y) { - return x.Compare(y) <= 0; -} -inline bool operator>=(const Cord& x, const Cord& y) { - return x.Compare(y) >= 0; -} - -// Nonmember Cord-to-absl::string_view relational operators. -// -// Due to implicit conversions, these also enable comparisons of Cord with -// with std::string, ::string, and const char*. -inline bool operator==(const Cord& lhs, absl::string_view rhs) { - size_t lhs_size = lhs.size(); - size_t rhs_size = rhs.size(); - if (lhs_size != rhs_size) return false; - return lhs.EqualsImpl(rhs, rhs_size); -} - -inline bool operator==(absl::string_view x, const Cord& y) { return y == x; } -inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); } -inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); } -inline bool operator<(const Cord& x, absl::string_view y) { - return x.Compare(y) < 0; -} -inline bool operator<(absl::string_view x, const Cord& y) { - return y.Compare(x) > 0; -} -inline bool operator>(const Cord& x, absl::string_view y) { return y < x; } -inline bool operator>(absl::string_view x, const Cord& y) { return y < x; } -inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); } -inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); } -inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); } -inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); } - -// Some internals exposed to test code. -namespace strings_internal { -class CordTestAccess { - public: - static size_t FlatOverhead(); - static size_t MaxFlatLength(); - static size_t SizeofCordRepConcat(); - static size_t SizeofCordRepExternal(); - static size_t SizeofCordRepSubstring(); - static size_t FlatTagToLength(uint8_t tag); - static uint8_t LengthToTag(size_t s); -}; -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STRINGS_CORD_H_ +inline bool operator<=(const Cord& x, const Cord& y) { + return x.Compare(y) <= 0; +} +inline bool operator>=(const Cord& x, const Cord& y) { + return x.Compare(y) >= 0; +} + +// Nonmember Cord-to-absl::string_view relational operators. +// +// Due to implicit conversions, these also enable comparisons of Cord with +// with std::string, ::string, and const char*. +inline bool operator==(const Cord& lhs, absl::string_view rhs) { + size_t lhs_size = lhs.size(); + size_t rhs_size = rhs.size(); + if (lhs_size != rhs_size) return false; + return lhs.EqualsImpl(rhs, rhs_size); +} + +inline bool operator==(absl::string_view x, const Cord& y) { return y == x; } +inline bool operator!=(const Cord& x, absl::string_view y) { return !(x == y); } +inline bool operator!=(absl::string_view x, const Cord& y) { return !(x == y); } +inline bool operator<(const Cord& x, absl::string_view y) { + return x.Compare(y) < 0; +} +inline bool operator<(absl::string_view x, const Cord& y) { + return y.Compare(x) > 0; +} +inline bool operator>(const Cord& x, absl::string_view y) { return y < x; } +inline bool operator>(absl::string_view x, const Cord& y) { return y < x; } +inline bool operator<=(const Cord& x, absl::string_view y) { return !(y < x); } +inline bool operator<=(absl::string_view x, const Cord& y) { return !(y < x); } +inline bool operator>=(const Cord& x, absl::string_view y) { return !(x < y); } +inline bool operator>=(absl::string_view x, const Cord& y) { return !(x < y); } + +// Some internals exposed to test code. +namespace strings_internal { +class CordTestAccess { + public: + static size_t FlatOverhead(); + static size_t MaxFlatLength(); + static size_t SizeofCordRepConcat(); + static size_t SizeofCordRepExternal(); + static size_t SizeofCordRepSubstring(); + static size_t FlatTagToLength(uint8_t tag); + static uint8_t LengthToTag(size_t s); +}; +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_CORD_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/cord_test_helpers.h b/contrib/restricted/abseil-cpp/absl/strings/cord_test_helpers.h index 31a1dc8980..e8832f72c1 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/cord_test_helpers.h +++ b/contrib/restricted/abseil-cpp/absl/strings/cord_test_helpers.h @@ -1,34 +1,34 @@ -// -// Copyright 2018 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_CORD_TEST_HELPERS_H_ -#define ABSL_STRINGS_CORD_TEST_HELPERS_H_ - +// +// Copyright 2018 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_CORD_TEST_HELPERS_H_ +#define ABSL_STRINGS_CORD_TEST_HELPERS_H_ + #include <cstdint> #include <iostream> #include <string> #include "absl/base/config.h" -#include "absl/strings/cord.h" +#include "absl/strings/cord.h" #include "absl/strings/internal/cord_internal.h" #include "absl/strings/string_view.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN - + +namespace absl { +ABSL_NAMESPACE_BEGIN + // Cord sizes relevant for testing enum class TestCordSize { // An empty value @@ -84,39 +84,39 @@ inline std::ostream& operator<<(std::ostream& stream, TestCordSize size) { return stream << ToString(size); } -// Creates a multi-segment Cord from an iterable container of strings. The -// resulting Cord is guaranteed to have one segment for every string in the -// container. This allows code to be unit tested with multi-segment Cord -// inputs. -// -// Example: -// -// absl::Cord c = absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"}); -// EXPECT_FALSE(c.GetFlat(&unused)); -// -// The mechanism by which this Cord is created is an implementation detail. Any -// implementation that produces a multi-segment Cord may produce a flat Cord in -// the future as new optimizations are added to the Cord class. -// MakeFragmentedCord will, however, always be updated to return a multi-segment -// Cord. -template <typename Container> -Cord MakeFragmentedCord(const Container& c) { - Cord result; - for (const auto& s : c) { - auto* external = new std::string(s); - Cord tmp = absl::MakeCordFromExternal( - *external, [external](absl::string_view) { delete external; }); - tmp.Prepend(result); - result = tmp; - } - return result; -} - -inline Cord MakeFragmentedCord(std::initializer_list<absl::string_view> list) { - return MakeFragmentedCord<std::initializer_list<absl::string_view>>(list); -} - -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STRINGS_CORD_TEST_HELPERS_H_ +// Creates a multi-segment Cord from an iterable container of strings. The +// resulting Cord is guaranteed to have one segment for every string in the +// container. This allows code to be unit tested with multi-segment Cord +// inputs. +// +// Example: +// +// absl::Cord c = absl::MakeFragmentedCord({"A ", "fragmented ", "Cord"}); +// EXPECT_FALSE(c.GetFlat(&unused)); +// +// The mechanism by which this Cord is created is an implementation detail. Any +// implementation that produces a multi-segment Cord may produce a flat Cord in +// the future as new optimizations are added to the Cord class. +// MakeFragmentedCord will, however, always be updated to return a multi-segment +// Cord. +template <typename Container> +Cord MakeFragmentedCord(const Container& c) { + Cord result; + for (const auto& s : c) { + auto* external = new std::string(s); + Cord tmp = absl::MakeCordFromExternal( + *external, [external](absl::string_view) { delete external; }); + tmp.Prepend(result); + result = tmp; + } + return result; +} + +inline Cord MakeFragmentedCord(std::initializer_list<absl::string_view> list) { + return MakeFragmentedCord<std::initializer_list<absl::string_view>>(list); +} + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_CORD_TEST_HELPERS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/escaping.cc b/contrib/restricted/abseil-cpp/absl/strings/escaping.cc index 18b20b83fd..0c4a52f877 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/escaping.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/escaping.cc @@ -26,7 +26,7 @@ #include "absl/base/internal/raw_logging.h" #include "absl/base/internal/unaligned_access.h" #include "absl/strings/internal/char_map.h" -#include "absl/strings/internal/escaping.h" +#include "absl/strings/internal/escaping.h" #include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/utf8.h" #include "absl/strings/str_cat.h" @@ -34,7 +34,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace { // These are used for the leave_nulls_escaped argument to CUnescapeInternal(). @@ -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); @@ -796,7 +796,7 @@ bool Base64UnescapeInternal(const char* src, size_t slen, String* dest, } /* clang-format off */ -constexpr char kHexValueLenient[256] = { +constexpr char kHexValueLenient[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -812,9 +812,9 @@ constexpr char kHexValueLenient[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; - + /* clang-format on */ // This is a templated function so that T can be either a char* @@ -823,8 +823,8 @@ constexpr char kHexValueLenient[256] = { template <typename T> void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) { for (int i = 0; i < num; i++) { - to[i] = (kHexValueLenient[from[i * 2] & 0xFF] << 4) + - (kHexValueLenient[from[i * 2 + 1] & 0xFF]); + to[i] = (kHexValueLenient[from[i * 2] & 0xFF] << 4) + + (kHexValueLenient[from[i * 2 + 1] & 0xFF]); } } @@ -902,30 +902,30 @@ bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) { } void Base64Escape(absl::string_view src, std::string* dest) { - strings_internal::Base64EscapeInternal( - reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, - true, strings_internal::kBase64Chars); + strings_internal::Base64EscapeInternal( + reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, + true, strings_internal::kBase64Chars); } void WebSafeBase64Escape(absl::string_view src, std::string* dest) { - strings_internal::Base64EscapeInternal( - reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, - false, kWebSafeBase64Chars); + strings_internal::Base64EscapeInternal( + reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest, + false, kWebSafeBase64Chars); } std::string Base64Escape(absl::string_view src) { std::string dest; - strings_internal::Base64EscapeInternal( - reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, - true, strings_internal::kBase64Chars); + strings_internal::Base64EscapeInternal( + reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, + true, strings_internal::kBase64Chars); return dest; } std::string WebSafeBase64Escape(absl::string_view src) { std::string dest; - strings_internal::Base64EscapeInternal( - reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, - false, kWebSafeBase64Chars); + strings_internal::Base64EscapeInternal( + reinterpret_cast<const unsigned char*>(src.data()), src.size(), &dest, + false, kWebSafeBase64Chars); return dest; } @@ -945,5 +945,5 @@ std::string BytesToHexString(absl::string_view from) { return result; } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/escaping.h b/contrib/restricted/abseil-cpp/absl/strings/escaping.h index f5ca26c5da..e2a6b106ae 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/escaping.h +++ b/contrib/restricted/abseil-cpp/absl/strings/escaping.h @@ -33,7 +33,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // CUnescape() // @@ -158,7 +158,7 @@ std::string HexStringToBytes(absl::string_view from); // `2*from.size()`. std::string BytesToHexString(absl::string_view from); -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_ESCAPING_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal/ya.make b/contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal/ya.make index 2c62f6421a..38fe96f8ef 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal/ya.make +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal/ya.make @@ -8,13 +8,13 @@ OWNER(g:cpp-contrib) LICENSE(Apache-2.0) -PEERDIR( +PEERDIR( contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait - contrib/restricted/abseil-cpp/absl/base/log_severity -) - + contrib/restricted/abseil-cpp/absl/base/log_severity +) + ADDINCL( GLOBAL contrib/restricted/abseil-cpp ) @@ -23,14 +23,14 @@ NO_COMPILER_WARNINGS() NO_UTIL() -CFLAGS( - -DNOMINMAX -) - +CFLAGS( + -DNOMINMAX +) + SRCDIR(contrib/restricted/abseil-cpp/absl/strings/internal) SRCS( - escaping.cc + escaping.cc ostringstream.cc utf8.cc ) diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/char_map.h b/contrib/restricted/abseil-cpp/absl/strings/internal/char_map.h index 61484de0b7..9fb6fca1ad 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/char_map.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/char_map.h @@ -28,7 +28,7 @@ #include "absl/base/port.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { class Charmap { @@ -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) { @@ -150,7 +150,7 @@ constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.cc index ebf8c0791a..ab4de5da19 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.cc @@ -19,7 +19,7 @@ #include <string> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { namespace { @@ -158,12 +158,12 @@ const uint32_t* LargePowerOfFiveData(int i) { int LargePowerOfFiveSize(int i) { return 2 * i; } } // namespace -ABSL_DLL const uint32_t kFiveToNth[14] = { +ABSL_DLL const uint32_t kFiveToNth[14] = { 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, }; -ABSL_DLL const uint32_t kTenToNth[10] = { +ABSL_DLL const uint32_t kTenToNth[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, }; @@ -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; @@ -355,5 +355,5 @@ template class BigUnsigned<4>; template class BigUnsigned<84>; } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.h b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.h index 8f702976a8..bb5350f4c8 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_bigint.h @@ -20,13 +20,13 @@ #include <iostream> #include <string> -#include "absl/base/config.h" +#include "absl/base/config.h" #include "absl/strings/ascii.h" #include "absl/strings/internal/charconv_parse.h" #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // The largest power that 5 that can be raised to, and still fit in a uint32_t. @@ -34,9 +34,9 @@ constexpr int kMaxSmallPowerOfFive = 13; // The largest power that 10 that can be raised to, and still fit in a uint32_t. constexpr int kMaxSmallPowerOfTen = 9; -ABSL_DLL extern const uint32_t - kFiveToNth[kMaxSmallPowerOfFive + 1]; -ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; +ABSL_DLL extern const uint32_t + kFiveToNth[kMaxSmallPowerOfFive + 1]; +ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; // Large, fixed-width unsigned integer. // @@ -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(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. std::string ToString() const; @@ -417,7 +417,7 @@ extern template class BigUnsigned<4>; extern template class BigUnsigned<84>; } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.cc index d29acaf462..31df50d2a5 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.cc @@ -22,7 +22,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace { // ParseFloat<10> will read the first 19 significant digits of the mantissa. @@ -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 == '(') { @@ -500,5 +500,5 @@ template ParsedFloat ParseFloat<16>(const char* begin, const char* end, chars_format format_flags); } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.h b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.h index 505998b539..12d828f4c8 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/charconv_parse.h @@ -17,11 +17,11 @@ #include <cstdint> -#include "absl/base/config.h" +#include "absl/base/config.h" #include "absl/strings/charconv.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // Enum indicating whether a parsed float is a number or special value. @@ -94,6 +94,6 @@ extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end, absl::chars_format format_flags); } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/cord_internal.h b/contrib/restricted/abseil-cpp/absl/strings/internal/cord_internal.h index bfe5564e46..1656482024 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/cord_internal.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/cord_internal.h @@ -1,38 +1,38 @@ // 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_INTERNAL_H_ -#define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ - -#include <atomic> -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <type_traits> - +// +// 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_INTERNAL_H_ +#define ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ + +#include <atomic> +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <type_traits> + #include "absl/base/config.h" #include "absl/base/internal/endian.h" -#include "absl/base/internal/invoke.h" +#include "absl/base/internal/invoke.h" #include "absl/base/optimization.h" -#include "absl/container/internal/compressed_tuple.h" -#include "absl/meta/type_traits.h" -#include "absl/strings/string_view.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace cord_internal { - +#include "absl/container/internal/compressed_tuple.h" +#include "absl/meta/type_traits.h" +#include "absl/strings/string_view.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace cord_internal { + class CordzInfo; // Default feature enable states for cord ring buffers @@ -83,48 +83,48 @@ enum Constants { // 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: + public: constexpr RefcountAndFlags() : count_{kRefIncrement} {} 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); } - - // Asserts that the current refcount is greater than 0. If the refcount is + + // Asserts that the current refcount is greater than 0. If the refcount is // 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 - // false will be visible to a thread that just observed this method returning + // + // Returns false if there are no references outstanding; true otherwise. + // Inserts barriers to ensure that state written before this method returns + // false will be visible to a thread that just observed this method returning // false. Always returns false when the immortal bit is set. - inline bool Decrement() { + inline bool Decrement() { int32_t refcount = count_.load(std::memory_order_acquire) & kRefcountMask; assert(refcount > 0 || refcount & kImmortalFlag); 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() { + } + + // Same as Decrement but expect that refcount is greater than 1. + inline bool DecrementExpectHighRefcount() { int32_t refcount = count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) & kRefcountMask; assert(refcount > 0 || refcount & kImmortalFlag); return refcount != kRefIncrement; - } - - // Returns the current reference count using acquire semantics. + } + + // Returns the current reference count using acquire semantics. 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 { return (count_.load(std::memory_order_relaxed) & kCrcFlag) != 0; @@ -155,12 +155,12 @@ class RefcountAndFlags { return (count_.load(std::memory_order_acquire) & kRefcountMask) == kRefIncrement; } - + bool IsImmortal() const { return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0; } - private: + 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 @@ -180,30 +180,30 @@ class RefcountAndFlags { kRefcountMask = ~kCrcFlag, }; - std::atomic<int32_t> count_; -}; - -// The overhead of a vtable is too much for Cord, so we roll our own subclasses -// using only a single byte to differentiate classes from each other - the "tag" -// byte. Define the subclasses first so we can provide downcasting helper -// functions in the base class. - -struct CordRepConcat; + std::atomic<int32_t> count_; +}; + +// The overhead of a vtable is too much for Cord, so we roll our own subclasses +// using only a single byte to differentiate classes from each other - the "tag" +// byte. Define the subclasses first so we can provide downcasting helper +// functions in the base class. + +struct CordRepConcat; struct CordRepExternal; struct CordRepFlat; -struct CordRepSubstring; +struct CordRepSubstring; class CordRepRing; class CordRepBtree; - -// Various representations that we allow -enum CordRepKind { + +// Various representations that we allow +enum CordRepKind { CONCAT = 0, SUBSTRING = 1, BTREE = 2, 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 @@ -211,8 +211,8 @@ enum CordRepKind { // 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' @@ -224,19 +224,19 @@ static_assert(RING == BTREE + 1, "BTREE and RING not consecutive"); static_assert(EXTERNAL == RING + 1, "BTREE and EXTERNAL not consecutive"); static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive"); -struct CordRep { +struct CordRep { CordRep() = default; constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l) : 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; + // The following three fields have to be less than 32 bytes since + // that is the smallest supported flat node size. + 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. - uint8_t tag; - + // 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. + uint8_t tag; + // `storage` provides two main purposes: // - the starting point for FlatCordRep.Data() [flexible-array-member] // - 3 bytes of additional storage for use by derived classes. @@ -257,12 +257,12 @@ struct CordRep { 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 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 CordRepBtree* btree(); @@ -281,82 +281,82 @@ struct CordRep { // 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 { - CordRep* left; - CordRep* right; - +}; + +struct CordRepConcat : public CordRep { + CordRep* left; + CordRep* right; + uint8_t depth() const { return storage[0]; } void set_depth(uint8_t depth) { storage[0] = depth; } -}; - -struct CordRepSubstring : public CordRep { - size_t start; // Starting offset of substring in child - 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*); - -// 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 { +}; + +struct CordRepSubstring : public CordRep { + size_t start; // Starting offset of substring in child + 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*); + +// 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(absl::string_view str) : CordRep(RefcountAndFlags::Immortal{}, str.size()), base(str.data()), releaser_invoker(nullptr) {} - const char* base; - // Pointer to function that knows how to call and destroy the releaser. - ExternalReleaserInvoker releaser_invoker; + const char* base; + // Pointer to function that knows how to call and destroy the releaser. + ExternalReleaserInvoker releaser_invoker; // Deletes (releases) the external rep. // Requires rep != nullptr and rep->IsExternal() static void Delete(CordRep* rep); -}; - -struct Rank1 {}; -struct Rank0 : Rank1 {}; - -template <typename Releaser, typename = ::absl::base_internal::invoke_result_t< - Releaser, absl::string_view>> -void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) { - ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data); -} - -template <typename Releaser, - typename = ::absl::base_internal::invoke_result_t<Releaser>> -void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) { - ::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 ::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>()), - absl::string_view(base, length)); - } - - static void Release(CordRepExternal* rep) { - delete static_cast<CordRepExternalImpl*>(rep); - } -}; - +}; + +struct Rank1 {}; +struct Rank0 : Rank1 {}; + +template <typename Releaser, typename = ::absl::base_internal::invoke_result_t< + Releaser, absl::string_view>> +void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) { + ::absl::base_internal::invoke(std::forward<Releaser>(releaser), data); +} + +template <typename Releaser, + typename = ::absl::base_internal::invoke_result_t<Releaser>> +void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) { + ::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 ::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>()), + 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); @@ -372,10 +372,10 @@ struct ConstInitExternalStorage { template <typename Str> CordRepExternal ConstInitExternalStorage<Str>::value(Str::value); -enum { - kMaxInline = 15, -}; - +enum { + kMaxInline = 15, +}; + constexpr char GetOrNull(absl::string_view data, size_t pos) { return pos < data.size() ? data[pos] : '\0'; } @@ -564,10 +564,10 @@ class InlineData { char as_chars_[kMaxInline + 1]; AsTree as_tree_; }; -}; - -static_assert(sizeof(InlineData) == kMaxInline + 1, ""); - +}; + +static_assert(sizeof(InlineData) == kMaxInline + 1, ""); + inline CordRepConcat* CordRep::concat() { assert(IsConcat()); return static_cast<CordRepConcat*>(this); @@ -613,8 +613,8 @@ inline void CordRep::Unref(CordRep* rep) { } } -} // namespace cord_internal +} // namespace cord_internal -ABSL_NAMESPACE_END -} // namespace absl -#endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ +ABSL_NAMESPACE_END +} // namespace absl +#endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/cordz_functions/ya.make b/contrib/restricted/abseil-cpp/absl/strings/internal/cordz_functions/ya.make index 6dc8a23cc5..69f582d096 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/cordz_functions/ya.make +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/cordz_functions/ya.make @@ -22,10 +22,10 @@ NO_COMPILER_WARNINGS() NO_UTIL() -CFLAGS( - -DNOMINMAX -) - +CFLAGS( + -DNOMINMAX +) + SRCDIR(contrib/restricted/abseil-cpp/absl/strings/internal) SRCS( diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.cc index c5271286ad..73de85e483 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.cc @@ -1,180 +1,180 @@ -// 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 "absl/strings/internal/escaping.h" - -#include "absl/base/internal/endian.h" -#include "absl/base/internal/raw_logging.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -const char kBase64Chars[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { - // Base64 encodes three bytes of input at a time. If the input is not - // divisible by three, we pad as appropriate. - // - // (from https://tools.ietf.org/html/rfc3548) - // Special processing is performed if fewer than 24 bits are available - // at the end of the data being encoded. A full encoding quantum is - // always completed at the end of a quantity. When fewer than 24 input - // bits are available in an input group, zero bits are added (on the - // right) to form an integral number of 6-bit groups. Padding at the - // end of the data is performed using the '=' character. Since all base - // 64 input is an integral number of octets, only the following cases - // can arise: - - // Base64 encodes each three bytes of input into four bytes of output. - size_t len = (input_len / 3) * 4; - - if (input_len % 3 == 0) { - // (from https://tools.ietf.org/html/rfc3548) - // (1) the final quantum of encoding input is an integral multiple of 24 - // bits; here, the final unit of encoded output will be an integral - // multiple of 4 characters with no "=" padding, - } else if (input_len % 3 == 1) { - // (from https://tools.ietf.org/html/rfc3548) - // (2) the final quantum of encoding input is exactly 8 bits; here, the - // final unit of encoded output will be two characters followed by two - // "=" padding characters, or - len += 2; - if (do_padding) { - len += 2; - } - } else { // (input_len % 3 == 2) - // (from https://tools.ietf.org/html/rfc3548) - // (3) the final quantum of encoding input is exactly 16 bits; here, the - // final unit of encoded output will be three characters followed by one - // "=" padding character. - len += 3; - if (do_padding) { - len += 1; - } - } - - assert(len >= input_len); // make sure we didn't overflow - return len; -} - -size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, - size_t szdest, const char* base64, - bool do_padding) { - static const char kPad64 = '='; - - if (szsrc * 4 > szdest * 3) return 0; - - char* cur_dest = dest; - const unsigned char* cur_src = src; - - char* const limit_dest = dest + szdest; - const unsigned char* const limit_src = src + szsrc; - - // Three bytes of data encodes to four characters of cyphertext. - // So we can pump through three-byte chunks atomically. - if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3. - while (cur_src < limit_src - 3) { // While we have >= 32 bits. - uint32_t in = absl::big_endian::Load32(cur_src) >> 8; - - cur_dest[0] = base64[in >> 18]; - in &= 0x3FFFF; - cur_dest[1] = base64[in >> 12]; - in &= 0xFFF; - cur_dest[2] = base64[in >> 6]; - in &= 0x3F; - cur_dest[3] = base64[in]; - - cur_dest += 4; - cur_src += 3; - } - } - // To save time, we didn't update szdest or szsrc in the loop. So do it now. - szdest = limit_dest - cur_dest; - szsrc = limit_src - cur_src; - - /* now deal with the tail (<=3 bytes) */ - switch (szsrc) { - case 0: - // Nothing left; nothing more to do. - break; - case 1: { - // One byte left: this encodes to two characters, and (optionally) - // two pad characters to round out the four-character cypherblock. - if (szdest < 2) return 0; - uint32_t in = cur_src[0]; - cur_dest[0] = base64[in >> 2]; - in &= 0x3; - cur_dest[1] = base64[in << 4]; - cur_dest += 2; - szdest -= 2; - if (do_padding) { - if (szdest < 2) return 0; - cur_dest[0] = kPad64; - cur_dest[1] = kPad64; - cur_dest += 2; - szdest -= 2; - } - break; - } - case 2: { - // Two bytes left: this encodes to three characters, and (optionally) - // one pad character to round out the four-character cypherblock. - if (szdest < 3) return 0; - uint32_t in = absl::big_endian::Load16(cur_src); - cur_dest[0] = base64[in >> 10]; - in &= 0x3FF; - cur_dest[1] = base64[in >> 4]; - in &= 0x00F; - cur_dest[2] = base64[in << 2]; - cur_dest += 3; - szdest -= 3; - if (do_padding) { - if (szdest < 1) return 0; - cur_dest[0] = kPad64; - cur_dest += 1; - szdest -= 1; - } - break; - } - case 3: { - // Three bytes left: same as in the big loop above. We can't do this in - // the loop because the loop above always reads 4 bytes, and the fourth - // byte is past the end of the input. - if (szdest < 4) return 0; - uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1); - cur_dest[0] = base64[in >> 18]; - in &= 0x3FFFF; - cur_dest[1] = base64[in >> 12]; - in &= 0xFFF; - cur_dest[2] = base64[in >> 6]; - in &= 0x3F; - cur_dest[3] = base64[in]; - cur_dest += 4; - szdest -= 4; - break; - } - default: - // Should not be reached: blocks of 4 bytes are handled - // in the while loop before this switch statement. - ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc); - break; - } - return (cur_dest - dest); -} - -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl +// 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 "absl/strings/internal/escaping.h" + +#include "absl/base/internal/endian.h" +#include "absl/base/internal/raw_logging.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace strings_internal { + +const char kBase64Chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { + // Base64 encodes three bytes of input at a time. If the input is not + // divisible by three, we pad as appropriate. + // + // (from https://tools.ietf.org/html/rfc3548) + // Special processing is performed if fewer than 24 bits are available + // at the end of the data being encoded. A full encoding quantum is + // always completed at the end of a quantity. When fewer than 24 input + // bits are available in an input group, zero bits are added (on the + // right) to form an integral number of 6-bit groups. Padding at the + // end of the data is performed using the '=' character. Since all base + // 64 input is an integral number of octets, only the following cases + // can arise: + + // Base64 encodes each three bytes of input into four bytes of output. + size_t len = (input_len / 3) * 4; + + if (input_len % 3 == 0) { + // (from https://tools.ietf.org/html/rfc3548) + // (1) the final quantum of encoding input is an integral multiple of 24 + // bits; here, the final unit of encoded output will be an integral + // multiple of 4 characters with no "=" padding, + } else if (input_len % 3 == 1) { + // (from https://tools.ietf.org/html/rfc3548) + // (2) the final quantum of encoding input is exactly 8 bits; here, the + // final unit of encoded output will be two characters followed by two + // "=" padding characters, or + len += 2; + if (do_padding) { + len += 2; + } + } else { // (input_len % 3 == 2) + // (from https://tools.ietf.org/html/rfc3548) + // (3) the final quantum of encoding input is exactly 16 bits; here, the + // final unit of encoded output will be three characters followed by one + // "=" padding character. + len += 3; + if (do_padding) { + len += 1; + } + } + + assert(len >= input_len); // make sure we didn't overflow + return len; +} + +size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, + size_t szdest, const char* base64, + bool do_padding) { + static const char kPad64 = '='; + + if (szsrc * 4 > szdest * 3) return 0; + + char* cur_dest = dest; + const unsigned char* cur_src = src; + + char* const limit_dest = dest + szdest; + const unsigned char* const limit_src = src + szsrc; + + // Three bytes of data encodes to four characters of cyphertext. + // So we can pump through three-byte chunks atomically. + if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3. + while (cur_src < limit_src - 3) { // While we have >= 32 bits. + uint32_t in = absl::big_endian::Load32(cur_src) >> 8; + + cur_dest[0] = base64[in >> 18]; + in &= 0x3FFFF; + cur_dest[1] = base64[in >> 12]; + in &= 0xFFF; + cur_dest[2] = base64[in >> 6]; + in &= 0x3F; + cur_dest[3] = base64[in]; + + cur_dest += 4; + cur_src += 3; + } + } + // To save time, we didn't update szdest or szsrc in the loop. So do it now. + szdest = limit_dest - cur_dest; + szsrc = limit_src - cur_src; + + /* now deal with the tail (<=3 bytes) */ + switch (szsrc) { + case 0: + // Nothing left; nothing more to do. + break; + case 1: { + // One byte left: this encodes to two characters, and (optionally) + // two pad characters to round out the four-character cypherblock. + if (szdest < 2) return 0; + uint32_t in = cur_src[0]; + cur_dest[0] = base64[in >> 2]; + in &= 0x3; + cur_dest[1] = base64[in << 4]; + cur_dest += 2; + szdest -= 2; + if (do_padding) { + if (szdest < 2) return 0; + cur_dest[0] = kPad64; + cur_dest[1] = kPad64; + cur_dest += 2; + szdest -= 2; + } + break; + } + case 2: { + // Two bytes left: this encodes to three characters, and (optionally) + // one pad character to round out the four-character cypherblock. + if (szdest < 3) return 0; + uint32_t in = absl::big_endian::Load16(cur_src); + cur_dest[0] = base64[in >> 10]; + in &= 0x3FF; + cur_dest[1] = base64[in >> 4]; + in &= 0x00F; + cur_dest[2] = base64[in << 2]; + cur_dest += 3; + szdest -= 3; + if (do_padding) { + if (szdest < 1) return 0; + cur_dest[0] = kPad64; + cur_dest += 1; + szdest -= 1; + } + break; + } + case 3: { + // Three bytes left: same as in the big loop above. We can't do this in + // the loop because the loop above always reads 4 bytes, and the fourth + // byte is past the end of the input. + if (szdest < 4) return 0; + uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1); + cur_dest[0] = base64[in >> 18]; + in &= 0x3FFFF; + cur_dest[1] = base64[in >> 12]; + in &= 0xFFF; + cur_dest[2] = base64[in >> 6]; + in &= 0x3F; + cur_dest[3] = base64[in]; + cur_dest += 4; + szdest -= 4; + break; + } + default: + // Should not be reached: blocks of 4 bytes are handled + // in the while loop before this switch statement. + ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc); + break; + } + return (cur_dest - dest); +} + +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.h b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.h index 6a9ce602d9..dc20940e75 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping.h @@ -1,58 +1,58 @@ -// 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_ESCAPING_H_ -#define ABSL_STRINGS_INTERNAL_ESCAPING_H_ - -#include <cassert> - -#include "absl/strings/internal/resize_uninitialized.h" - -namespace absl { -ABSL_NAMESPACE_BEGIN -namespace strings_internal { - -ABSL_CONST_INIT extern const char kBase64Chars[]; - -// Calculates how long a string will be when it is base64 encoded given its -// length and whether or not the result should be padded. -size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding); - -// Base64-encodes `src` using the alphabet provided in `base64` and writes the -// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars -// until its length is a multiple of 3. Returns the length of `dest`. -size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, - size_t szdest, const char* base64, bool do_padding); - -// Base64-encodes `src` using the alphabet provided in `base64` and writes the -// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars -// until its length is a multiple of 3. -template <typename String> -void Base64EscapeInternal(const unsigned char* src, size_t szsrc, String* dest, - bool do_padding, const char* base64_chars) { - const size_t calc_escaped_size = - CalculateBase64EscapedLenInternal(szsrc, do_padding); - STLStringResizeUninitialized(dest, calc_escaped_size); - - const size_t escaped_len = Base64EscapeInternal( - src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding); - assert(calc_escaped_size == escaped_len); - dest->erase(escaped_len); -} - -} // namespace strings_internal -ABSL_NAMESPACE_END -} // namespace absl - -#endif // ABSL_STRINGS_INTERNAL_ESCAPING_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_ESCAPING_H_ +#define ABSL_STRINGS_INTERNAL_ESCAPING_H_ + +#include <cassert> + +#include "absl/strings/internal/resize_uninitialized.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace strings_internal { + +ABSL_CONST_INIT extern const char kBase64Chars[]; + +// Calculates how long a string will be when it is base64 encoded given its +// length and whether or not the result should be padded. +size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding); + +// Base64-encodes `src` using the alphabet provided in `base64` and writes the +// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars +// until its length is a multiple of 3. Returns the length of `dest`. +size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, + size_t szdest, const char* base64, bool do_padding); + +// Base64-encodes `src` using the alphabet provided in `base64` and writes the +// result to `dest`. If `do_padding` is true, `dest` is padded with '=' chars +// until its length is a multiple of 3. +template <typename String> +void Base64EscapeInternal(const unsigned char* src, size_t szsrc, String* dest, + bool do_padding, const char* base64_chars) { + const size_t calc_escaped_size = + CalculateBase64EscapedLenInternal(szsrc, do_padding); + STLStringResizeUninitialized(dest, calc_escaped_size); + + const size_t escaped_len = Base64EscapeInternal( + src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding); + assert(calc_escaped_size == escaped_len); + dest->erase(escaped_len); +} + +} // namespace strings_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_STRINGS_INTERNAL_ESCAPING_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping_test_common.h b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping_test_common.h index 7b18017a08..0e6fc75de7 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/escaping_test_common.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/escaping_test_common.h @@ -22,7 +22,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { struct base64_testcase { @@ -127,7 +127,7 @@ inline const std::array<base64_testcase, 5>& base64_strings() { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.cc index 2519c6881e..22a33cc584 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.cc @@ -17,7 +17,7 @@ #include <cstdlib> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { int memcasecmp(const char* s1, const char* s2, size_t len) { @@ -108,5 +108,5 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.h b/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.h index 9ad0535808..f0217db9f1 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/memutil.h @@ -69,7 +69,7 @@ #include "absl/strings/ascii.h" // for absl::ascii_tolower namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { inline char* memcat(char* dest, size_t destlen, const char* src, @@ -142,7 +142,7 @@ const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, size_t neelen); } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/numbers_test_common.h b/contrib/restricted/abseil-cpp/absl/strings/internal/numbers_test_common.h index eaa88a8897..709cc6b209 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/numbers_test_common.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/numbers_test_common.h @@ -23,10 +23,10 @@ #include <limits> #include <string> -#include "absl/base/config.h" - +#include "absl/base/config.h" + namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { template <typename IntType> @@ -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}, }}; @@ -178,7 +178,7 @@ inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.cc index 05324c780c..290b3b1776 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.cc @@ -15,7 +15,7 @@ #include "absl/strings/internal/ostringstream.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { OStringStream::Buf::int_type OStringStream::overflow(int c) { @@ -32,5 +32,5 @@ std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.h b/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.h index d25d60473f..a219a0be4c 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/ostringstream.h @@ -23,7 +23,7 @@ #include "absl/base/port.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // The same as std::ostringstream but appends to a user-specified std::string, @@ -83,7 +83,7 @@ class OStringStream : private std::basic_streambuf<char>, public std::ostream { }; } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/pow10_helper.h b/contrib/restricted/abseil-cpp/absl/strings/internal/pow10_helper.h index c37c2c3ffe..5e124e4cac 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/pow10_helper.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/pow10_helper.h @@ -22,10 +22,10 @@ #include <vector> -#include "absl/base/config.h" - +#include "absl/base/config.h" + namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // Computes the precise value of 10^exp. (I.e. the nearest representable @@ -34,7 +34,7 @@ namespace strings_internal { double Pow10(int exp); } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/resize_uninitialized.h b/contrib/restricted/abseil-cpp/absl/strings/internal/resize_uninitialized.h index 49859dcc7d..023a61c69b 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/resize_uninitialized.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/resize_uninitialized.h @@ -26,7 +26,7 @@ #include "absl/meta/type_traits.h" // for void_t namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // In this type trait, we look for a __resize_default_init member function, and @@ -113,7 +113,7 @@ void STLStringResizeUninitializedAmortized(string_type* s, size_t new_size) { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/stl_type_traits.h b/contrib/restricted/abseil-cpp/absl/strings/internal/stl_type_traits.h index 6035ca45cb..20b0bee39e 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/stl_type_traits.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/stl_type_traits.h @@ -40,7 +40,7 @@ #include "absl/meta/type_traits.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { template <typename C, template <typename...> class T> @@ -243,6 +243,6 @@ struct IsStrictlyBaseOfAndConvertibleToSTLContainer IsConvertibleToSTLContainer<C>> {}; } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.cc index e28a29b171..bf57d5fdc7 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.cc +++ b/contrib/restricted/abseil-cpp/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,10 +26,10 @@ #include "absl/base/port.h" #include "absl/strings/internal/str_format/float_conversion.h" -#include "absl/strings/numbers.h" +#include "absl/strings/numbers.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { namespace { @@ -61,179 +61,179 @@ struct IsSigned<absl::int128> : std::true_type {}; template <> struct IsSigned<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()) && - ConvertFloatImpl(v, conv, sink); +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 std::string &v, - const FormatConversionSpecImpl conv, - FormatSinkImpl *sink) { +StringConvertResult FormatConvertImpl(const std::string &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) { @@ -374,106 +374,106 @@ FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv, } else if (conv.precision() < 0) { len = std::strlen(v); } else { - // If precision is set, we look for the NUL-terminator on the valid range. + // If precision is set, we look for the NUL-terminator on the valid range. len = std::find(v, v + conv.precision(), '\0') - v; } return {ConvertStringArg(string_view(v, len), conv, sink)}; } // ==================== 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(absl::int128 v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } IntegralConvertResult FormatConvertImpl(absl::uint128 v, - const FormatConversionSpecImpl conv, + const FormatConversionSpecImpl conv, FormatSinkImpl *sink) { return {ConvertIntArg(v, conv, sink)}; } @@ -484,5 +484,5 @@ ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(); } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.h index 3c91be701f..fbfa00ee47 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/arg.h +++ b/contrib/restricted/abseil-cpp/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_ @@ -33,58 +33,58 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN -class Cord; +class Cord; class FormatCountCapture; class FormatSink; -template <absl::FormatConversionCharSet C> -struct FormatConvertResult; -class FormatConversionSpec; - +template <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 = - absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; - using FormatSinkT = - 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 = + absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>; + using FormatSinkT = + 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; @@ -95,33 +95,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 std::string& v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); -StringConvertResult FormatConvertImpl(string_view v, - FormatConversionSpecImpl conv, - FormatSinkImpl* sink); +StringConvertResult FormatConvertImpl(const std::string& 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, @@ -130,17 +130,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, 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, 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(); @@ -156,80 +156,80 @@ StringConvertResult FormatConvertImpl(const AbslCord& value, if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); - for (string_view piece : value.Chunks()) { - if (piece.size() > to_write) { - piece.remove_suffix(piece.size() - to_write); - to_write = 0; - } else { - to_write -= piece.size(); - } + for (string_view piece : value.Chunks()) { + if (piece.size() > to_write) { + piece.remove_suffix(piece.size() - to_write); + to_write = 0; + } else { + to_write -= piece.size(); + } sink->Append(piece); - if (to_write == 0) { - break; - } + if (to_write == 0) { + break; + } } if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); 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); } @@ -240,12 +240,12 @@ 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) { +StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, + FormatConversionSpecImpl conv, + FormatSinkImpl* out) { std::ostringstream oss; oss << v.v_; if (!oss) return {false}; @@ -256,24 +256,24 @@ StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v, // 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 absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; - if (conv.conversion_char() != - str_format_internal::FormatConversionCharInternal::n) { + 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); } @@ -282,13 +282,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); } @@ -299,15 +299,15 @@ struct FormatArgImplFriend { } }; -template <typename Arg> -constexpr FormatConversionCharSet ArgumentToConv() { - return 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 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: @@ -321,7 +321,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 @@ -463,20 +463,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; } @@ -484,9 +484,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, \ @@ -520,7 +520,7 @@ ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(extern); } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.cc index c988ba8fd2..34742bff72 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.cc +++ b/contrib/restricted/abseil-cpp/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 "absl/strings/internal/str_format/bind.h" #include <cerrno> @@ -20,7 +20,7 @@ #include <string> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { namespace { @@ -80,21 +80,21 @@ inline bool ArgContext::Bind(const UnboundConversion* unbound, return false; } - FormatConversionSpecImplFriend::SetWidth(width, bound); - FormatConversionSpecImplFriend::SetPrecision(precision, bound); - - if (force_left) { + FormatConversionSpecImplFriend::SetWidth(width, bound); + FormatConversionSpecImplFriend::SetPrecision(precision, bound); + + if (force_left) { FormatConversionSpecImplFriend::SetFlags(unbound->flags | Flags::kLeft, bound); - } else { - FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); - } + } else { + FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); + } } else { - FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); - FormatConversionSpecImplFriend::SetWidth(-1, bound); - FormatConversionSpecImplFriend::SetPrecision(-1, bound); + FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound); + FormatConversionSpecImplFriend::SetWidth(-1, bound); + FormatConversionSpecImplFriend::SetPrecision(-1, bound); } - FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound); + FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound); bound->set_arg(arg); return true; } @@ -156,11 +156,11 @@ class SummarizingConverter { UntypedFormatSpecImpl spec("%d"); std::ostringstream ss; - ss << "{" << Streamable(spec, {*bound.arg()}) << ":" - << FormatConversionSpecImplFriend::FlagsToString(bound); + ss << "{" << Streamable(spec, {*bound.arg()}) << ":" + << 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; } @@ -254,5 +254,5 @@ int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format, } } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.h index b26cff6648..3d88a6f830 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/bind.h +++ b/contrib/restricted/abseil-cpp/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_ @@ -27,13 +27,13 @@ #include "absl/types/span.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN 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,19 +82,19 @@ 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; public: -#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER +#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 @@ -204,14 +204,14 @@ 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_; }; } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/checker.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/checker.h index 2a2601eccf..bfff09965f 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/checker.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/checker.h @@ -1,34 +1,34 @@ -// 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_ -#include "absl/base/attributes.h" +#include "absl/base/attributes.h" #include "absl/strings/internal/str_format/arg.h" #include "absl/strings/internal/str_format/extension.h" // Compile time check support for entry points. #ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER -#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) +#if ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) #define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 -#endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) +#endif // ABSL_HAVE_ATTRIBUTE(enable_if) && !defined(__native_client__) #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { constexpr bool AllOf() { return true; } @@ -38,7 +38,7 @@ constexpr bool AllOf(bool b, T... t) { return b && AllOf(t...); } -#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER +#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER constexpr bool ContainsChar(const char* chars, char c) { return *chars == c || (*chars && ContainsChar(chars + 1, c)); @@ -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)}) @@ -327,7 +327,7 @@ constexpr bool ValidFormatImpl(string_view format) { #endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.cc index 484f6ebfc1..afc0a0bb56 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.cc @@ -20,7 +20,7 @@ #include <string> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { std::string FlagsToString(Flags v) { @@ -33,43 +33,43 @@ std::string FlagsToString(Flags v) { return s; } -#define ABSL_INTERNAL_X_VAL(id) \ - constexpr absl::FormatConversionChar FormatConversionCharInternal::id; -ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) -#undef ABSL_INTERNAL_X_VAL -// NOLINTNEXTLINE(readability-redundant-declaration) -constexpr absl::FormatConversionChar FormatConversionCharInternal::kNone; +#define ABSL_INTERNAL_X_VAL(id) \ + constexpr absl::FormatConversionChar FormatConversionCharInternal::id; +ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) +#undef ABSL_INTERNAL_X_VAL +// NOLINTNEXTLINE(readability-redundant-declaration) +constexpr 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 +#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) { +// 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; } } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.h index 55cbb56d0a..760cda3778 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/extension.h @@ -17,23 +17,23 @@ #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ #include <limits.h> - + #include <cstddef> #include <cstring> #include <ostream> -#include "absl/base/config.h" +#include "absl/base/config.h" #include "absl/base/port.h" -#include "absl/meta/type_traits.h" +#include "absl/meta/type_traits.h" #include "absl/strings/internal/str_format/output.h" #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN - -enum class FormatConversionChar : uint8_t; -enum class FormatConversionCharSet : uint64_t; +ABSL_NAMESPACE_BEGIN +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() { @@ -156,9 +156,9 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) { } // clang-format off -#define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \ +#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 \ @@ -169,108 +169,108 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) { 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 -// (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 +// 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 +// (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 + kNone }; - // clang-format on + // 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 - -inline FormatConversionChar FormatConversionCharFromChar(char c) { - switch (c) { -#define ABSL_INTERNAL_X_VAL(id) \ - case #id[0]: \ - return FormatConversionCharInternal::id; - ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) -#undef ABSL_INTERNAL_X_VAL +#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 + +inline FormatConversionChar FormatConversionCharFromChar(char c) { + switch (c) { +#define ABSL_INTERNAL_X_VAL(id) \ + case #id[0]: \ + return FormatConversionCharInternal::id; + ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, ) +#undef ABSL_INTERNAL_X_VAL } - 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; + 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; } -} - -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; +} + +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; } -} - -inline char FormatConversionCharToChar(FormatConversionChar c) { - 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'; +} + +inline char FormatConversionCharToChar(FormatConversionChar c) { + 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'; } -#undef ABSL_INTERNAL_X_VAL -#undef ABSL_INTERNAL_X_SEP -} +#undef ABSL_INTERNAL_X_VAL +#undef ABSL_INTERNAL_X_SEP +} -// The associated char. -inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) { - char c = FormatConversionCharToChar(v); - if (!c) c = '?'; - return os << c; -} +// The associated char. +inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) { + char c = FormatConversionCharToChar(v); + if (!c) c = '?'; + return os << c; +} -struct FormatConversionSpecImplFriend; +struct FormatConversionSpecImplFriend; -class FormatConversionSpecImpl { - public: - // Width and precison are not specified, no flags are set. +class FormatConversionSpecImpl { + public: + // Width and precison are not specified, no flags are set. bool is_basic() const { return flags_ == Flags::kBasic; } bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); } bool has_show_pos_flag() const { @@ -282,10 +282,10 @@ class FormatConversionSpecImpl { bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); } bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); } - FormatConversionChar conversion_char() const { + 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,96 +296,96 @@ 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; + friend struct str_format_internal::FormatConversionSpecImplFriend; + FormatConversionChar conv_ = FormatConversionCharInternal::kNone; Flags flags_; int width_; int precision_; }; -struct FormatConversionSpecImplFriend final { - static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { - conv->flags_ = f; - } - static void SetConversionChar(FormatConversionChar c, - FormatConversionSpecImpl* conv) { - conv->conv_ = c; - } - static void SetWidth(int w, FormatConversionSpecImpl* conv) { - conv->width_ = w; - } - static void SetPrecision(int p, FormatConversionSpecImpl* conv) { - conv->precision_ = p; - } - static std::string FlagsToString(const FormatConversionSpecImpl& spec) { +struct FormatConversionSpecImplFriend final { + static void SetFlags(Flags f, FormatConversionSpecImpl* conv) { + conv->flags_ = f; + } + static void SetConversionChar(FormatConversionChar c, + FormatConversionSpecImpl* conv) { + conv->conv_ = c; + } + static void SetWidth(int w, FormatConversionSpecImpl* conv) { + conv->width_ = w; + } + static void SetPrecision(int p, FormatConversionSpecImpl* conv) { + conv->precision_ = p; + } + static std::string 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) \ - : - ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, ) -#undef ABSL_INTERNAL_CHAR_SET_CASE +#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 conv == '*' ? 1 : 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 - +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. @@ -393,44 +393,44 @@ struct FormatConversionCharSetInternal { // 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 operator|(FormatConversionCharSet a, - FormatConversionCharSet b) { - return FormatConversionCharSetUnion(a, b); +constexpr FormatConversionCharSet operator|(FormatConversionCharSet a, + FormatConversionCharSet b) { + return FormatConversionCharSetUnion(a, b); } -// Overloaded conversion functions to support absl::ParsedFormat. +// Overloaded conversion functions to support absl::ParsedFormat. // Get a conversion with a single character in it. -constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { - return static_cast<FormatConversionCharSet>( - FormatConversionCharToConvValue(c)); +constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) { + return static_cast<FormatConversionCharSet>( + FormatConversionCharToConvValue(c)); } -// Get a conversion with a single character in it. -constexpr FormatConversionCharSet ToFormatConversionCharSet( - FormatConversionCharSet c) { - return 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; +constexpr bool Contains(FormatConversionCharSet set, char c) { + return (static_cast<uint64_t>(set) & + static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0; } // Checks whether all the characters in `c` are contained in `set` -constexpr bool Contains(FormatConversionCharSet set, - FormatConversionCharSet c) { +constexpr bool Contains(FormatConversionCharSet set, + FormatConversionCharSet c) { return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) == 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) { @@ -439,7 +439,7 @@ inline size_t Excess(size_t used, size_t capacity) { } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc index b1c4068475..1d151dd9bf 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc @@ -1,944 +1,944 @@ -// 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 "absl/strings/internal/str_format/float_conversion.h" #include <string.h> - + #include <algorithm> #include <cassert> #include <cmath> -#include <limits> +#include <limits> #include <string> -#include "absl/base/attributes.h" +#include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/optimization.h" -#include "absl/functional/function_ref.h" -#include "absl/meta/type_traits.h" +#include "absl/base/optimization.h" +#include "absl/functional/function_ref.h" +#include "absl/meta/type_traits.h" #include "absl/numeric/bits.h" -#include "absl/numeric/int128.h" +#include "absl/numeric/int128.h" #include "absl/numeric/internal/representation.h" -#include "absl/strings/numbers.h" -#include "absl/types/optional.h" -#include "absl/types/span.h" +#include "absl/strings/numbers.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { namespace { using ::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 = absl::FunctionRef<void(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(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 = 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; -} - +// 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 = absl::FunctionRef<void(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(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 = 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. -// +// 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, - absl::FunctionRef<void(BinaryToDecimal)> f) { - assert(exp > 0); +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, + absl::FunctionRef<void(BinaryToDecimal)> f) { + assert(exp > 0); assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent); - static_assert( + static_assert( static_cast<int>(StackArray::kMaxCapacity) >= ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent), - ""); - - StackArray::RunWithCapacity( - ChunksNeeded(exp), - [=](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. - absl::string_view CurrentDigits() const { - return 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(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; - - absl::Span<uint32_t> data_; -}; - -// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits. -// Requires `-exp < 0` and + ""); + + StackArray::RunWithCapacity( + ChunksNeeded(exp), + [=](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. + absl::string_view CurrentDigits() const { + return 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(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; + + 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, absl::FunctionRef<void(FractionalDigitGenerator)> f) { +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, 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, - [=](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(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_; - absl::Span<uint32_t> data_; -}; - -// Count the number of leading zero bits. + 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, + [=](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(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_; + 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); +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, absl::string_view data, - int padding_offset, int trailing_zeros, - 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, 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 = +} + +// 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, absl::string_view data, + int padding_offset, int trailing_zeros, + 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, 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(absl::string_view v, char *out) { + 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(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; @@ -946,22 +946,22 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv, { char *fp = fmt; *fp++ = '%'; - fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp); + fp = CopyStringTo(FormatConversionSpecImplFriend::FlagsToString(conv), fp); fp = CopyStringTo("*.*", fp); 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)); } std::string space(512, '\0'); - absl::string_view result; + 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 = absl::string_view(space.data(), n); + result = 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 = - 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 = + 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, absl::string_view str, - const FormatConversionSpecImpl &conv, - FormatSinkImpl *sink) { +void WriteBufferToSink(char sign_char, 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,95 +1329,95 @@ 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, - absl::string_view(buffer.begin, buffer.end - buffer.begin), - conv, sink); + 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); - } - + 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); } } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.h index 71100e7142..5d44c4b5e9 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/float_conversion.h @@ -1,37 +1,37 @@ -// 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_ #include "absl/strings/internal/str_format/extension.h" namespace absl { -ABSL_NAMESPACE_BEGIN +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 -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.cc index c4b2470613..f96aa1ecaa 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.cc @@ -18,7 +18,7 @@ #include <cstring> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { namespace { @@ -68,5 +68,5 @@ void FILERawSink::Write(string_view v) { } } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.h index 8030dae00f..3eb18ccd47 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/output.h @@ -29,7 +29,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { // RawSink implementation that writes into a char* buffer. @@ -82,15 +82,15 @@ 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 -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.cc index 2c9c07dacc..b7ace91c1b 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.cc +++ b/contrib/restricted/abseil-cpp/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 "absl/strings/internal/str_format/parser.h" #include <assert.h> @@ -28,12 +28,12 @@ #include <unordered_set> namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { -using CC = FormatConversionCharInternal; -using LM = LengthMod; - +using CC = FormatConversionCharInternal; +using LM = LengthMod; + // Abbreviations to fit in the table below. constexpr auto f_sign = Flags::kSignCol; constexpr auto f_alt = Flags::kAlt; @@ -209,11 +209,11 @@ const char *ConsumeConversion(const char *pos, const char *const end, using str_format_internal::LengthMod; LengthMod length_mod = tag.as_length(); ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - if (c == 'h' && length_mod == LengthMod::h) { - conv->length_mod = LengthMod::hh; + if (c == 'h' && length_mod == LengthMod::h) { + conv->length_mod = LengthMod::hh; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); - } else if (c == 'l' && length_mod == LengthMod::l) { - conv->length_mod = LengthMod::ll; + } else if (c == 'l' && length_mod == LengthMod::l) { + conv->length_mod = LengthMod::ll; ABSL_FORMAT_PARSER_INTERNAL_GET_CHAR(); } else { conv->length_mod = length_mod; @@ -232,32 +232,32 @@ const char *ConsumeConversion(const char *pos, const char *const end, } // namespace -std::string LengthModToString(LengthMod v) { - switch (v) { - case LengthMod::h: - return "h"; - case LengthMod::hh: - return "hh"; - case LengthMod::l: - return "l"; - case LengthMod::ll: - return "ll"; - case LengthMod::L: - return "L"; - case LengthMod::j: - return "j"; - case LengthMod::z: - return "z"; - case LengthMod::t: - return "t"; - case LengthMod::q: - return "q"; - case LengthMod::none: - return ""; - } - return ""; -} - +std::string LengthModToString(LengthMod v) { + switch (v) { + case LengthMod::h: + return "h"; + case LengthMod::hh: + return "hh"; + case LengthMod::l: + return "l"; + case LengthMod::ll: + return "ll"; + case LengthMod::L: + return "L"; + case LengthMod::j: + return "j"; + case LengthMod::z: + return "z"; + case LengthMod::t: + return "t"; + case LengthMod::q: + return "q"; + case LengthMod::none: + return ""; + } + return ""; +} + const char *ConsumeUnboundConversion(const char *p, const char *end, UnboundConversion *conv, int *next_arg) { if (*next_arg < 0) return ConsumeConversion<true>(p, end, conv, next_arg); @@ -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() || @@ -327,13 +327,13 @@ bool ParsedFormatBase::MatchesConversions( if (conv.width.is_from_arg() && !add_if_valid_conv(conv.width.get_from_arg(), '*')) return false; - if (!add_if_valid_conv(conv.arg_position, - FormatConversionCharToChar(conv.conv))) - return false; + if (!add_if_valid_conv(conv.arg_position, + FormatConversionCharToChar(conv.conv))) + return false; } return used.size() == convs.size() || allow_ignored; } } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.h index ad8646edff..c0db5b4335 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_format/parser.h +++ b/contrib/restricted/abseil-cpp/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_ @@ -20,25 +20,25 @@ #include <stdlib.h> #include <cassert> -#include <cstdint> +#include <cstdint> #include <initializer_list> #include <iosfwd> #include <iterator> #include <memory> -#include <string> +#include <string> #include <vector> #include "absl/strings/internal/str_format/checker.h" #include "absl/strings/internal/str_format/extension.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace str_format_internal { -enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none }; - -std::string LengthModToString(LengthMod v); - +enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none }; + +std::string LengthModToString(LengthMod v); + // The analyzed properties of a single specified conversion. struct UnboundConversion { UnboundConversion() {} @@ -77,8 +77,8 @@ struct UnboundConversion { InputValue precision; Flags flags = Flags::kBasic; - LengthMod length_mod = LengthMod::none; - FormatConversionChar conv = FormatConversionCharInternal::kNone; + LengthMod length_mod = LengthMod::none; + FormatConversionChar conv = FormatConversionCharInternal::kNone; }; // Consume conversion spec prefix (not including '%') of [p, end) if valid. @@ -91,12 +91,12 @@ const char* ConsumeUnboundConversion(const char* p, const char* end, // Helper tag class for the table below. // It allows fast `char -> ConversionChar/LengthMod/Flags` checking and -// conversions. +// 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 + constexpr ConvTag(LengthMod length_mod) // NOLINT : tag_(0x80 | static_cast<uint8_t>(length_mod)) {} constexpr ConvTag(Flags flags) // NOLINT : tag_(0xc0 | static_cast<uint8_t>(flags)) {} @@ -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 +#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 @@ -351,7 +351,7 @@ class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { : ParsedFormatBase(s, allow_ignored, {C...}) {} }; } // namespace str_format_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_join_internal.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_join_internal.h index 31dbf672f0..86219f2016 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_join_internal.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_join_internal.h @@ -43,7 +43,7 @@ #include "absl/strings/str_cat.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // @@ -308,7 +308,7 @@ std::string JoinRange(const Range& range, absl::string_view separator) { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/str_split_internal.h b/contrib/restricted/abseil-cpp/absl/strings/internal/str_split_internal.h index e766421617..a7229b6873 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/str_split_internal.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/str_split_internal.h @@ -47,7 +47,7 @@ #endif // _GLIBCXX_DEBUG namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // This class is implicitly constructible from everything that absl::string_view @@ -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; @@ -424,7 +424,7 @@ class Splitter { }; } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.cc b/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.cc index 8fd8edc1ec..66a2ca9496 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.cc @@ -17,7 +17,7 @@ #include "absl/strings/internal/utf8.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { @@ -49,5 +49,5 @@ size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { } } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.h b/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.h index 32fb1093be..38ce7b97d8 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.h +++ b/contrib/restricted/abseil-cpp/absl/strings/internal/utf8.h @@ -20,10 +20,10 @@ #include <cstddef> #include <cstdint> -#include "absl/base/config.h" - +#include "absl/base/config.h" + namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes @@ -44,7 +44,7 @@ enum { kMaxEncodedUTF8Size = 4 }; size_t EncodeUTF8Char(char *buffer, char32_t utf8_char); } // namespace strings_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_UTF8_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/match.cc b/contrib/restricted/abseil-cpp/absl/strings/match.cc index 2d67250970..c77d0ad322 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/match.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/match.cc @@ -17,7 +17,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN bool EqualsIgnoreCase(absl::string_view piece1, absl::string_view piece2) noexcept { @@ -39,5 +39,5 @@ bool EndsWithIgnoreCase(absl::string_view text, EqualsIgnoreCase(text.substr(text.size() - suffix.size()), suffix); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/match.h b/contrib/restricted/abseil-cpp/absl/strings/match.h index 038cbb3fa8..d83d31ea1d 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/match.h +++ b/contrib/restricted/abseil-cpp/absl/strings/match.h @@ -20,7 +20,7 @@ // This file contains simple utilities for performing string matching checks. // All of these function parameters are specified as `absl::string_view`, // meaning that these functions can accept `std::string`, `absl::string_view` or -// NUL-terminated C-style strings. +// NUL-terminated C-style strings. // // Examples: // std::string s = "foo"; @@ -38,7 +38,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // StrContains() // @@ -94,7 +94,7 @@ bool StartsWithIgnoreCase(absl::string_view text, bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) noexcept; -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_MATCH_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/numbers.cc b/contrib/restricted/abseil-cpp/absl/strings/numbers.cc index cbd84c918b..43550e3c4b 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/numbers.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/numbers.cc @@ -30,7 +30,7 @@ #include <memory> #include <utility> -#include "absl/base/attributes.h" +#include "absl/base/attributes.h" #include "absl/base/internal/raw_logging.h" #include "absl/numeric/bits.h" #include "absl/strings/ascii.h" @@ -41,7 +41,7 @@ #include "absl/strings/str_cat.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN bool SimpleAtof(absl::string_view str, float* out) { *out = 0.0; @@ -730,8 +730,8 @@ inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/, // commonly used bases. template <typename IntType> struct LookupTables { - ABSL_CONST_INIT static const IntType kVmaxOverBase[]; - ABSL_CONST_INIT static const IntType kVminOverBase[]; + ABSL_CONST_INIT static const IntType kVmaxOverBase[]; + ABSL_CONST_INIT static const IntType kVminOverBase[]; }; // An array initializer macro for X/base where base in [0, 36]. @@ -755,49 +755,49 @@ struct LookupTables { // } // See https://godbolt.org/z/aneYsb // -// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting -// array to avoid a static initializer. +// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting +// array to avoid a static initializer. template<> -const uint128 LookupTables<uint128>::kVmaxOverBase[] = { - 0, - 0, - MakeUint128(9223372036854775807u, 18446744073709551615u), - MakeUint128(6148914691236517205u, 6148914691236517205u), - MakeUint128(4611686018427387903u, 18446744073709551615u), - MakeUint128(3689348814741910323u, 3689348814741910323u), - MakeUint128(3074457345618258602u, 12297829382473034410u), - MakeUint128(2635249153387078802u, 5270498306774157604u), - MakeUint128(2305843009213693951u, 18446744073709551615u), - MakeUint128(2049638230412172401u, 14347467612885206812u), - MakeUint128(1844674407370955161u, 11068046444225730969u), - MakeUint128(1676976733973595601u, 8384883669867978007u), - MakeUint128(1537228672809129301u, 6148914691236517205u), - MakeUint128(1418980313362273201u, 4256940940086819603u), - MakeUint128(1317624576693539401u, 2635249153387078802u), - MakeUint128(1229782938247303441u, 1229782938247303441u), - MakeUint128(1152921504606846975u, 18446744073709551615u), - MakeUint128(1085102592571150095u, 1085102592571150095u), - MakeUint128(1024819115206086200u, 16397105843297379214u), - MakeUint128(970881267037344821u, 16504981539634861972u), - MakeUint128(922337203685477580u, 14757395258967641292u), - MakeUint128(878416384462359600u, 14054662151397753612u), - MakeUint128(838488366986797800u, 13415813871788764811u), - MakeUint128(802032351030850070u, 4812194106185100421u), - MakeUint128(768614336404564650u, 12297829382473034410u), - MakeUint128(737869762948382064u, 11805916207174113034u), - MakeUint128(709490156681136600u, 11351842506898185609u), - MakeUint128(683212743470724133u, 17080318586768103348u), - MakeUint128(658812288346769700u, 10540996613548315209u), - MakeUint128(636094623231363848u, 15266270957552732371u), - MakeUint128(614891469123651720u, 9838263505978427528u), - MakeUint128(595056260442243600u, 9520900167075897608u), - MakeUint128(576460752303423487u, 18446744073709551615u), - MakeUint128(558992244657865200u, 8943875914525843207u), - MakeUint128(542551296285575047u, 9765923333140350855u), - MakeUint128(527049830677415760u, 8432797290838652167u), - MakeUint128(512409557603043100u, 8198552921648689607u), -}; - +const uint128 LookupTables<uint128>::kVmaxOverBase[] = { + 0, + 0, + MakeUint128(9223372036854775807u, 18446744073709551615u), + MakeUint128(6148914691236517205u, 6148914691236517205u), + MakeUint128(4611686018427387903u, 18446744073709551615u), + MakeUint128(3689348814741910323u, 3689348814741910323u), + MakeUint128(3074457345618258602u, 12297829382473034410u), + MakeUint128(2635249153387078802u, 5270498306774157604u), + MakeUint128(2305843009213693951u, 18446744073709551615u), + MakeUint128(2049638230412172401u, 14347467612885206812u), + MakeUint128(1844674407370955161u, 11068046444225730969u), + MakeUint128(1676976733973595601u, 8384883669867978007u), + MakeUint128(1537228672809129301u, 6148914691236517205u), + MakeUint128(1418980313362273201u, 4256940940086819603u), + MakeUint128(1317624576693539401u, 2635249153387078802u), + MakeUint128(1229782938247303441u, 1229782938247303441u), + MakeUint128(1152921504606846975u, 18446744073709551615u), + MakeUint128(1085102592571150095u, 1085102592571150095u), + MakeUint128(1024819115206086200u, 16397105843297379214u), + MakeUint128(970881267037344821u, 16504981539634861972u), + MakeUint128(922337203685477580u, 14757395258967641292u), + MakeUint128(878416384462359600u, 14054662151397753612u), + MakeUint128(838488366986797800u, 13415813871788764811u), + MakeUint128(802032351030850070u, 4812194106185100421u), + MakeUint128(768614336404564650u, 12297829382473034410u), + MakeUint128(737869762948382064u, 11805916207174113034u), + MakeUint128(709490156681136600u, 11351842506898185609u), + MakeUint128(683212743470724133u, 17080318586768103348u), + MakeUint128(658812288346769700u, 10540996613548315209u), + MakeUint128(636094623231363848u, 15266270957552732371u), + MakeUint128(614891469123651720u, 9838263505978427528u), + MakeUint128(595056260442243600u, 9520900167075897608u), + MakeUint128(576460752303423487u, 18446744073709551615u), + MakeUint128(558992244657865200u, 8943875914525843207u), + MakeUint128(542551296285575047u, 9765923333140350855u), + MakeUint128(527049830677415760u, 8432797290838652167u), + MakeUint128(512409557603043100u, 8198552921648689607u), +}; + // This kVmaxOverBase generated with // for (int base = 2; base < 37; ++base) { // absl::int128 max = std::numeric_limits<absl::int128>::max(); @@ -922,8 +922,8 @@ inline bool safe_parse_positive_int(absl::string_view text, int base, assert(base >= 0); assert(vmax >= static_cast<IntType>(base)); const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base]; - assert(base < 2 || - std::numeric_limits<IntType>::max() / base == vmax_over_base); + assert(base < 2 || + std::numeric_limits<IntType>::max() / base == vmax_over_base); const char* start = text.data(); const char* end = start + text.size(); // loop over digits @@ -957,8 +957,8 @@ inline bool safe_parse_negative_int(absl::string_view text, int base, assert(vmin < 0); assert(vmin <= 0 - base); IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base]; - assert(base < 2 || - std::numeric_limits<IntType>::min() / base == vmin_over_base); + assert(base < 2 || + std::numeric_limits<IntType>::min() / base == vmin_over_base); // 2003 c++ standard [expr.mul] // "... the sign of the remainder is implementation-defined." // Although (vmin/base)*base + vmin%base is always vmin. @@ -1024,10 +1024,10 @@ inline bool safe_uint_internal(absl::string_view text, IntType* value_p, namespace numbers_internal { // Digit conversion. -ABSL_CONST_INIT ABSL_DLL const char kHexChar[] = - "0123456789abcdef"; +ABSL_CONST_INIT ABSL_DLL const char kHexChar[] = + "0123456789abcdef"; -ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = +ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "000102030405060708090a0b0c0d0e0f" "101112131415161718191a1b1c1d1e1f" "202122232425262728292a2b2c2d2e2f" @@ -1045,7 +1045,7 @@ ABSL_CONST_INIT ABSL_DLL const char kHexTable[513] = "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; -ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = { +ABSL_CONST_INIT ABSL_DLL const char two_ASCII_digits[100][2] = { {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, @@ -1089,5 +1089,5 @@ bool safe_strtou128_base(absl::string_view text, uint128* value, int base) { } } // namespace numbers_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/numbers.h b/contrib/restricted/abseil-cpp/absl/strings/numbers.h index 899e623c8c..6cdaa73db0 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/numbers.h +++ b/contrib/restricted/abseil-cpp/absl/strings/numbers.h @@ -39,7 +39,7 @@ #include <string> #include <type_traits> -#include "absl/base/config.h" +#include "absl/base/config.h" #ifdef __SSE4_2__ // TODO(jorg): Remove this when we figure out the right way // to swap bytes on SSE 4.2 that works with the compilers @@ -55,24 +55,24 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // SimpleAtoi() // -// Converts the given string (optionally followed or preceded by ASCII -// whitespace) into an integer value, returning `true` if successful. The string -// must reflect a base-10 integer whose value falls within the range of the -// integer type (optionally preceded by a `+` or `-`). If any errors are -// encountered, this function returns `false`, leaving `out` in an unspecified -// state. +// Converts the given string (optionally followed or preceded by ASCII +// whitespace) into an integer value, returning `true` if successful. The string +// must reflect a base-10 integer whose value falls within the range of the +// integer type (optionally preceded by a `+` or `-`). If any errors are +// encountered, this function returns `false`, leaving `out` in an unspecified +// state. template <typename int_type> ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out); // SimpleAtof() // // Converts the given string (optionally followed or preceded by ASCII -// whitespace) into a float, which may be rounded on overflow or underflow, -// returning `true` if successful. +// whitespace) into a float, which may be rounded on overflow or underflow, +// returning `true` if successful. // See https://en.cppreference.com/w/c/string/byte/strtof for details about the // allowed formats for `str`, except SimpleAtof() is locale-independent and will // always use the "C" locale. If any errors are encountered, this function @@ -82,8 +82,8 @@ ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* out); // SimpleAtod() // // Converts the given string (optionally followed or preceded by ASCII -// whitespace) into a double, which may be rounded on overflow or underflow, -// returning `true` if successful. +// whitespace) into a double, which may be rounded on overflow or underflow, +// returning `true` if successful. // See https://en.cppreference.com/w/c/string/byte/strtof for details about the // allowed formats for `str`, except SimpleAtod is locale-independent and will // always use the "C" locale. If any errors are encountered, this function @@ -119,21 +119,21 @@ ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, absl::uint128* out); -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl // End of public API. Implementation details follow. namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace numbers_internal { // Digit conversion. -ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef -ABSL_DLL extern const char - kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... -ABSL_DLL extern const char - two_ASCII_digits[100][2]; // 00, 01, 02, 03... +ABSL_DLL extern const char kHexChar[17]; // 0123456789abcdef +ABSL_DLL extern const char + kHexTable[513]; // 000102030405060708090a0b0c0d0e0f1011... +ABSL_DLL extern const char + two_ASCII_digits[100][2]; // 00, 01, 02, 03... // Writes a two-character representation of 'i' to 'buf'. 'i' must be in the // range 0 <= i < 100, and buf must have space for two characters. Example: @@ -298,7 +298,7 @@ ABSL_MUST_USE_RESULT inline bool SimpleHexAtoi(absl::string_view str, return numbers_internal::safe_strtou128_base(str, out, 16); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_NUMBERS_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_cat.cc b/contrib/restricted/abseil-cpp/absl/strings/str_cat.cc index f4a77493a4..5bd867d918 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_cat.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/str_cat.cc @@ -25,7 +25,7 @@ #include "absl/strings/numbers.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN AlphaNum::AlphaNum(Hex hex) { static_assert(numbers_internal::kFastToBufferSize >= 32, @@ -141,12 +141,12 @@ namespace strings_internal { std::string CatPieces(std::initializer_list<absl::string_view> pieces) { std::string result; size_t total_size = 0; - for (const absl::string_view& piece : pieces) total_size += piece.size(); + for (const 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 absl::string_view& piece : pieces) { + for (const 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(std::string* dest, std::initializer_list<absl::string_view> pieces) { size_t old_size = dest->size(); size_t total_size = old_size; - for (const absl::string_view& piece : pieces) { + for (const absl::string_view& piece : pieces) { ASSERT_NO_OVERLAP(*dest, piece); total_size += piece.size(); } @@ -178,7 +178,7 @@ void AppendPieces(std::string* dest, char* const begin = &(*dest)[0]; char* out = begin + old_size; - for (const absl::string_view& piece : pieces) { + for (const absl::string_view& piece : pieces) { const size_t this_size = piece.size(); if (this_size != 0) { memcpy(out, piece.data(), this_size); @@ -242,5 +242,5 @@ void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, assert(out == begin + dest->size()); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_cat.h b/contrib/restricted/abseil-cpp/absl/strings/str_cat.h index a8a85c7322..3253bb0077 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_cat.h +++ b/contrib/restricted/abseil-cpp/absl/strings/str_cat.h @@ -64,7 +64,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { // AlphaNumBuffer allows a way to pass a string to StrCat without having to do @@ -253,7 +253,7 @@ class AlphaNum { const std::basic_string<char, std::char_traits<char>, Allocator>& str) : piece_(str) {} - // 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; @@ -402,7 +402,7 @@ SixDigits(double d) { return result; } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_CAT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_format.h b/contrib/restricted/abseil-cpp/absl/strings/str_format.h index 4b05c70c23..d7a2a90d9f 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_format.h +++ b/contrib/restricted/abseil-cpp/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_ @@ -80,7 +80,7 @@ #include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // UntypedFormatSpec // @@ -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 -// `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 `absl::FormatConversionCharSet::kIntegral`. -// -// Example: -// // Extended format supports multiple conversion characters per argument, -// // specified via a combination of `FormatConversionCharSet` enums. -// using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d | -// 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 = absl::str_format_internal::ExtendedParsedFormat< - 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 +// `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 `absl::FormatConversionCharSet::kIntegral`. +// +// Example: +// // Extended format supports multiple conversion characters per argument, +// // specified via a combination of `FormatConversionCharSet` enums. +// using MyFormat = absl::ParsedFormat<absl::FormatConversionCharSet::d | +// 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 = absl::str_format_internal::ExtendedParsedFormat< + absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; +#else template <char... Conv> using ParsedFormat = str_format_internal::ExtendedParsedFormat< - absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; -#endif // defined(__cpp_nontype_template_parameter_auto) + absl::str_format_internal::ToFormatConversionCharSet(Conv)...>; +#endif // defined(__cpp_nontype_template_parameter_auto) // StrFormat() // @@ -427,7 +427,7 @@ int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, // type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`. // // In particular, a successful call to `absl::SNPrintF()` writes at most `size` -// bytes of the formatted output to `output`, including a NUL-terminator, and +// bytes of the formatted output to `output`, including a NUL-terminator, and // returns the number of bytes that would have been written if truncation did // not occur. In the event of an error, a negative value is returned and `errno` // is set. @@ -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, absl::string_view part); -// -// where `dest` is the pointer passed to `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, absl::string_view part); +// +// where `dest` is the pointer passed to `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 { // `absl::FormatRawSink` interface), using a format string and zero or more // additional arguments. // -// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as -// destination objects. If a `std::string` is used the formatted string is -// appended to it. +// By default, `std::string`, `std::ostream`, and `absl::Cord` are supported as +// destination objects. If a `std::string` is used the formatted string is +// appended to it. // -// `absl::Format()` is a generic version of `absl::StrAppendFormat()`, for -// custom sinks. The format string, like format strings for `StrFormat()`, is -// checked at compile-time. +// `absl::Format()` is a generic version of `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,247 +566,247 @@ 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 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: -// -// absl::FormatConvertResult<...> AbslFormatConvert( -// const X& value, -// const absl::FormatConversionSpec& spec, -// 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 `absl::FormatConversionSpec` to specify the fields to pull from a -// user-defined type's format string -// * An `absl::FormatSink` to hold the converted string data during the -// conversion process. -// * An `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 absl::FormatConvertResult<absl::FormatConversionCharSet::kString | -// absl::FormatConversionCharSet::kIntegral> -// AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec, -// absl::FormatSink* s) { -// if (spec.conversion_char() == absl::FormatConversionChar::s) { -// s->Append(absl::StrCat("x=", p.x, " y=", p.y)); -// } else { -// s->Append(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; - - 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>( - 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 +//------------------------------------------------------------------------------ +// StrFormat Extensions +//------------------------------------------------------------------------------ +// +// AbslFormatConvert() +// +// The StrFormat library provides a customization API for formatting +// user-defined types using 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: +// +// absl::FormatConvertResult<...> AbslFormatConvert( +// const X& value, +// const absl::FormatConversionSpec& spec, +// 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 `absl::FormatConversionSpec` to specify the fields to pull from a +// user-defined type's format string +// * An `absl::FormatSink` to hold the converted string data during the +// conversion process. +// * An `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 absl::FormatConvertResult<absl::FormatConversionCharSet::kString | +// absl::FormatConversionCharSet::kIntegral> +// AbslFormatConvert(const Point& p, const absl::FormatConversionSpec& spec, +// absl::FormatSink* s) { +// if (spec.conversion_char() == absl::FormatConversionChar::s) { +// s->Append(absl::StrCat("x=", p.x, " y=", p.y)); +// } else { +// s->Append(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; + + 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>( + 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 absl #endif // ABSL_STRINGS_STR_FORMAT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_join.h b/contrib/restricted/abseil-cpp/absl/strings/str_join.h index 33534536cf..5f388b5000 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_join.h +++ b/contrib/restricted/abseil-cpp/absl/strings/str_join.h @@ -60,7 +60,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // ----------------------------------------------------------------------------- // Concept: Formatter @@ -287,7 +287,7 @@ std::string StrJoin(const std::tuple<T...>& value, return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_JOIN_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_replace.cc b/contrib/restricted/abseil-cpp/absl/strings/str_replace.cc index 2bd5fa9821..73c72a46a1 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_replace.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/str_replace.cc @@ -17,7 +17,7 @@ #include "absl/strings/str_cat.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace strings_internal { using FixedMapping = @@ -78,5 +78,5 @@ int StrReplaceAll(strings_internal::FixedMapping replacements, return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_replace.h b/contrib/restricted/abseil-cpp/absl/strings/str_replace.h index 273c707735..00dd1b85cf 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_replace.h +++ b/contrib/restricted/abseil-cpp/absl/strings/str_replace.h @@ -46,7 +46,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // StrReplaceAll() // @@ -213,7 +213,7 @@ int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) { return substitutions; } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_REPLACE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_split.cc b/contrib/restricted/abseil-cpp/absl/strings/str_split.cc index e08c26b6bb..e421049bc2 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_split.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/str_split.cc @@ -27,7 +27,7 @@ #include "absl/strings/ascii.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace { @@ -42,7 +42,7 @@ absl::string_view GenericFind(absl::string_view text, 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 // absl::string_view referring to the item at position 1 past pos. return absl::string_view(text.data() + pos + 1, 0); } @@ -127,7 +127,7 @@ absl::string_view ByLength::Find(absl::string_view text, size_t pos) const { pos = std::min(pos, text.size()); // truncate `pos` 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 absl::string_view(text.data() + text.size(), 0); @@ -135,5 +135,5 @@ absl::string_view ByLength::Find(absl::string_view text, return absl::string_view(substr.data() + length_, 0); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/str_split.h b/contrib/restricted/abseil-cpp/absl/strings/str_split.h index bfbca422a8..092edff75f 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/str_split.h +++ b/contrib/restricted/abseil-cpp/absl/strings/str_split.h @@ -44,13 +44,13 @@ #include <vector> #include "absl/base/internal/raw_logging.h" -#include "absl/base/macros.h" +#include "absl/base/macros.h" #include "absl/strings/internal/str_split_internal.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN //------------------------------------------------------------------------------ // Delimiters @@ -542,7 +542,7 @@ StrSplit(StringType&& text, Delimiter d, Predicate p) { std::move(text), DelimiterType(d), std::move(p)); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STR_SPLIT_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/string_view.cc b/contrib/restricted/abseil-cpp/absl/strings/string_view.cc index d596e08cde..2e62545317 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/string_view.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/string_view.cc @@ -24,7 +24,7 @@ #include "absl/strings/internal/memutil.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace { void WritePadding(std::ostream& o, size_t pad) { @@ -224,7 +224,7 @@ constexpr string_view::size_type string_view::npos; ABSL_STRING_VIEW_SELECTANY constexpr string_view::size_type string_view::kMaxSize; -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_USES_STD_STRING_VIEW diff --git a/contrib/restricted/abseil-cpp/absl/strings/string_view.h b/contrib/restricted/abseil-cpp/absl/strings/string_view.h index 65e74ccb1d..bc2b853a07 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/string_view.h +++ b/contrib/restricted/abseil-cpp/absl/strings/string_view.h @@ -28,29 +28,29 @@ #define ABSL_STRINGS_STRING_VIEW_H_ #include <algorithm> -#include <cassert> -#include <cstddef> -#include <cstring> -#include <iosfwd> -#include <iterator> -#include <limits> -#include <string> - +#include <cassert> +#include <cstddef> +#include <cstring> +#include <iosfwd> +#include <iterator> +#include <limits> +#include <string> + #include "absl/base/attributes.h" #include "absl/base/config.h" -#include "absl/base/internal/throw_delegate.h" -#include "absl/base/macros.h" -#include "absl/base/optimization.h" -#include "absl/base/port.h" +#include "absl/base/internal/throw_delegate.h" +#include "absl/base/macros.h" +#include "absl/base/optimization.h" +#include "absl/base/port.h" #ifdef ABSL_USES_STD_STRING_VIEW #include <string_view> // IWYU pragma: export namespace absl { -ABSL_NAMESPACE_BEGIN -using string_view = std::string_view; -ABSL_NAMESPACE_END +ABSL_NAMESPACE_BEGIN +using string_view = std::string_view; +ABSL_NAMESPACE_END } // namespace absl #else // ABSL_USES_STD_STRING_VIEW @@ -71,7 +71,7 @@ ABSL_NAMESPACE_END #endif namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // absl::string_view // @@ -120,22 +120,22 @@ ABSL_NAMESPACE_BEGIN // example, when splitting a string, `std::vector<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. -// -// 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 -// on NUL-terminated strings do not work on `string_view` objects. If you write +// 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 +// on NUL-terminated strings do not work on `string_view` objects. If you write // code that scans a `string_view`, you must check its length rather than test // for nul, for example. Note, however, that nuls may still be embedded within // a `string_view` explicitly. // // You may create a null `string_view` in two ways: // -// absl::string_view sv; +// absl::string_view sv; // absl::string_view sv(nullptr, 0); // // For the above, `sv.data() == nullptr`, `sv.length() == 0`, and @@ -197,7 +197,7 @@ class string_view { // code bloat. : string_view(str.data(), str.size(), SkipCheckLengthTag{}) {} - // Implicit constructor of a `string_view` from NUL-terminated `str`. When + // Implicit constructor of a `string_view` from NUL-terminated `str`. When // accepting possibly null strings, use `absl::NullSafeStringView(str)` // instead (see below). // The length check is skipped since it is unnecessary and causes code bloat. @@ -296,9 +296,9 @@ 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]; - } + constexpr const_reference operator[](size_type i) const { + return ABSL_HARDENING_ASSERT(i < size()), ptr_[i]; + } // string_view::at() // @@ -316,24 +316,24 @@ class string_view { // string_view::front() // // Returns the first element of a `string_view`. - constexpr const_reference front() const { - return ABSL_HARDENING_ASSERT(!empty()), ptr_[0]; - } + constexpr const_reference front() const { + 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]; - } + constexpr const_reference back() const { + return ABSL_HARDENING_ASSERT(!empty()), ptr_[size() - 1]; + } // string_view::data() // // Returns a pointer to the underlying character array (which is of course // 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. + // 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. 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 absl::ClippedSubstr if you need a truncating substr operation. + // Use 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( - "absl::string_view::substr"), - string_view()) - : string_view(ptr_ + pos, Min(n, length_ - pos)); + return ABSL_PREDICT_FALSE(pos > length_) + ? (base_internal::ThrowStdOutOfRange( + "absl::string_view::substr"), + string_view()) + : string_view(ptr_ + pos, Min(n, length_ - pos)); } // string_view::compare() @@ -412,11 +412,11 @@ class string_view { // than `x`, 0 if `*this` is equal to `x`, and a positive value if `*this` // is greater than `x`. constexpr int compare(string_view x) const noexcept { - return CompareImpl(length_, x.length_, - Min(length_, x.length_) == 0 - ? 0 - : ABSL_INTERNAL_STRING_VIEW_MEMCMP( - ptr_, x.ptr_, Min(length_, x.length_))); + return CompareImpl(length_, x.length_, + Min(length_, x.length_) == 0 + ? 0 + : ABSL_INTERNAL_STRING_VIEW_MEMCMP( + ptr_, x.ptr_, Min(length_, x.length_))); } // Overload of `string_view::compare()` for comparing a substring of the @@ -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) { @@ -629,15 +629,15 @@ class string_view { #endif } - static constexpr size_t Min(size_type length_a, size_type length_b) { - return length_a < length_b ? length_a : length_b; - } - + static constexpr size_t Min(size_type length_a, size_type length_b) { + return length_a < length_b ? length_a : length_b; + } + static constexpr int CompareImpl(size_type length_a, size_type length_b, int compare_result) { return compare_result == 0 ? static_cast<int>(length_a > length_b) - static_cast<int>(length_a < length_b) - : (compare_result < 0 ? -1 : 1); + : (compare_result < 0 ? -1 : 1); } const char* ptr_; @@ -676,7 +676,7 @@ constexpr bool operator>=(string_view x, string_view y) noexcept { // IO Insertion Operator std::ostream& operator<<(std::ostream& o, string_view piece); -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #undef ABSL_INTERNAL_STRING_VIEW_CXX14_CONSTEXPR @@ -685,7 +685,7 @@ ABSL_NAMESPACE_END #endif // ABSL_USES_STD_STRING_VIEW namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // ClippedSubstr() // @@ -702,11 +702,11 @@ inline string_view ClippedSubstr(string_view s, size_t pos, // Creates an `absl::string_view` from a pointer `p` even if it's null-valued. // This function should be used where an `absl::string_view` can be created from // a possibly-null pointer. -constexpr string_view NullSafeStringView(const char* p) { +constexpr string_view NullSafeStringView(const char* p) { return p ? string_view(p) : string_view(); } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STRING_VIEW_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/strip.h b/contrib/restricted/abseil-cpp/absl/strings/strip.h index 111872ca54..5dfa716942 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/strip.h +++ b/contrib/restricted/abseil-cpp/absl/strings/strip.h @@ -30,7 +30,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN // ConsumePrefix() // @@ -85,7 +85,7 @@ ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix( return str; } -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_STRIP_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/substitute.cc b/contrib/restricted/abseil-cpp/absl/strings/substitute.cc index 8980b198c2..bc625d4082 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/substitute.cc +++ b/contrib/restricted/abseil-cpp/absl/strings/substitute.cc @@ -23,7 +23,7 @@ #include "absl/strings/string_view.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace substitute_internal { void SubstituteAndAppendArray(std::string* output, absl::string_view format, @@ -36,7 +36,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, if (i + 1 >= format.size()) { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, - "Invalid absl::Substitute() format string: \"%s\".", + "Invalid absl::Substitute() format string: \"%s\".", absl::CEscape(format).c_str()); #endif return; @@ -46,8 +46,8 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, #ifndef NDEBUG ABSL_RAW_LOG( FATAL, - "Invalid absl::Substitute() format string: asked for \"$" - "%d\", but only %d args were given. Full format string was: " + "Invalid absl::Substitute() format string: asked for \"$" + "%d\", but only %d args were given. Full format string was: " "\"%s\".", index, static_cast<int>(num_args), absl::CEscape(format).c_str()); #endif @@ -61,7 +61,7 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, } else { #ifndef NDEBUG ABSL_RAW_LOG(FATAL, - "Invalid absl::Substitute() format string: \"%s\".", + "Invalid absl::Substitute() format string: \"%s\".", absl::CEscape(format).c_str()); #endif return; @@ -73,7 +73,7 @@ void SubstituteAndAppendArray(std::string* output, 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); @@ -168,5 +168,5 @@ Arg::Arg(Dec dec) { } } // namespace substitute_internal -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl diff --git a/contrib/restricted/abseil-cpp/absl/strings/substitute.h b/contrib/restricted/abseil-cpp/absl/strings/substitute.h index 151c56f543..c928c0979e 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/substitute.h +++ b/contrib/restricted/abseil-cpp/absl/strings/substitute.h @@ -50,7 +50,7 @@ // // Supported types: // * absl::string_view, std::string, 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>", @@ -86,7 +86,7 @@ #include "absl/strings/strip.h" namespace absl { -ABSL_NAMESPACE_BEGIN +ABSL_NAMESPACE_BEGIN namespace substitute_internal { // Arg @@ -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) @@ -120,9 +120,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_) {} @@ -192,12 +192,12 @@ void SubstituteAndAppendArray(std::string* output, absl::string_view format, #if defined(ABSL_BAD_CALL_IF) constexpr int CalculateOneBit(const char* format) { - // Returns: - // * 2^N for '$N' when N is in [0-9] - // * 0 for correct '$' escaping: '$$'. - // * -1 otherwise. - return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1) - : (1 << (*format - '0')); + // Returns: + // * 2^N for '$N' when N is in [0-9] + // * 0 for correct '$' escaping: '$$'. + // * -1 otherwise. + return (*format < '0' || *format > '9') ? (*format == '$' ? 0 : -1) + : (1 << (*format - '0')); } constexpr const char* SkipNumber(const char* format) { @@ -205,11 +205,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 @@ -715,7 +715,7 @@ std::string Substitute( "contains an unescaped $ character (use $$ instead)"); #endif // ABSL_BAD_CALL_IF -ABSL_NAMESPACE_END +ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_SUBSTITUTE_H_ diff --git a/contrib/restricted/abseil-cpp/absl/strings/ya.make b/contrib/restricted/abseil-cpp/absl/strings/ya.make index bc11193f12..52364d460e 100644 --- a/contrib/restricted/abseil-cpp/absl/strings/ya.make +++ b/contrib/restricted/abseil-cpp/absl/strings/ya.make @@ -8,16 +8,16 @@ LICENSE(Apache-2.0) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/restricted/abseil-cpp/absl/base - contrib/restricted/abseil-cpp/absl/base/internal/raw_logging + contrib/restricted/abseil-cpp/absl/base/internal/raw_logging contrib/restricted/abseil-cpp/absl/base/internal/spinlock_wait contrib/restricted/abseil-cpp/absl/base/internal/throw_delegate - contrib/restricted/abseil-cpp/absl/base/log_severity + contrib/restricted/abseil-cpp/absl/base/log_severity contrib/restricted/abseil-cpp/absl/numeric contrib/restricted/abseil-cpp/absl/strings/internal/absl_strings_internal -) - +) + ADDINCL( GLOBAL contrib/restricted/abseil-cpp ) @@ -26,14 +26,14 @@ NO_COMPILER_WARNINGS() NO_UTIL() -CFLAGS( - -DNOMINMAX -) - +CFLAGS( + -DNOMINMAX +) + SRCS( ascii.cc charconv.cc - escaping.cc + escaping.cc internal/charconv_bigint.cc internal/charconv_parse.cc internal/memutil.cc |