aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal
diff options
context:
space:
mode:
authorheretic <heretic@yandex-team.ru>2022-02-10 16:45:43 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:43 +0300
commit397cbe258b9e064f49c4ca575279f02f39fef76e (patch)
treea0b0eb3cca6a14e4e8ea715393637672fa651284 /contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal
parent43f5a35593ebc9f6bcea619bb170394ea7ae468e (diff)
downloadydb-397cbe258b9e064f49c4ca575279f02f39fef76e.tar.gz
Restoring authorship annotation for <heretic@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal')
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make68
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make12
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h2
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc2
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h4
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc16
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc166
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h766
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h278
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc1432
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h1130
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h228
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make12
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make68
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make68
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h2
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt40
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc472
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h310
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc32
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h58
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h42
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc62
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h296
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc2036
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h34
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h8
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc40
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h54
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make12
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h28
-rw-r--r--contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h128
32 files changed, 3953 insertions, 3953 deletions
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make
index 42b7b6cd5e..5b0a4c0695 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal/ya.make
@@ -1,42 +1,42 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
-WITHOUT_LICENSE_TEXTS()
-
-OWNER(
- somov
- g:cpp-contrib
-)
-
-LICENSE(Apache-2.0)
-
-PEERDIR(
- contrib/restricted/abseil-cpp-tstring/y_absl/base
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
- contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
- contrib/restricted/abseil-cpp-tstring/y_absl/numeric
- contrib/restricted/abseil-cpp-tstring/y_absl/strings
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ somov
+ g:cpp-contrib
+)
+
+LICENSE(Apache-2.0)
+
+PEERDIR(
+ contrib/restricted/abseil-cpp-tstring/y_absl/base
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
+ contrib/restricted/abseil-cpp-tstring/y_absl/numeric
+ contrib/restricted/abseil-cpp-tstring/y_absl/strings
contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal
-)
-
-ADDINCL(
- GLOBAL contrib/restricted/abseil-cpp-tstring
-)
-
-NO_COMPILER_WARNINGS()
-
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/abseil-cpp-tstring
+)
+
+NO_COMPILER_WARNINGS()
+
SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal)
-
-SRCS(
+
+SRCS(
cord_internal.cc
cord_rep_btree.cc
cord_rep_btree_navigator.cc
cord_rep_btree_reader.cc
cord_rep_consume.cc
cord_rep_ring.cc
-)
-
-END()
+)
+
+END()
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make
index 4e57fc75f6..f1c30b2590 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal/ya.make
@@ -4,17 +4,17 @@ LIBRARY()
WITHOUT_LICENSE_TEXTS()
-OWNER(
- somov
- g:cpp-contrib
-)
+OWNER(
+ somov
+ g:cpp-contrib
+)
LICENSE(Apache-2.0)
PEERDIR(
- contrib/restricted/abseil-cpp-tstring/y_absl/base
+ contrib/restricted/abseil-cpp-tstring/y_absl/base
contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
)
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h
index 25428e304c..873125a571 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/char_map.h
@@ -72,7 +72,7 @@ class Charmap {
CharMaskForWord(x, 2), CharMaskForWord(x, 3));
}
- // Containing all the chars in the C-string 's'.
+ // Containing all the chars in the C-string 's'.
// Note that this is expensively recursive because of the C++11 constexpr
// formulation. Use only in constexpr initializers.
static constexpr Charmap FromString(const char* s) {
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc
index 72a4fa188b..2b6742a64e 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.cc
@@ -208,7 +208,7 @@ int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end,
++dropped_digits;
}
if (begin < end && *std::prev(end) == '.') {
- // If the string ends in '.', either before or after dropping zeroes, then
+ // If the string ends in '.', either before or after dropping zeroes, then
// drop the decimal point and look for more digits to drop.
dropped_digits = 0;
--end;
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h
index a77aab14dd..75df41a2e1 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_bigint.h
@@ -66,7 +66,7 @@ class BigUnsigned {
static_cast<uint32_t>(v >> 32)} {}
// Constructs a BigUnsigned from the given string_view containing a decimal
- // value. If the input string is not a decimal integer, constructs a 0
+ // value. If the input string is not a decimal integer, constructs a 0
// instead.
explicit BigUnsigned(y_absl::string_view sv) : size_(0), words_{} {
// Check for valid input, returning a 0 otherwise. This is reasonable
@@ -210,7 +210,7 @@ class BigUnsigned {
return words_[index];
}
- // Returns this integer as a decimal string. This is not used in the decimal-
+ // Returns this integer as a decimal string. This is not used in the decimal-
// to-binary conversion; it is intended to aid in testing.
TString ToString() const;
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc
index f0f78eb68c..cf92a22d56 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/charconv_parse.cc
@@ -246,8 +246,8 @@ constexpr int DigitMagnitude<16>() {
// ConsumeDigits does not protect against overflow on *out; max_digits must
// be chosen with respect to type T to avoid the possibility of overflow.
template <int base, typename T>
-int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
- bool* dropped_nonzero_digit) {
+int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
+ bool* dropped_nonzero_digit) {
if (base == 10) {
assert(max_digits <= std::numeric_limits<T>::digits10);
} else if (base == 16) {
@@ -282,7 +282,7 @@ int ConsumeDigits(const char* begin, const char* end, int max_digits, T* out,
*dropped_nonzero_digit = true;
}
*out = accumulator;
- return static_cast<int>(begin - original_begin);
+ return static_cast<int>(begin - original_begin);
}
// Returns true if `v` is one of the chars allowed inside parentheses following
@@ -302,7 +302,7 @@ bool ParseInfinityOrNan(const char* begin, const char* end,
switch (*begin) {
case 'i':
case 'I': {
- // An infinity string consists of the characters "inf" or "infinity",
+ // An infinity string consists of the characters "inf" or "infinity",
// case insensitive.
if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) {
return false;
@@ -326,7 +326,7 @@ bool ParseInfinityOrNan(const char* begin, const char* end,
}
out->type = strings_internal::FloatType::kNan;
out->end = begin + 3;
- // NaN is allowed to be followed by a parenthesized string, consisting of
+ // NaN is allowed to be followed by a parenthesized string, consisting of
// only the characters [a-zA-Z0-9_]. Match that if it's present.
begin += 3;
if (begin < end && *begin == '(') {
@@ -372,7 +372,7 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
int exponent_adjustment = 0;
bool mantissa_is_inexact = false;
- int pre_decimal_digits = ConsumeDigits<base>(
+ int pre_decimal_digits = ConsumeDigits<base>(
begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact);
begin += pre_decimal_digits;
int digits_left;
@@ -398,14 +398,14 @@ strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end,
while (begin < end && *begin == '0') {
++begin;
}
- int zeros_skipped = static_cast<int>(begin - begin_zeros);
+ int zeros_skipped = static_cast<int>(begin - begin_zeros);
if (zeros_skipped >= DigitLimit<base>()) {
// refuse to parse pathological inputs
return result;
}
exponent_adjustment -= static_cast<int>(zeros_skipped);
}
- int post_decimal_digits = ConsumeDigits<base>(
+ int post_decimal_digits = ConsumeDigits<base>(
begin, end, digits_left, &mantissa, &mantissa_is_inexact);
begin += post_decimal_digits;
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc
index 6fc39985d8..d32e638883 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.cc
@@ -1,89 +1,89 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "y_absl/strings/internal/cord_internal.h"
-
-#include <atomic>
-#include <cassert>
-#include <memory>
-
-#include "y_absl/container/inlined_vector.h"
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "y_absl/strings/internal/cord_internal.h"
+
+#include <atomic>
+#include <cassert>
+#include <memory>
+
+#include "y_absl/container/inlined_vector.h"
#include "y_absl/strings/internal/cord_rep_btree.h"
-#include "y_absl/strings/internal/cord_rep_flat.h"
-#include "y_absl/strings/internal/cord_rep_ring.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace cord_internal {
-
+#include "y_absl/strings/internal/cord_rep_flat.h"
+#include "y_absl/strings/internal/cord_rep_ring.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
ABSL_CONST_INIT std::atomic<bool> cord_btree_enabled(kCordEnableBtreeDefault);
-ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
- kCordEnableRingBufferDefault);
-ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
- kCordShallowSubcordsDefault);
+ABSL_CONST_INIT std::atomic<bool> cord_ring_buffer_enabled(
+ kCordEnableRingBufferDefault);
+ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
+ kCordShallowSubcordsDefault);
ABSL_CONST_INIT std::atomic<bool> cord_btree_exhaustive_validation(false);
-
-void CordRep::Destroy(CordRep* rep) {
- assert(rep != nullptr);
-
- y_absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
- while (true) {
- assert(!rep->refcount.IsImmortal());
- if (rep->tag == CONCAT) {
- CordRepConcat* rep_concat = rep->concat();
- CordRep* right = rep_concat->right;
- if (!right->refcount.Decrement()) {
- pending.push_back(right);
- }
- CordRep* left = rep_concat->left;
- delete rep_concat;
- rep = nullptr;
- if (!left->refcount.Decrement()) {
- rep = left;
- continue;
- }
+
+void CordRep::Destroy(CordRep* rep) {
+ assert(rep != nullptr);
+
+ y_absl::InlinedVector<CordRep*, Constants::kInlinedVectorSize> pending;
+ while (true) {
+ assert(!rep->refcount.IsImmortal());
+ if (rep->tag == CONCAT) {
+ CordRepConcat* rep_concat = rep->concat();
+ CordRep* right = rep_concat->right;
+ if (!right->refcount.Decrement()) {
+ pending.push_back(right);
+ }
+ CordRep* left = rep_concat->left;
+ delete rep_concat;
+ rep = nullptr;
+ if (!left->refcount.Decrement()) {
+ rep = left;
+ continue;
+ }
} else if (rep->tag == BTREE) {
CordRepBtree::Destroy(rep->btree());
rep = nullptr;
- } else if (rep->tag == RING) {
- CordRepRing::Destroy(rep->ring());
- rep = nullptr;
- } else if (rep->tag == EXTERNAL) {
- CordRepExternal::Delete(rep);
- rep = nullptr;
- } else if (rep->tag == SUBSTRING) {
- CordRepSubstring* rep_substring = rep->substring();
- CordRep* child = rep_substring->child;
- delete rep_substring;
- rep = nullptr;
- if (!child->refcount.Decrement()) {
- rep = child;
- continue;
- }
- } else {
- CordRepFlat::Delete(rep);
- rep = nullptr;
- }
-
- if (!pending.empty()) {
- rep = pending.back();
- pending.pop_back();
- } else {
- break;
- }
- }
-}
-
-} // namespace cord_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
+ } else if (rep->tag == RING) {
+ CordRepRing::Destroy(rep->ring());
+ rep = nullptr;
+ } else if (rep->tag == EXTERNAL) {
+ CordRepExternal::Delete(rep);
+ rep = nullptr;
+ } else if (rep->tag == SUBSTRING) {
+ CordRepSubstring* rep_substring = rep->substring();
+ CordRep* child = rep_substring->child;
+ delete rep_substring;
+ rep = nullptr;
+ if (!child->refcount.Decrement()) {
+ rep = child;
+ continue;
+ }
+ } else {
+ CordRepFlat::Delete(rep);
+ rep = nullptr;
+ }
+
+ if (!pending.empty()) {
+ rep = pending.back();
+ pending.pop_back();
+ } else {
+ break;
+ }
+ }
+}
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h
index 82f5ac7b81..02b215f61f 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_internal.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Abseil Authors.
+// Copyright 2021 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,11 +21,11 @@
#include <cstdint>
#include <type_traits>
-#include "y_absl/base/config.h"
-#include "y_absl/base/internal/endian.h"
-#include "y_absl/base/internal/invoke.h"
-#include "y_absl/base/optimization.h"
-#include "y_absl/container/internal/compressed_tuple.h"
+#include "y_absl/base/config.h"
+#include "y_absl/base/internal/endian.h"
+#include "y_absl/base/internal/invoke.h"
+#include "y_absl/base/optimization.h"
+#include "y_absl/container/internal/compressed_tuple.h"
#include "y_absl/meta/type_traits.h"
#include "y_absl/strings/string_view.h"
@@ -33,19 +33,19 @@ namespace y_absl {
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
-class CordzInfo;
-
-// Default feature enable states for cord ring buffers
-enum CordFeatureDefaults {
+class CordzInfo;
+
+// Default feature enable states for cord ring buffers
+enum CordFeatureDefaults {
kCordEnableBtreeDefault = true,
- kCordEnableRingBufferDefault = false,
- kCordShallowSubcordsDefault = false
-};
-
+ kCordEnableRingBufferDefault = false,
+ kCordShallowSubcordsDefault = false
+};
+
extern std::atomic<bool> cord_btree_enabled;
-extern std::atomic<bool> cord_ring_buffer_enabled;
-extern std::atomic<bool> shallow_subcords_enabled;
-
+extern std::atomic<bool> cord_ring_buffer_enabled;
+extern std::atomic<bool> shallow_subcords_enabled;
+
// `cord_btree_exhaustive_validation` can be set to force exhaustive validation
// in debug assertions, and code that calls `IsValid()` explicitly. By default,
// assertions should be relatively cheap and AssertValid() can easily lead to
@@ -56,48 +56,48 @@ inline void enable_cord_btree(bool enable) {
cord_btree_enabled.store(enable, std::memory_order_relaxed);
}
-inline void enable_cord_ring_buffer(bool enable) {
- cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
-}
-
-inline void enable_shallow_subcords(bool enable) {
- shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
-}
-
-enum Constants {
- // The inlined size to use with y_absl::InlinedVector.
- //
- // Note: The InlinedVectors in this file (and in cord.h) do not need to use
- // the same value for their inlined size. The fact that they do is historical.
- // It may be desirable for each to use a different inlined size optimized for
- // that InlinedVector's usage.
- //
- // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
- // the inlined vector size (47 exists for backward compatibility).
- kInlinedVectorSize = 47,
-
- // Prefer copying blocks of at most this size, otherwise reference count.
- kMaxBytesToCopy = 511
-};
-
+inline void enable_cord_ring_buffer(bool enable) {
+ cord_ring_buffer_enabled.store(enable, std::memory_order_relaxed);
+}
+
+inline void enable_shallow_subcords(bool enable) {
+ shallow_subcords_enabled.store(enable, std::memory_order_relaxed);
+}
+
+enum Constants {
+ // The inlined size to use with y_absl::InlinedVector.
+ //
+ // Note: The InlinedVectors in this file (and in cord.h) do not need to use
+ // the same value for their inlined size. The fact that they do is historical.
+ // It may be desirable for each to use a different inlined size optimized for
+ // that InlinedVector's usage.
+ //
+ // TODO(jgm): Benchmark to see if there's a more optimal value than 47 for
+ // the inlined vector size (47 exists for backward compatibility).
+ kInlinedVectorSize = 47,
+
+ // Prefer copying blocks of at most this size, otherwise reference count.
+ kMaxBytesToCopy = 511
+};
+
// Compact class for tracking the reference count and state flags for CordRep
// instances. Data is stored in an atomic int32_t for compactness and speed.
class RefcountAndFlags {
public:
constexpr RefcountAndFlags() : count_{kRefIncrement} {}
- struct Immortal {};
+ struct Immortal {};
explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {}
struct WithCrc {};
explicit constexpr RefcountAndFlags(WithCrc)
: count_(kCrcFlag | kRefIncrement) {}
- // Increments the reference count. Imposes no memory ordering.
- inline void Increment() {
- count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
- }
+ // Increments the reference count. Imposes no memory ordering.
+ inline void Increment() {
+ count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+ }
// Asserts that the current refcount is greater than 0. If the refcount is
- // greater than 1, decrements the reference count.
+ // greater than 1, decrements the reference count.
//
// Returns false if there are no references outstanding; true otherwise.
// Inserts barriers to ensure that state written before this method returns
@@ -106,24 +106,24 @@ class RefcountAndFlags {
inline bool Decrement() {
int32_t refcount = count_.load(std::memory_order_acquire) & kRefcountMask;
assert(refcount > 0 || refcount & kImmortalFlag);
- return refcount != kRefIncrement &&
+ return refcount != kRefIncrement &&
(count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) &
kRefcountMask) != kRefIncrement;
}
// Same as Decrement but expect that refcount is greater than 1.
inline bool DecrementExpectHighRefcount() {
- int32_t refcount =
+ int32_t refcount =
count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) &
kRefcountMask;
assert(refcount > 0 || refcount & kImmortalFlag);
- return refcount != kRefIncrement;
+ return refcount != kRefIncrement;
}
// Returns the current reference count using acquire semantics.
- inline int32_t Get() const {
+ inline int32_t Get() const {
return count_.load(std::memory_order_acquire) >> kNumFlags;
- }
+ }
// Returns true if the referenced object carries a CRC value.
bool HasCrc() const {
@@ -151,22 +151,22 @@ class RefcountAndFlags {
//
// When this returns true, there are no other references, and data sinks
// may safely adopt the children of the CordRep.
- inline bool IsOne() {
+ inline bool IsOne() {
return (count_.load(std::memory_order_acquire) & kRefcountMask) ==
kRefIncrement;
- }
+ }
- bool IsImmortal() const {
+ bool IsImmortal() const {
return (count_.load(std::memory_order_relaxed) & kImmortalFlag) != 0;
- }
-
+ }
+
private:
// We reserve the bottom bits for flags.
// kImmortalBit indicates that this entity should never be collected; it is
// used for the StringConstant constructor to avoid collecting immutable
// constant cords.
// kReservedFlag is reserved for future use.
- enum {
+ enum {
kNumFlags = 2,
kImmortalFlag = 0x1,
@@ -178,8 +178,8 @@ class RefcountAndFlags {
// purposes of equality. (A refcount of 0 or 1 does not count as 0 or 1
// if the immortal bit is set.)
kRefcountMask = ~kCrcFlag,
- };
-
+ };
+
std::atomic<int32_t> count_;
};
@@ -189,30 +189,30 @@ class RefcountAndFlags {
// functions in the base class.
struct CordRepConcat;
-struct CordRepExternal;
-struct CordRepFlat;
+struct CordRepExternal;
+struct CordRepFlat;
struct CordRepSubstring;
-class CordRepRing;
+class CordRepRing;
class CordRepBtree;
-// Various representations that we allow
-enum CordRepKind {
- CONCAT = 0,
+// Various representations that we allow
+enum CordRepKind {
+ CONCAT = 0,
SUBSTRING = 1,
BTREE = 2,
- RING = 3,
+ RING = 3,
EXTERNAL = 4,
-
- // We have different tags for different sized flat arrays,
+
+ // We have different tags for different sized flat arrays,
// starting with FLAT, and limited to MAX_FLAT_TAG. The 225 value is based on
- // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
- // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
- // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
- // allocation size. (32 bytes as of now).
+ // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
+ // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
+ // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
+ // allocation size. (32 bytes as of now).
FLAT = 5,
MAX_FLAT_TAG = 225
-};
-
+};
+
// There are various locations where we want to check if some rep is a 'plain'
// data edge, i.e. an external or flat rep. By having FLAT == EXTERNAL + 1, we
// can perform this check in a single branch as 'tag >= EXTERNAL'
@@ -225,13 +225,13 @@ static_assert(EXTERNAL == RING + 1, "BTREE and EXTERNAL not consecutive");
static_assert(FLAT == EXTERNAL + 1, "EXTERNAL and FLAT not consecutive");
struct CordRep {
- CordRep() = default;
+ CordRep() = default;
constexpr CordRep(RefcountAndFlags::Immortal immortal, size_t l)
- : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
-
+ : length(l), refcount(immortal), tag(EXTERNAL), storage{} {}
+
// The following three fields have to be less than 32 bytes since
// that is the smallest supported flat node size.
- size_t length;
+ size_t length;
RefcountAndFlags refcount;
// If tag < FLAT, it represents CordRepKind and indicates the type of node.
// Otherwise, the node type is CordRepFlat and the tag is the encoded size.
@@ -255,32 +255,32 @@ struct CordRep {
constexpr bool IsFlat() const { return tag >= FLAT; }
constexpr bool IsBtree() const { return tag == BTREE; }
- inline CordRepRing* ring();
- inline const CordRepRing* ring() const;
+ inline CordRepRing* ring();
+ inline const CordRepRing* ring() const;
inline CordRepConcat* concat();
inline const CordRepConcat* concat() const;
inline CordRepSubstring* substring();
inline const CordRepSubstring* substring() const;
inline CordRepExternal* external();
inline const CordRepExternal* external() const;
- inline CordRepFlat* flat();
- inline const CordRepFlat* flat() const;
+ inline CordRepFlat* flat();
+ inline const CordRepFlat* flat() const;
inline CordRepBtree* btree();
inline const CordRepBtree* btree() const;
-
- // --------------------------------------------------------------------
- // Memory management
-
- // Destroys the provided `rep`.
- static void Destroy(CordRep* rep);
-
- // Increments the reference count of `rep`.
- // Requires `rep` to be a non-null pointer value.
- static inline CordRep* Ref(CordRep* rep);
-
- // Decrements the reference count of `rep`. Destroys rep if count reaches
- // zero. Requires `rep` to be a non-null pointer value.
- static inline void Unref(CordRep* rep);
+
+ // --------------------------------------------------------------------
+ // Memory management
+
+ // Destroys the provided `rep`.
+ static void Destroy(CordRep* rep);
+
+ // Increments the reference count of `rep`.
+ // Requires `rep` to be a non-null pointer value.
+ static inline CordRep* Ref(CordRep* rep);
+
+ // Decrements the reference count of `rep`. Destroys rep if count reaches
+ // zero. Requires `rep` to be a non-null pointer value.
+ static inline void Unref(CordRep* rep);
};
struct CordRepConcat : public CordRep {
@@ -296,151 +296,151 @@ struct CordRepSubstring : public CordRep {
CordRep* child;
};
-// Type for function pointer that will invoke the releaser function and also
-// delete the `CordRepExternalImpl` corresponding to the passed in
-// `CordRepExternal`.
-using ExternalReleaserInvoker = void (*)(CordRepExternal*);
+// Type for function pointer that will invoke the releaser function and also
+// delete the `CordRepExternalImpl` corresponding to the passed in
+// `CordRepExternal`.
+using ExternalReleaserInvoker = void (*)(CordRepExternal*);
// External CordReps are allocated together with a type erased releaser. The
// releaser is stored in the memory directly following the CordRepExternal.
-struct CordRepExternal : public CordRep {
- CordRepExternal() = default;
- explicit constexpr CordRepExternal(y_absl::string_view str)
+struct CordRepExternal : public CordRep {
+ CordRepExternal() = default;
+ explicit constexpr CordRepExternal(y_absl::string_view str)
: CordRep(RefcountAndFlags::Immortal{}, str.size()),
- base(str.data()),
- releaser_invoker(nullptr) {}
-
+ base(str.data()),
+ releaser_invoker(nullptr) {}
+
const char* base;
// Pointer to function that knows how to call and destroy the releaser.
ExternalReleaserInvoker releaser_invoker;
-
- // Deletes (releases) the external rep.
+
+ // Deletes (releases) the external rep.
// Requires rep != nullptr and rep->IsExternal()
- static void Delete(CordRep* rep);
+ static void Delete(CordRep* rep);
};
-struct Rank1 {};
-struct Rank0 : Rank1 {};
-
-template <typename Releaser, typename = ::y_absl::base_internal::invoke_result_t<
- Releaser, y_absl::string_view>>
-void InvokeReleaser(Rank0, Releaser&& releaser, y_absl::string_view data) {
- ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
-}
-
-template <typename Releaser,
- typename = ::y_absl::base_internal::invoke_result_t<Releaser>>
-void InvokeReleaser(Rank1, Releaser&& releaser, y_absl::string_view) {
- ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser));
-}
-
-// We use CompressedTuple so that we can benefit from EBCO.
-template <typename Releaser>
-struct CordRepExternalImpl
- : public CordRepExternal,
- public ::y_absl::container_internal::CompressedTuple<Releaser> {
- // The extra int arg is so that we can avoid interfering with copy/move
- // constructors while still benefitting from perfect forwarding.
- template <typename T>
- CordRepExternalImpl(T&& releaser, int)
- : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
- this->releaser_invoker = &Release;
- }
-
- ~CordRepExternalImpl() {
- InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
- y_absl::string_view(base, length));
- }
-
- static void Release(CordRepExternal* rep) {
- delete static_cast<CordRepExternalImpl*>(rep);
- }
-};
-
-inline void CordRepExternal::Delete(CordRep* rep) {
+struct Rank1 {};
+struct Rank0 : Rank1 {};
+
+template <typename Releaser, typename = ::y_absl::base_internal::invoke_result_t<
+ Releaser, y_absl::string_view>>
+void InvokeReleaser(Rank0, Releaser&& releaser, y_absl::string_view data) {
+ ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
+}
+
+template <typename Releaser,
+ typename = ::y_absl::base_internal::invoke_result_t<Releaser>>
+void InvokeReleaser(Rank1, Releaser&& releaser, y_absl::string_view) {
+ ::y_absl::base_internal::invoke(std::forward<Releaser>(releaser));
+}
+
+// We use CompressedTuple so that we can benefit from EBCO.
+template <typename Releaser>
+struct CordRepExternalImpl
+ : public CordRepExternal,
+ public ::y_absl::container_internal::CompressedTuple<Releaser> {
+ // The extra int arg is so that we can avoid interfering with copy/move
+ // constructors while still benefitting from perfect forwarding.
+ template <typename T>
+ CordRepExternalImpl(T&& releaser, int)
+ : CordRepExternalImpl::CompressedTuple(std::forward<T>(releaser)) {
+ this->releaser_invoker = &Release;
+ }
+
+ ~CordRepExternalImpl() {
+ InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
+ y_absl::string_view(base, length));
+ }
+
+ static void Release(CordRepExternal* rep) {
+ delete static_cast<CordRepExternalImpl*>(rep);
+ }
+};
+
+inline void CordRepExternal::Delete(CordRep* rep) {
assert(rep != nullptr && rep->IsExternal());
- auto* rep_external = static_cast<CordRepExternal*>(rep);
- assert(rep_external->releaser_invoker != nullptr);
- rep_external->releaser_invoker(rep_external);
-}
-
-template <typename Str>
-struct ConstInitExternalStorage {
- ABSL_CONST_INIT static CordRepExternal value;
-};
-
-template <typename Str>
-CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
-
-enum {
- kMaxInline = 15,
-};
-
-constexpr char GetOrNull(y_absl::string_view data, size_t pos) {
- return pos < data.size() ? data[pos] : '\0';
-}
-
-// We store cordz_info as 64 bit pointer value in big endian format. This
-// guarantees that the least significant byte of cordz_info matches the last
-// byte of the inline data representation in as_chars_, which holds the inlined
-// size or the 'is_tree' bit.
-using cordz_info_t = int64_t;
-
-// Assert that the `cordz_info` pointer value perfectly overlaps the last half
-// of `as_chars_` and can hold a pointer value.
-static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
-static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
-
-// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
-// endian value where the last byte in the host's representation holds 'value`,
-// with all other bytes being 0.
-static constexpr cordz_info_t BigEndianByte(unsigned char value) {
-#if defined(ABSL_IS_BIG_ENDIAN)
- return value;
-#else
- return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
-#endif
-}
-
-class InlineData {
- public:
+ auto* rep_external = static_cast<CordRepExternal*>(rep);
+ assert(rep_external->releaser_invoker != nullptr);
+ rep_external->releaser_invoker(rep_external);
+}
+
+template <typename Str>
+struct ConstInitExternalStorage {
+ ABSL_CONST_INIT static CordRepExternal value;
+};
+
+template <typename Str>
+CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
+
+enum {
+ kMaxInline = 15,
+};
+
+constexpr char GetOrNull(y_absl::string_view data, size_t pos) {
+ return pos < data.size() ? data[pos] : '\0';
+}
+
+// We store cordz_info as 64 bit pointer value in big endian format. This
+// guarantees that the least significant byte of cordz_info matches the last
+// byte of the inline data representation in as_chars_, which holds the inlined
+// size or the 'is_tree' bit.
+using cordz_info_t = int64_t;
+
+// Assert that the `cordz_info` pointer value perfectly overlaps the last half
+// of `as_chars_` and can hold a pointer value.
+static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
+static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
+
+// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
+// endian value where the last byte in the host's representation holds 'value`,
+// with all other bytes being 0.
+static constexpr cordz_info_t BigEndianByte(unsigned char value) {
+#if defined(ABSL_IS_BIG_ENDIAN)
+ return value;
+#else
+ return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
+#endif
+}
+
+class InlineData {
+ public:
// DefaultInitType forces the use of the default initialization constructor.
enum DefaultInitType { kDefaultInit };
- // kNullCordzInfo holds the big endian representation of intptr_t(1)
- // This is the 'null' / initial value of 'cordz_info'. The null value
- // is specifically big endian 1 as with 64-bit pointers, the last
- // byte of cordz_info overlaps with the last byte holding the tag.
- static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
-
- constexpr InlineData() : as_chars_{0} {}
+ // kNullCordzInfo holds the big endian representation of intptr_t(1)
+ // This is the 'null' / initial value of 'cordz_info'. The null value
+ // is specifically big endian 1 as with 64-bit pointers, the last
+ // byte of cordz_info overlaps with the last byte holding the tag.
+ static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
+
+ constexpr InlineData() : as_chars_{0} {}
explicit InlineData(DefaultInitType) {}
- explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
- explicit constexpr InlineData(y_absl::string_view chars)
- : as_chars_{
- GetOrNull(chars, 0), GetOrNull(chars, 1),
- GetOrNull(chars, 2), GetOrNull(chars, 3),
- GetOrNull(chars, 4), GetOrNull(chars, 5),
- GetOrNull(chars, 6), GetOrNull(chars, 7),
- GetOrNull(chars, 8), GetOrNull(chars, 9),
- GetOrNull(chars, 10), GetOrNull(chars, 11),
- GetOrNull(chars, 12), GetOrNull(chars, 13),
- GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
-
- // Returns true if the current instance is empty.
- // The 'empty value' is an inlined data value of zero length.
- bool is_empty() const { return tag() == 0; }
-
- // Returns true if the current instance holds a tree value.
- bool is_tree() const { return (tag() & 1) != 0; }
-
- // Returns true if the current instance holds a cordz_info value.
- // Requires the current instance to hold a tree value.
- bool is_profiled() const {
- assert(is_tree());
- return as_tree_.cordz_info != kNullCordzInfo;
- }
-
+ explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
+ explicit constexpr InlineData(y_absl::string_view chars)
+ : as_chars_{
+ GetOrNull(chars, 0), GetOrNull(chars, 1),
+ GetOrNull(chars, 2), GetOrNull(chars, 3),
+ GetOrNull(chars, 4), GetOrNull(chars, 5),
+ GetOrNull(chars, 6), GetOrNull(chars, 7),
+ GetOrNull(chars, 8), GetOrNull(chars, 9),
+ GetOrNull(chars, 10), GetOrNull(chars, 11),
+ GetOrNull(chars, 12), GetOrNull(chars, 13),
+ GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
+
+ // Returns true if the current instance is empty.
+ // The 'empty value' is an inlined data value of zero length.
+ bool is_empty() const { return tag() == 0; }
+
+ // Returns true if the current instance holds a tree value.
+ bool is_tree() const { return (tag() & 1) != 0; }
+
+ // Returns true if the current instance holds a cordz_info value.
+ // Requires the current instance to hold a tree value.
+ bool is_profiled() const {
+ assert(is_tree());
+ return as_tree_.cordz_info != kNullCordzInfo;
+ }
+
// Returns true if either of the provided instances hold a cordz_info value.
// This method is more efficient than the equivalent `data1.is_profiled() ||
// data2.is_profiled()`. Requires both arguments to hold a tree.
@@ -451,170 +451,170 @@ class InlineData {
kNullCordzInfo;
}
- // Returns the cordz_info sampling instance for this instance, or nullptr
- // if the current instance is not sampled and does not have CordzInfo data.
- // Requires the current instance to hold a tree value.
- CordzInfo* cordz_info() const {
- assert(is_tree());
- intptr_t info =
- static_cast<intptr_t>(y_absl::big_endian::ToHost64(as_tree_.cordz_info));
- assert(info & 1);
- return reinterpret_cast<CordzInfo*>(info - 1);
- }
-
- // Sets the current cordz_info sampling instance for this instance, or nullptr
- // if the current instance is not sampled and does not have CordzInfo data.
- // Requires the current instance to hold a tree value.
- void set_cordz_info(CordzInfo* cordz_info) {
- assert(is_tree());
- intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
- as_tree_.cordz_info = y_absl::big_endian::FromHost64(info);
- }
-
- // Resets the current cordz_info to null / empty.
- void clear_cordz_info() {
- assert(is_tree());
- as_tree_.cordz_info = kNullCordzInfo;
- }
-
- // Returns a read only pointer to the character data inside this instance.
- // Requires the current instance to hold inline data.
- const char* as_chars() const {
- assert(!is_tree());
- return as_chars_;
- }
-
- // Returns a mutable pointer to the character data inside this instance.
- // Should be used for 'write only' operations setting an inlined value.
- // Applications can set the value of inlined data either before or after
- // setting the inlined size, i.e., both of the below are valid:
- //
- // // Set inlined data and inline size
- // memcpy(data_.as_chars(), data, size);
- // data_.set_inline_size(size);
- //
- // // Set inlined size and inline data
- // data_.set_inline_size(size);
- // memcpy(data_.as_chars(), data, size);
- //
- // It's an error to read from the returned pointer without a preceding write
- // if the current instance does not hold inline data, i.e.: is_tree() == true.
- char* as_chars() { return as_chars_; }
-
- // Returns the tree value of this value.
- // Requires the current instance to hold a tree value.
- CordRep* as_tree() const {
- assert(is_tree());
- return as_tree_.rep;
- }
-
- // Initialize this instance to holding the tree value `rep`,
- // initializing the cordz_info to null, i.e.: 'not profiled'.
- void make_tree(CordRep* rep) {
- as_tree_.rep = rep;
- as_tree_.cordz_info = kNullCordzInfo;
- }
-
- // Set the tree value of this instance to 'rep`.
- // Requires the current instance to already hold a tree value.
- // Does not affect the value of cordz_info.
- void set_tree(CordRep* rep) {
- assert(is_tree());
- as_tree_.rep = rep;
- }
-
- // Returns the size of the inlined character data inside this instance.
- // Requires the current instance to hold inline data.
- size_t inline_size() const {
- assert(!is_tree());
- return tag() >> 1;
- }
-
- // Sets the size of the inlined character data inside this instance.
- // Requires `size` to be <= kMaxInline.
- // See the documentation on 'as_chars()' for more information and examples.
- void set_inline_size(size_t size) {
- ABSL_ASSERT(size <= kMaxInline);
- tag() = static_cast<char>(size << 1);
- }
-
- private:
- // See cordz_info_t for forced alignment and size of `cordz_info` details.
- struct AsTree {
- explicit constexpr AsTree(y_absl::cord_internal::CordRep* tree)
- : rep(tree), cordz_info(kNullCordzInfo) {}
- // This union uses up extra space so that whether rep is 32 or 64 bits,
- // cordz_info will still start at the eighth byte, and the last
- // byte of cordz_info will still be the last byte of InlineData.
- union {
- y_absl::cord_internal::CordRep* rep;
- cordz_info_t unused_aligner;
- };
- cordz_info_t cordz_info;
- };
-
- char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
- char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
-
- // If the data has length <= kMaxInline, we store it in `as_chars_`, and
- // store the size in the last char of `as_chars_` shifted left + 1.
- // Else we store it in a tree and store a pointer to that tree in
- // `as_tree_.rep` and store a tag in `tagged_size`.
+ // Returns the cordz_info sampling instance for this instance, or nullptr
+ // if the current instance is not sampled and does not have CordzInfo data.
+ // Requires the current instance to hold a tree value.
+ CordzInfo* cordz_info() const {
+ assert(is_tree());
+ intptr_t info =
+ static_cast<intptr_t>(y_absl::big_endian::ToHost64(as_tree_.cordz_info));
+ assert(info & 1);
+ return reinterpret_cast<CordzInfo*>(info - 1);
+ }
+
+ // Sets the current cordz_info sampling instance for this instance, or nullptr
+ // if the current instance is not sampled and does not have CordzInfo data.
+ // Requires the current instance to hold a tree value.
+ void set_cordz_info(CordzInfo* cordz_info) {
+ assert(is_tree());
+ intptr_t info = reinterpret_cast<intptr_t>(cordz_info) | 1;
+ as_tree_.cordz_info = y_absl::big_endian::FromHost64(info);
+ }
+
+ // Resets the current cordz_info to null / empty.
+ void clear_cordz_info() {
+ assert(is_tree());
+ as_tree_.cordz_info = kNullCordzInfo;
+ }
+
+ // Returns a read only pointer to the character data inside this instance.
+ // Requires the current instance to hold inline data.
+ const char* as_chars() const {
+ assert(!is_tree());
+ return as_chars_;
+ }
+
+ // Returns a mutable pointer to the character data inside this instance.
+ // Should be used for 'write only' operations setting an inlined value.
+ // Applications can set the value of inlined data either before or after
+ // setting the inlined size, i.e., both of the below are valid:
+ //
+ // // Set inlined data and inline size
+ // memcpy(data_.as_chars(), data, size);
+ // data_.set_inline_size(size);
+ //
+ // // Set inlined size and inline data
+ // data_.set_inline_size(size);
+ // memcpy(data_.as_chars(), data, size);
+ //
+ // It's an error to read from the returned pointer without a preceding write
+ // if the current instance does not hold inline data, i.e.: is_tree() == true.
+ char* as_chars() { return as_chars_; }
+
+ // Returns the tree value of this value.
+ // Requires the current instance to hold a tree value.
+ CordRep* as_tree() const {
+ assert(is_tree());
+ return as_tree_.rep;
+ }
+
+ // Initialize this instance to holding the tree value `rep`,
+ // initializing the cordz_info to null, i.e.: 'not profiled'.
+ void make_tree(CordRep* rep) {
+ as_tree_.rep = rep;
+ as_tree_.cordz_info = kNullCordzInfo;
+ }
+
+ // Set the tree value of this instance to 'rep`.
+ // Requires the current instance to already hold a tree value.
+ // Does not affect the value of cordz_info.
+ void set_tree(CordRep* rep) {
+ assert(is_tree());
+ as_tree_.rep = rep;
+ }
+
+ // Returns the size of the inlined character data inside this instance.
+ // Requires the current instance to hold inline data.
+ size_t inline_size() const {
+ assert(!is_tree());
+ return tag() >> 1;
+ }
+
+ // Sets the size of the inlined character data inside this instance.
+ // Requires `size` to be <= kMaxInline.
+ // See the documentation on 'as_chars()' for more information and examples.
+ void set_inline_size(size_t size) {
+ ABSL_ASSERT(size <= kMaxInline);
+ tag() = static_cast<char>(size << 1);
+ }
+
+ private:
+ // See cordz_info_t for forced alignment and size of `cordz_info` details.
+ struct AsTree {
+ explicit constexpr AsTree(y_absl::cord_internal::CordRep* tree)
+ : rep(tree), cordz_info(kNullCordzInfo) {}
+ // This union uses up extra space so that whether rep is 32 or 64 bits,
+ // cordz_info will still start at the eighth byte, and the last
+ // byte of cordz_info will still be the last byte of InlineData.
+ union {
+ y_absl::cord_internal::CordRep* rep;
+ cordz_info_t unused_aligner;
+ };
+ cordz_info_t cordz_info;
+ };
+
+ char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
+ char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
+
+ // If the data has length <= kMaxInline, we store it in `as_chars_`, and
+ // store the size in the last char of `as_chars_` shifted left + 1.
+ // Else we store it in a tree and store a pointer to that tree in
+ // `as_tree_.rep` and store a tag in `tagged_size`.
union {
- char as_chars_[kMaxInline + 1];
- AsTree as_tree_;
- };
-};
-
-static_assert(sizeof(InlineData) == kMaxInline + 1, "");
-
-inline CordRepConcat* CordRep::concat() {
+ char as_chars_[kMaxInline + 1];
+ AsTree as_tree_;
+ };
+};
+
+static_assert(sizeof(InlineData) == kMaxInline + 1, "");
+
+inline CordRepConcat* CordRep::concat() {
assert(IsConcat());
- return static_cast<CordRepConcat*>(this);
-}
-
-inline const CordRepConcat* CordRep::concat() const {
+ return static_cast<CordRepConcat*>(this);
+}
+
+inline const CordRepConcat* CordRep::concat() const {
assert(IsConcat());
- return static_cast<const CordRepConcat*>(this);
-}
-
-inline CordRepSubstring* CordRep::substring() {
+ return static_cast<const CordRepConcat*>(this);
+}
+
+inline CordRepSubstring* CordRep::substring() {
assert(IsSubstring());
- return static_cast<CordRepSubstring*>(this);
-}
-
-inline const CordRepSubstring* CordRep::substring() const {
+ return static_cast<CordRepSubstring*>(this);
+}
+
+inline const CordRepSubstring* CordRep::substring() const {
assert(IsSubstring());
- return static_cast<const CordRepSubstring*>(this);
-}
-
-inline CordRepExternal* CordRep::external() {
+ return static_cast<const CordRepSubstring*>(this);
+}
+
+inline CordRepExternal* CordRep::external() {
assert(IsExternal());
- return static_cast<CordRepExternal*>(this);
-}
-
-inline const CordRepExternal* CordRep::external() const {
+ return static_cast<CordRepExternal*>(this);
+}
+
+inline const CordRepExternal* CordRep::external() const {
assert(IsExternal());
- return static_cast<const CordRepExternal*>(this);
-}
-
-inline CordRep* CordRep::Ref(CordRep* rep) {
- assert(rep != nullptr);
- rep->refcount.Increment();
- return rep;
-}
-
-inline void CordRep::Unref(CordRep* rep) {
- assert(rep != nullptr);
- // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
- // typically outweigh the cost of an extra branch checking for ref == 1.
- if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
- Destroy(rep);
- }
-}
-
+ return static_cast<const CordRepExternal*>(this);
+}
+
+inline CordRep* CordRep::Ref(CordRep* rep) {
+ assert(rep != nullptr);
+ rep->refcount.Increment();
+ return rep;
+}
+
+inline void CordRep::Unref(CordRep* rep) {
+ assert(rep != nullptr);
+ // Expect refcount to be 0. Avoiding the cost of an atomic decrement should
+ // typically outweigh the cost of an extra branch checking for ref == 1.
+ if (ABSL_PREDICT_FALSE(!rep->refcount.DecrementExpectHighRefcount())) {
+ Destroy(rep);
+ }
+}
+
} // namespace cord_internal
-
+
ABSL_NAMESPACE_END
} // namespace y_absl
#endif // ABSL_STRINGS_INTERNAL_CORD_INTERNAL_H_
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h
index 976613031c..5557022553 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_flat.h
@@ -1,146 +1,146 @@
-// Copyright 2020 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
-#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-
-#include "y_absl/strings/internal/cord_internal.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace cord_internal {
-
-// Note: all constants below are never ODR used and internal to cord, we define
-// these as static constexpr to avoid 'in struct' definition and usage clutter.
-
-// Largest and smallest flat node lengths we are willing to allocate
-// Flat allocation size is stored in tag, which currently can encode sizes up
-// to 4K, encoded as multiple of either 8 or 32 bytes.
-// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
-// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
-// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
-// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
-// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
-static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
-static constexpr size_t kMinFlatSize = 32;
-static constexpr size_t kMaxFlatSize = 4096;
-static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
-static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
-
-constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+#include "y_absl/strings/internal/cord_internal.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// Note: all constants below are never ODR used and internal to cord, we define
+// these as static constexpr to avoid 'in struct' definition and usage clutter.
+
+// Largest and smallest flat node lengths we are willing to allocate
+// Flat allocation size is stored in tag, which currently can encode sizes up
+// to 4K, encoded as multiple of either 8 or 32 bytes.
+// If we allow for larger sizes, we need to change this to 8/64, 16/128, etc.
+// kMinFlatSize is bounded by tag needing to be at least FLAT * 8 bytes, and
+// ideally a 'nice' size aligning with allocation and cacheline sizes like 32.
+// kMaxFlatSize is bounded by the size resulting in a computed tag no greater
+// than MAX_FLAT_TAG. MAX_FLAT_TAG provides for additional 'high' tag values.
+static constexpr size_t kFlatOverhead = offsetof(CordRep, storage);
+static constexpr size_t kMinFlatSize = 32;
+static constexpr size_t kMaxFlatSize = 4096;
+static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
+static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
+
+constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
return static_cast<uint8_t>((size <= 1024) ? size / 8 + 1
: 129 + size / 32 - 1024 / 32);
-}
-
+}
+
static_assert(kMinFlatSize / 8 + 1 >= FLAT, "");
-static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
-
-// Helper functions for rounded div, and rounding to exact sizes.
-constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
-constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
-
-// Returns the size to the nearest equal or larger value that can be
-// expressed exactly as a tag value.
-inline size_t RoundUpForTag(size_t size) {
- return RoundUp(size, (size <= 1024) ? 8 : 32);
-}
-
-// Converts the allocated size to a tag, rounding down if the size
-// does not exactly match a 'tag expressible' size value. The result is
-// undefined if the size exceeds the maximum size that can be encoded in
-// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
-inline uint8_t AllocatedSizeToTag(size_t size) {
- const uint8_t tag = AllocatedSizeToTagUnchecked(size);
- assert(tag <= MAX_FLAT_TAG);
- return tag;
-}
-
-// Converts the provided tag to the corresponding allocated size
-constexpr size_t TagToAllocatedSize(uint8_t tag) {
+static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
+
+// Helper functions for rounded div, and rounding to exact sizes.
+constexpr size_t DivUp(size_t n, size_t m) { return (n + m - 1) / m; }
+constexpr size_t RoundUp(size_t n, size_t m) { return DivUp(n, m) * m; }
+
+// Returns the size to the nearest equal or larger value that can be
+// expressed exactly as a tag value.
+inline size_t RoundUpForTag(size_t size) {
+ return RoundUp(size, (size <= 1024) ? 8 : 32);
+}
+
+// Converts the allocated size to a tag, rounding down if the size
+// does not exactly match a 'tag expressible' size value. The result is
+// undefined if the size exceeds the maximum size that can be encoded in
+// a tag, i.e., if size is larger than TagToAllocatedSize(<max tag>).
+inline uint8_t AllocatedSizeToTag(size_t size) {
+ const uint8_t tag = AllocatedSizeToTagUnchecked(size);
+ assert(tag <= MAX_FLAT_TAG);
+ return tag;
+}
+
+// Converts the provided tag to the corresponding allocated size
+constexpr size_t TagToAllocatedSize(uint8_t tag) {
return (tag <= 129) ? ((tag - 1) * 8) : (1024 + (tag - 129) * 32);
-}
-
-// Converts the provided tag to the corresponding available data length
-constexpr size_t TagToLength(uint8_t tag) {
- return TagToAllocatedSize(tag) - kFlatOverhead;
-}
-
-// Enforce that kMaxFlatSize maps to a well-known exact tag value.
+}
+
+// Converts the provided tag to the corresponding available data length
+constexpr size_t TagToLength(uint8_t tag) {
+ return TagToAllocatedSize(tag) - kFlatOverhead;
+}
+
+// Enforce that kMaxFlatSize maps to a well-known exact tag value.
static_assert(TagToAllocatedSize(225) == kMaxFlatSize, "Bad tag logic");
-
-struct CordRepFlat : public CordRep {
- // Creates a new flat node.
- static CordRepFlat* New(size_t len) {
- if (len <= kMinFlatLength) {
- len = kMinFlatLength;
- } else if (len > kMaxFlatLength) {
- len = kMaxFlatLength;
- }
-
- // Round size up so it matches a size we can exactly express in a tag.
- const size_t size = RoundUpForTag(len + kFlatOverhead);
- void* const raw_rep = ::operator new(size);
- CordRepFlat* rep = new (raw_rep) CordRepFlat();
- rep->tag = AllocatedSizeToTag(size);
- return rep;
- }
-
- // Deletes a CordRepFlat instance created previously through a call to New().
- // Flat CordReps are allocated and constructed with raw ::operator new and
- // placement new, and must be destructed and deallocated accordingly.
- static void Delete(CordRep*rep) {
- assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
-
-#if defined(__cpp_sized_deallocation)
- size_t size = TagToAllocatedSize(rep->tag);
- rep->~CordRep();
- ::operator delete(rep, size);
-#else
- rep->~CordRep();
- ::operator delete(rep);
-#endif
- }
-
- // Returns a pointer to the data inside this flat rep.
+
+struct CordRepFlat : public CordRep {
+ // Creates a new flat node.
+ static CordRepFlat* New(size_t len) {
+ if (len <= kMinFlatLength) {
+ len = kMinFlatLength;
+ } else if (len > kMaxFlatLength) {
+ len = kMaxFlatLength;
+ }
+
+ // Round size up so it matches a size we can exactly express in a tag.
+ const size_t size = RoundUpForTag(len + kFlatOverhead);
+ void* const raw_rep = ::operator new(size);
+ CordRepFlat* rep = new (raw_rep) CordRepFlat();
+ rep->tag = AllocatedSizeToTag(size);
+ return rep;
+ }
+
+ // Deletes a CordRepFlat instance created previously through a call to New().
+ // Flat CordReps are allocated and constructed with raw ::operator new and
+ // placement new, and must be destructed and deallocated accordingly.
+ static void Delete(CordRep*rep) {
+ assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
+
+#if defined(__cpp_sized_deallocation)
+ size_t size = TagToAllocatedSize(rep->tag);
+ rep->~CordRep();
+ ::operator delete(rep, size);
+#else
+ rep->~CordRep();
+ ::operator delete(rep);
+#endif
+ }
+
+ // Returns a pointer to the data inside this flat rep.
char* Data() { return reinterpret_cast<char*>(storage); }
const char* Data() const { return reinterpret_cast<const char*>(storage); }
-
- // Returns the maximum capacity (payload size) of this instance.
- size_t Capacity() const { return TagToLength(tag); }
-
- // Returns the allocated size (payload + overhead) of this instance.
- size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
-};
-
-// Now that CordRepFlat is defined, we can define CordRep's helper casts:
-inline CordRepFlat* CordRep::flat() {
- assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
- return reinterpret_cast<CordRepFlat*>(this);
-}
-
-inline const CordRepFlat* CordRep::flat() const {
- assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
- return reinterpret_cast<const CordRepFlat*>(this);
-}
-
-} // namespace cord_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
-
-#endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
+
+ // Returns the maximum capacity (payload size) of this instance.
+ size_t Capacity() const { return TagToLength(tag); }
+
+ // Returns the allocated size (payload + overhead) of this instance.
+ size_t AllocatedSize() const { return TagToAllocatedSize(tag); }
+};
+
+// Now that CordRepFlat is defined, we can define CordRep's helper casts:
+inline CordRepFlat* CordRep::flat() {
+ assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+ return reinterpret_cast<CordRepFlat*>(this);
+}
+
+inline const CordRepFlat* CordRep::flat() const {
+ assert(tag >= FLAT && tag <= MAX_FLAT_TAG);
+ return reinterpret_cast<const CordRepFlat*>(this);
+}
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
+
+#endif // ABSL_STRINGS_INTERNAL_CORD_REP_FLAT_H_
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc
index 06c7e75bd8..97dff05363 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.cc
@@ -1,771 +1,771 @@
-// Copyright 2020 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-#include "y_absl/strings/internal/cord_rep_ring.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <iostream>
-#include <limits>
-#include <memory>
-#include <util/generic/string.h>
-
-#include "y_absl/base/internal/raw_logging.h"
-#include "y_absl/base/internal/throw_delegate.h"
-#include "y_absl/base/macros.h"
-#include "y_absl/container/inlined_vector.h"
-#include "y_absl/strings/internal/cord_internal.h"
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "y_absl/strings/internal/cord_rep_ring.h"
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iostream>
+#include <limits>
+#include <memory>
+#include <util/generic/string.h>
+
+#include "y_absl/base/internal/raw_logging.h"
+#include "y_absl/base/internal/throw_delegate.h"
+#include "y_absl/base/macros.h"
+#include "y_absl/container/inlined_vector.h"
+#include "y_absl/strings/internal/cord_internal.h"
#include "y_absl/strings/internal/cord_rep_consume.h"
-#include "y_absl/strings/internal/cord_rep_flat.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace cord_internal {
-
-namespace {
-
-using index_type = CordRepRing::index_type;
-
-enum class Direction { kForward, kReversed };
-
-inline bool IsFlatOrExternal(CordRep* rep) {
+#include "y_absl/strings/internal/cord_rep_flat.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+namespace {
+
+using index_type = CordRepRing::index_type;
+
+enum class Direction { kForward, kReversed };
+
+inline bool IsFlatOrExternal(CordRep* rep) {
return rep->IsFlat() || rep->IsExternal();
-}
-
-// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise.
-inline void CheckCapacity(size_t n, size_t extra) {
- if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) {
- base_internal::ThrowStdLengthError("Maximum capacity exceeded");
- }
-}
-
-// Creates a flat from the provided string data, allocating up to `extra`
-// capacity in the returned flat depending on kMaxFlatLength limitations.
-// Requires `len` to be less or equal to `kMaxFlatLength`
-CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) { // NOLINT
- assert(n <= kMaxFlatLength);
- auto* rep = CordRepFlat::New(n + extra);
- rep->length = n;
- memcpy(rep->Data(), s, n);
- return rep;
-}
-
-// Unrefs the entries in `[head, tail)`.
-// Requires all entries to be a FLAT or EXTERNAL node.
-void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) {
- rep->ForEach(head, tail, [rep](index_type ix) {
- CordRep* child = rep->entry_child(ix);
- if (!child->refcount.Decrement()) {
- if (child->tag >= FLAT) {
- CordRepFlat::Delete(child->flat());
- } else {
- CordRepExternal::Delete(child->external());
- }
- }
- });
-}
-
-} // namespace
-
-std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) {
- // Note: 'pos' values are defined as size_t (for overflow reasons), but that
- // prints really awkward for small prepended values such as -5. ssize_t is not
- // portable (POSIX), so we use ptrdiff_t instead to cast to signed values.
- s << " CordRepRing(" << &rep << ", length = " << rep.length
- << ", head = " << rep.head_ << ", tail = " << rep.tail_
- << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get()
- << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n";
- CordRepRing::index_type head = rep.head();
- do {
- CordRep* child = rep.entry_child(head);
- s << " entry[" << head << "] length = " << rep.entry_length(head)
- << ", child " << child << ", clen = " << child->length
- << ", tag = " << static_cast<int>(child->tag)
- << ", rc = " << child->refcount.Get()
- << ", offset = " << rep.entry_data_offset(head)
- << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head))
- << "\n";
- head = rep.advance(head);
- } while (head != rep.tail());
- return s << "}\n";
-}
-
-void CordRepRing::AddDataOffset(index_type index, size_t n) {
- entry_data_offset()[index] += static_cast<offset_type>(n);
-}
-
-void CordRepRing::SubLength(index_type index, size_t n) {
- entry_end_pos()[index] -= n;
-}
-
-class CordRepRing::Filler {
- public:
- Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {}
-
- index_type head() const { return head_; }
- index_type pos() const { return pos_; }
-
- void Add(CordRep* child, size_t offset, pos_type end_pos) {
- rep_->entry_end_pos()[pos_] = end_pos;
- rep_->entry_child()[pos_] = child;
- rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset);
- pos_ = rep_->advance(pos_);
- }
-
- private:
- CordRepRing* rep_;
- index_type head_;
- index_type pos_;
-};
-
-constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11
-
-bool CordRepRing::IsValid(std::ostream& output) const {
- if (capacity_ == 0) {
- output << "capacity == 0";
- return false;
- }
-
- if (head_ >= capacity_ || tail_ >= capacity_) {
- output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity "
- << capacity_;
- return false;
- }
-
- const index_type back = retreat(tail_);
- size_t pos_length = Distance(begin_pos_, entry_end_pos(back));
- if (pos_length != length) {
- output << "length " << length << " does not match positional length "
- << pos_length << " from begin_pos " << begin_pos_ << " and entry["
- << back << "].end_pos " << entry_end_pos(back);
- return false;
- }
-
- index_type head = head_;
- pos_type begin_pos = begin_pos_;
- do {
- pos_type end_pos = entry_end_pos(head);
- size_t entry_length = Distance(begin_pos, end_pos);
- if (entry_length == 0) {
- output << "entry[" << head << "] has an invalid length " << entry_length
- << " from begin_pos " << begin_pos << " and end_pos " << end_pos;
- return false;
- }
-
- CordRep* child = entry_child(head);
- if (child == nullptr) {
- output << "entry[" << head << "].child == nullptr";
- return false;
- }
- if (child->tag < FLAT && child->tag != EXTERNAL) {
- output << "entry[" << head << "].child has an invalid tag "
- << static_cast<int>(child->tag);
- return false;
- }
-
- size_t offset = entry_data_offset(head);
- if (offset >= child->length || entry_length > child->length - offset) {
- output << "entry[" << head << "] has offset " << offset
- << " and entry length " << entry_length
+}
+
+// Verifies that n + extra <= kMaxCapacity: throws std::length_error otherwise.
+inline void CheckCapacity(size_t n, size_t extra) {
+ if (ABSL_PREDICT_FALSE(extra > CordRepRing::kMaxCapacity - n)) {
+ base_internal::ThrowStdLengthError("Maximum capacity exceeded");
+ }
+}
+
+// Creates a flat from the provided string data, allocating up to `extra`
+// capacity in the returned flat depending on kMaxFlatLength limitations.
+// Requires `len` to be less or equal to `kMaxFlatLength`
+CordRepFlat* CreateFlat(const char* s, size_t n, size_t extra = 0) { // NOLINT
+ assert(n <= kMaxFlatLength);
+ auto* rep = CordRepFlat::New(n + extra);
+ rep->length = n;
+ memcpy(rep->Data(), s, n);
+ return rep;
+}
+
+// Unrefs the entries in `[head, tail)`.
+// Requires all entries to be a FLAT or EXTERNAL node.
+void UnrefEntries(const CordRepRing* rep, index_type head, index_type tail) {
+ rep->ForEach(head, tail, [rep](index_type ix) {
+ CordRep* child = rep->entry_child(ix);
+ if (!child->refcount.Decrement()) {
+ if (child->tag >= FLAT) {
+ CordRepFlat::Delete(child->flat());
+ } else {
+ CordRepExternal::Delete(child->external());
+ }
+ }
+ });
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep) {
+ // Note: 'pos' values are defined as size_t (for overflow reasons), but that
+ // prints really awkward for small prepended values such as -5. ssize_t is not
+ // portable (POSIX), so we use ptrdiff_t instead to cast to signed values.
+ s << " CordRepRing(" << &rep << ", length = " << rep.length
+ << ", head = " << rep.head_ << ", tail = " << rep.tail_
+ << ", cap = " << rep.capacity_ << ", rc = " << rep.refcount.Get()
+ << ", begin_pos_ = " << static_cast<ptrdiff_t>(rep.begin_pos_) << ") {\n";
+ CordRepRing::index_type head = rep.head();
+ do {
+ CordRep* child = rep.entry_child(head);
+ s << " entry[" << head << "] length = " << rep.entry_length(head)
+ << ", child " << child << ", clen = " << child->length
+ << ", tag = " << static_cast<int>(child->tag)
+ << ", rc = " << child->refcount.Get()
+ << ", offset = " << rep.entry_data_offset(head)
+ << ", end_pos = " << static_cast<ptrdiff_t>(rep.entry_end_pos(head))
+ << "\n";
+ head = rep.advance(head);
+ } while (head != rep.tail());
+ return s << "}\n";
+}
+
+void CordRepRing::AddDataOffset(index_type index, size_t n) {
+ entry_data_offset()[index] += static_cast<offset_type>(n);
+}
+
+void CordRepRing::SubLength(index_type index, size_t n) {
+ entry_end_pos()[index] -= n;
+}
+
+class CordRepRing::Filler {
+ public:
+ Filler(CordRepRing* rep, index_type pos) : rep_(rep), head_(pos), pos_(pos) {}
+
+ index_type head() const { return head_; }
+ index_type pos() const { return pos_; }
+
+ void Add(CordRep* child, size_t offset, pos_type end_pos) {
+ rep_->entry_end_pos()[pos_] = end_pos;
+ rep_->entry_child()[pos_] = child;
+ rep_->entry_data_offset()[pos_] = static_cast<offset_type>(offset);
+ pos_ = rep_->advance(pos_);
+ }
+
+ private:
+ CordRepRing* rep_;
+ index_type head_;
+ index_type pos_;
+};
+
+constexpr size_t CordRepRing::kMaxCapacity; // NOLINT: needed for c++11
+
+bool CordRepRing::IsValid(std::ostream& output) const {
+ if (capacity_ == 0) {
+ output << "capacity == 0";
+ return false;
+ }
+
+ if (head_ >= capacity_ || tail_ >= capacity_) {
+ output << "head " << head_ << " and/or tail " << tail_ << "exceed capacity "
+ << capacity_;
+ return false;
+ }
+
+ const index_type back = retreat(tail_);
+ size_t pos_length = Distance(begin_pos_, entry_end_pos(back));
+ if (pos_length != length) {
+ output << "length " << length << " does not match positional length "
+ << pos_length << " from begin_pos " << begin_pos_ << " and entry["
+ << back << "].end_pos " << entry_end_pos(back);
+ return false;
+ }
+
+ index_type head = head_;
+ pos_type begin_pos = begin_pos_;
+ do {
+ pos_type end_pos = entry_end_pos(head);
+ size_t entry_length = Distance(begin_pos, end_pos);
+ if (entry_length == 0) {
+ output << "entry[" << head << "] has an invalid length " << entry_length
+ << " from begin_pos " << begin_pos << " and end_pos " << end_pos;
+ return false;
+ }
+
+ CordRep* child = entry_child(head);
+ if (child == nullptr) {
+ output << "entry[" << head << "].child == nullptr";
+ return false;
+ }
+ if (child->tag < FLAT && child->tag != EXTERNAL) {
+ output << "entry[" << head << "].child has an invalid tag "
+ << static_cast<int>(child->tag);
+ return false;
+ }
+
+ size_t offset = entry_data_offset(head);
+ if (offset >= child->length || entry_length > child->length - offset) {
+ output << "entry[" << head << "] has offset " << offset
+ << " and entry length " << entry_length
<< " which are outside of the child's length of " << child->length;
- return false;
- }
-
- begin_pos = end_pos;
- head = advance(head);
- } while (head != tail_);
-
- return true;
-}
-
-#ifdef EXTRA_CORD_RING_VALIDATION
-CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file,
- int line) {
- if (!rep->IsValid(std::cerr)) {
- std::cerr << "\nERROR: CordRepRing corrupted";
- if (line) std::cerr << " at line " << line;
- if (file) std::cerr << " in file " << file;
- std::cerr << "\nContent = " << *rep;
- abort();
- }
- return rep;
-}
-#endif // EXTRA_CORD_RING_VALIDATION
-
-CordRepRing* CordRepRing::New(size_t capacity, size_t extra) {
- CheckCapacity(capacity, extra);
-
- size_t size = AllocSize(capacity += extra);
- void* mem = ::operator new(size);
- auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity));
- rep->tag = RING;
- rep->capacity_ = static_cast<index_type>(capacity);
- rep->begin_pos_ = 0;
- return rep;
-}
-
-void CordRepRing::SetCapacityForTesting(size_t capacity) {
- // Adjust for the changed layout
- assert(capacity <= capacity_);
- assert(head() == 0 || head() < tail());
- memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(),
- Layout::Partial(capacity_).Pointer<1>(data_) + head(),
- entries() * sizeof(Layout::ElementType<1>));
- memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(),
- Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(),
- entries() * sizeof(Layout::ElementType<2>));
- capacity_ = static_cast<index_type>(capacity);
-}
-
-void CordRepRing::Delete(CordRepRing* rep) {
+ return false;
+ }
+
+ begin_pos = end_pos;
+ head = advance(head);
+ } while (head != tail_);
+
+ return true;
+}
+
+#ifdef EXTRA_CORD_RING_VALIDATION
+CordRepRing* CordRepRing::Validate(CordRepRing* rep, const char* file,
+ int line) {
+ if (!rep->IsValid(std::cerr)) {
+ std::cerr << "\nERROR: CordRepRing corrupted";
+ if (line) std::cerr << " at line " << line;
+ if (file) std::cerr << " in file " << file;
+ std::cerr << "\nContent = " << *rep;
+ abort();
+ }
+ return rep;
+}
+#endif // EXTRA_CORD_RING_VALIDATION
+
+CordRepRing* CordRepRing::New(size_t capacity, size_t extra) {
+ CheckCapacity(capacity, extra);
+
+ size_t size = AllocSize(capacity += extra);
+ void* mem = ::operator new(size);
+ auto* rep = new (mem) CordRepRing(static_cast<index_type>(capacity));
+ rep->tag = RING;
+ rep->capacity_ = static_cast<index_type>(capacity);
+ rep->begin_pos_ = 0;
+ return rep;
+}
+
+void CordRepRing::SetCapacityForTesting(size_t capacity) {
+ // Adjust for the changed layout
+ assert(capacity <= capacity_);
+ assert(head() == 0 || head() < tail());
+ memmove(Layout::Partial(capacity).Pointer<1>(data_) + head(),
+ Layout::Partial(capacity_).Pointer<1>(data_) + head(),
+ entries() * sizeof(Layout::ElementType<1>));
+ memmove(Layout::Partial(capacity, capacity).Pointer<2>(data_) + head(),
+ Layout::Partial(capacity_, capacity_).Pointer<2>(data_) + head(),
+ entries() * sizeof(Layout::ElementType<2>));
+ capacity_ = static_cast<index_type>(capacity);
+}
+
+void CordRepRing::Delete(CordRepRing* rep) {
assert(rep != nullptr && rep->IsRing());
-#if defined(__cpp_sized_deallocation)
- size_t size = AllocSize(rep->capacity_);
- rep->~CordRepRing();
- ::operator delete(rep, size);
-#else
- rep->~CordRepRing();
- ::operator delete(rep);
-#endif
-}
-
-void CordRepRing::Destroy(CordRepRing* rep) {
- UnrefEntries(rep, rep->head(), rep->tail());
- Delete(rep);
-}
-
-template <bool ref>
-void CordRepRing::Fill(const CordRepRing* src, index_type head,
- index_type tail) {
- this->length = src->length;
- head_ = 0;
- tail_ = advance(0, src->entries(head, tail));
- begin_pos_ = src->begin_pos_;
-
- // TODO(mvels): there may be opportunities here for large buffers.
- auto* dst_pos = entry_end_pos();
- auto* dst_child = entry_child();
- auto* dst_offset = entry_data_offset();
- src->ForEach(head, tail, [&](index_type index) {
- *dst_pos++ = src->entry_end_pos(index);
- CordRep* child = src->entry_child(index);
- *dst_child++ = ref ? CordRep::Ref(child) : child;
- *dst_offset++ = src->entry_data_offset(index);
- });
-}
-
-CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head,
- index_type tail, size_t extra) {
- CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra);
- newrep->Fill<true>(rep, head, tail);
- CordRep::Unref(rep);
- return newrep;
-}
-
-CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
- // Get current number of entries, and check for max capacity.
- size_t entries = rep->entries();
-
+#if defined(__cpp_sized_deallocation)
+ size_t size = AllocSize(rep->capacity_);
+ rep->~CordRepRing();
+ ::operator delete(rep, size);
+#else
+ rep->~CordRepRing();
+ ::operator delete(rep);
+#endif
+}
+
+void CordRepRing::Destroy(CordRepRing* rep) {
+ UnrefEntries(rep, rep->head(), rep->tail());
+ Delete(rep);
+}
+
+template <bool ref>
+void CordRepRing::Fill(const CordRepRing* src, index_type head,
+ index_type tail) {
+ this->length = src->length;
+ head_ = 0;
+ tail_ = advance(0, src->entries(head, tail));
+ begin_pos_ = src->begin_pos_;
+
+ // TODO(mvels): there may be opportunities here for large buffers.
+ auto* dst_pos = entry_end_pos();
+ auto* dst_child = entry_child();
+ auto* dst_offset = entry_data_offset();
+ src->ForEach(head, tail, [&](index_type index) {
+ *dst_pos++ = src->entry_end_pos(index);
+ CordRep* child = src->entry_child(index);
+ *dst_child++ = ref ? CordRep::Ref(child) : child;
+ *dst_offset++ = src->entry_data_offset(index);
+ });
+}
+
+CordRepRing* CordRepRing::Copy(CordRepRing* rep, index_type head,
+ index_type tail, size_t extra) {
+ CordRepRing* newrep = CordRepRing::New(rep->entries(head, tail), extra);
+ newrep->Fill<true>(rep, head, tail);
+ CordRep::Unref(rep);
+ return newrep;
+}
+
+CordRepRing* CordRepRing::Mutable(CordRepRing* rep, size_t extra) {
+ // Get current number of entries, and check for max capacity.
+ size_t entries = rep->entries();
+
if (!rep->refcount.IsMutable()) {
return Copy(rep, rep->head(), rep->tail(), extra);
- } else if (entries + extra > rep->capacity()) {
+ } else if (entries + extra > rep->capacity()) {
const size_t min_grow = rep->capacity() + rep->capacity() / 2;
const size_t min_extra = (std::max)(extra, min_grow - entries);
- CordRepRing* newrep = CordRepRing::New(entries, min_extra);
- newrep->Fill<false>(rep, rep->head(), rep->tail());
- CordRepRing::Delete(rep);
- return newrep;
- } else {
- return rep;
- }
-}
-
-Span<char> CordRepRing::GetAppendBuffer(size_t size) {
+ CordRepRing* newrep = CordRepRing::New(entries, min_extra);
+ newrep->Fill<false>(rep, rep->head(), rep->tail());
+ CordRepRing::Delete(rep);
+ return newrep;
+ } else {
+ return rep;
+ }
+}
+
+Span<char> CordRepRing::GetAppendBuffer(size_t size) {
assert(refcount.IsMutable());
- index_type back = retreat(tail_);
- CordRep* child = entry_child(back);
+ index_type back = retreat(tail_);
+ CordRep* child = entry_child(back);
if (child->tag >= FLAT && child->refcount.IsMutable()) {
- size_t capacity = child->flat()->Capacity();
- pos_type end_pos = entry_end_pos(back);
- size_t data_offset = entry_data_offset(back);
- size_t entry_length = Distance(entry_begin_pos(back), end_pos);
- size_t used = data_offset + entry_length;
- if (size_t n = (std::min)(capacity - used, size)) {
- child->length = data_offset + entry_length + n;
- entry_end_pos()[back] = end_pos + n;
- this->length += n;
- return {child->flat()->Data() + used, n};
- }
- }
- return {nullptr, 0};
-}
-
-Span<char> CordRepRing::GetPrependBuffer(size_t size) {
+ size_t capacity = child->flat()->Capacity();
+ pos_type end_pos = entry_end_pos(back);
+ size_t data_offset = entry_data_offset(back);
+ size_t entry_length = Distance(entry_begin_pos(back), end_pos);
+ size_t used = data_offset + entry_length;
+ if (size_t n = (std::min)(capacity - used, size)) {
+ child->length = data_offset + entry_length + n;
+ entry_end_pos()[back] = end_pos + n;
+ this->length += n;
+ return {child->flat()->Data() + used, n};
+ }
+ }
+ return {nullptr, 0};
+}
+
+Span<char> CordRepRing::GetPrependBuffer(size_t size) {
assert(refcount.IsMutable());
- CordRep* child = entry_child(head_);
- size_t data_offset = entry_data_offset(head_);
+ CordRep* child = entry_child(head_);
+ size_t data_offset = entry_data_offset(head_);
if (data_offset && child->refcount.IsMutable() && child->tag >= FLAT) {
- size_t n = (std::min)(data_offset, size);
- this->length += n;
- begin_pos_ -= n;
- data_offset -= n;
- entry_data_offset()[head_] = static_cast<offset_type>(data_offset);
- return {child->flat()->Data() + data_offset, n};
- }
- return {nullptr, 0};
-}
-
-CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset,
+ size_t n = (std::min)(data_offset, size);
+ this->length += n;
+ begin_pos_ -= n;
+ data_offset -= n;
+ entry_data_offset()[head_] = static_cast<offset_type>(data_offset);
+ return {child->flat()->Data() + data_offset, n};
+ }
+ return {nullptr, 0};
+}
+
+CordRepRing* CordRepRing::CreateFromLeaf(CordRep* child, size_t offset,
size_t len, size_t extra) {
- CordRepRing* rep = CordRepRing::New(1, extra);
- rep->head_ = 0;
- rep->tail_ = rep->advance(0);
+ CordRepRing* rep = CordRepRing::New(1, extra);
+ rep->head_ = 0;
+ rep->tail_ = rep->advance(0);
rep->length = len;
rep->entry_end_pos()[0] = len;
- rep->entry_child()[0] = child;
- rep->entry_data_offset()[0] = static_cast<offset_type>(offset);
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) {
- CordRepRing* rep = nullptr;
+ rep->entry_child()[0] = child;
+ rep->entry_data_offset()[0] = static_cast<offset_type>(offset);
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::CreateSlow(CordRep* child, size_t extra) {
+ CordRepRing* rep = nullptr;
Consume(child, [&](CordRep* child_arg, size_t offset, size_t len) {
if (IsFlatOrExternal(child_arg)) {
rep = rep ? AppendLeaf(rep, child_arg, offset, len)
: CreateFromLeaf(child_arg, offset, len, extra);
- } else if (rep) {
+ } else if (rep) {
rep = AddRing<AddMode::kAppend>(rep, child_arg->ring(), offset, len);
} else if (offset == 0 && child_arg->length == len) {
rep = Mutable(child_arg->ring(), extra);
- } else {
+ } else {
rep = SubRing(child_arg->ring(), offset, len, extra);
- }
- });
- return Validate(rep, nullptr, __LINE__);
-}
-
-CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) {
- size_t length = child->length;
- if (IsFlatOrExternal(child)) {
- return CreateFromLeaf(child, 0, length, extra);
- }
+ }
+ });
+ return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Create(CordRep* child, size_t extra) {
+ size_t length = child->length;
+ if (IsFlatOrExternal(child)) {
+ return CreateFromLeaf(child, 0, length, extra);
+ }
if (child->IsRing()) {
- return Mutable(child->ring(), extra);
- }
- return CreateSlow(child, extra);
-}
-
-template <CordRepRing::AddMode mode>
-CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring,
+ return Mutable(child->ring(), extra);
+ }
+ return CreateSlow(child, extra);
+}
+
+template <CordRepRing::AddMode mode>
+CordRepRing* CordRepRing::AddRing(CordRepRing* rep, CordRepRing* ring,
size_t offset, size_t len) {
- assert(offset < ring->length);
- constexpr bool append = mode == AddMode::kAppend;
- Position head = ring->Find(offset);
+ assert(offset < ring->length);
+ constexpr bool append = mode == AddMode::kAppend;
+ Position head = ring->Find(offset);
Position tail = ring->FindTail(head.index, offset + len);
- const index_type entries = ring->entries(head.index, tail.index);
-
- rep = Mutable(rep, entries);
-
- // The delta for making ring[head].end_pos into 'len - offset'
- const pos_type delta_length =
+ const index_type entries = ring->entries(head.index, tail.index);
+
+ rep = Mutable(rep, entries);
+
+ // The delta for making ring[head].end_pos into 'len - offset'
+ const pos_type delta_length =
(append ? rep->begin_pos_ + rep->length : rep->begin_pos_ - len) -
- ring->entry_begin_pos(head.index) - head.offset;
-
- // Start filling at `tail`, or `entries` before `head`
- Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries));
-
- if (ring->refcount.IsOne()) {
- // Copy entries from source stealing the ref and adjusting the end position.
- // Commit the filler as this is no-op.
- ring->ForEach(head.index, tail.index, [&](index_type ix) {
- filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix),
- ring->entry_end_pos(ix) + delta_length);
- });
-
- // Unref entries we did not copy over, and delete source.
- if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index);
- if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_);
- CordRepRing::Delete(ring);
- } else {
- ring->ForEach(head.index, tail.index, [&](index_type ix) {
- CordRep* child = ring->entry_child(ix);
- filler.Add(child, ring->entry_data_offset(ix),
- ring->entry_end_pos(ix) + delta_length);
- CordRep::Ref(child);
- });
- CordRepRing::Unref(ring);
- }
-
- if (head.offset) {
- // Increase offset of first 'source' entry appended or prepended.
- // This is always the entry in `filler.head()`
- rep->AddDataOffset(filler.head(), head.offset);
- }
-
- if (tail.offset) {
- // Reduce length of last 'source' entry appended or prepended.
- // This is always the entry tailed by `filler.pos()`
- rep->SubLength(rep->retreat(filler.pos()), tail.offset);
- }
-
- // Commit changes
+ ring->entry_begin_pos(head.index) - head.offset;
+
+ // Start filling at `tail`, or `entries` before `head`
+ Filler filler(rep, append ? rep->tail_ : rep->retreat(rep->head_, entries));
+
+ if (ring->refcount.IsOne()) {
+ // Copy entries from source stealing the ref and adjusting the end position.
+ // Commit the filler as this is no-op.
+ ring->ForEach(head.index, tail.index, [&](index_type ix) {
+ filler.Add(ring->entry_child(ix), ring->entry_data_offset(ix),
+ ring->entry_end_pos(ix) + delta_length);
+ });
+
+ // Unref entries we did not copy over, and delete source.
+ if (head.index != ring->head_) UnrefEntries(ring, ring->head_, head.index);
+ if (tail.index != ring->tail_) UnrefEntries(ring, tail.index, ring->tail_);
+ CordRepRing::Delete(ring);
+ } else {
+ ring->ForEach(head.index, tail.index, [&](index_type ix) {
+ CordRep* child = ring->entry_child(ix);
+ filler.Add(child, ring->entry_data_offset(ix),
+ ring->entry_end_pos(ix) + delta_length);
+ CordRep::Ref(child);
+ });
+ CordRepRing::Unref(ring);
+ }
+
+ if (head.offset) {
+ // Increase offset of first 'source' entry appended or prepended.
+ // This is always the entry in `filler.head()`
+ rep->AddDataOffset(filler.head(), head.offset);
+ }
+
+ if (tail.offset) {
+ // Reduce length of last 'source' entry appended or prepended.
+ // This is always the entry tailed by `filler.pos()`
+ rep->SubLength(rep->retreat(filler.pos()), tail.offset);
+ }
+
+ // Commit changes
rep->length += len;
- if (append) {
- rep->tail_ = filler.pos();
- } else {
- rep->head_ = filler.head();
+ if (append) {
+ rep->tail_ = filler.pos();
+ } else {
+ rep->head_ = filler.head();
rep->begin_pos_ -= len;
- }
-
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) {
+ }
+
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::AppendSlow(CordRepRing* rep, CordRep* child) {
Consume(child, [&rep](CordRep* child_arg, size_t offset, size_t len) {
if (child_arg->IsRing()) {
rep = AddRing<AddMode::kAppend>(rep, child_arg->ring(), offset, len);
- } else {
+ } else {
rep = AppendLeaf(rep, child_arg, offset, len);
- }
- });
- return rep;
-}
-
-CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child,
+ }
+ });
+ return rep;
+}
+
+CordRepRing* CordRepRing::AppendLeaf(CordRepRing* rep, CordRep* child,
size_t offset, size_t len) {
- rep = Mutable(rep, 1);
- index_type back = rep->tail_;
- const pos_type begin_pos = rep->begin_pos_ + rep->length;
- rep->tail_ = rep->advance(rep->tail_);
+ rep = Mutable(rep, 1);
+ index_type back = rep->tail_;
+ const pos_type begin_pos = rep->begin_pos_ + rep->length;
+ rep->tail_ = rep->advance(rep->tail_);
rep->length += len;
rep->entry_end_pos()[back] = begin_pos + len;
- rep->entry_child()[back] = child;
- rep->entry_data_offset()[back] = static_cast<offset_type>(offset);
- return Validate(rep, nullptr, __LINE__);
-}
-
-CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) {
- size_t length = child->length;
- if (IsFlatOrExternal(child)) {
- return AppendLeaf(rep, child, 0, length);
- }
+ rep->entry_child()[back] = child;
+ rep->entry_data_offset()[back] = static_cast<offset_type>(offset);
+ return Validate(rep, nullptr, __LINE__);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, CordRep* child) {
+ size_t length = child->length;
+ if (IsFlatOrExternal(child)) {
+ return AppendLeaf(rep, child, 0, length);
+ }
if (child->IsRing()) {
- return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length);
- }
- return AppendSlow(rep, child);
-}
-
-CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) {
+ return AddRing<AddMode::kAppend>(rep, child->ring(), 0, length);
+ }
+ return AppendSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::PrependSlow(CordRepRing* rep, CordRep* child) {
ReverseConsume(child, [&](CordRep* child_arg, size_t offset, size_t len) {
if (IsFlatOrExternal(child_arg)) {
rep = PrependLeaf(rep, child_arg, offset, len);
- } else {
+ } else {
rep = AddRing<AddMode::kPrepend>(rep, child_arg->ring(), offset, len);
- }
- });
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child,
+ }
+ });
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::PrependLeaf(CordRepRing* rep, CordRep* child,
size_t offset, size_t len) {
- rep = Mutable(rep, 1);
- index_type head = rep->retreat(rep->head_);
- pos_type end_pos = rep->begin_pos_;
- rep->head_ = head;
+ rep = Mutable(rep, 1);
+ index_type head = rep->retreat(rep->head_);
+ pos_type end_pos = rep->begin_pos_;
+ rep->head_ = head;
rep->length += len;
rep->begin_pos_ -= len;
- rep->entry_end_pos()[head] = end_pos;
- rep->entry_child()[head] = child;
- rep->entry_data_offset()[head] = static_cast<offset_type>(offset);
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) {
- size_t length = child->length;
- if (IsFlatOrExternal(child)) {
- return PrependLeaf(rep, child, 0, length);
- }
+ rep->entry_end_pos()[head] = end_pos;
+ rep->entry_child()[head] = child;
+ rep->entry_data_offset()[head] = static_cast<offset_type>(offset);
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, CordRep* child) {
+ size_t length = child->length;
+ if (IsFlatOrExternal(child)) {
+ return PrependLeaf(rep, child, 0, length);
+ }
if (child->IsRing()) {
- return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length);
- }
- return PrependSlow(rep, child);
-}
-
-CordRepRing* CordRepRing::Append(CordRepRing* rep, y_absl::string_view data,
- size_t extra) {
+ return AddRing<AddMode::kPrepend>(rep, child->ring(), 0, length);
+ }
+ return PrependSlow(rep, child);
+}
+
+CordRepRing* CordRepRing::Append(CordRepRing* rep, y_absl::string_view data,
+ size_t extra) {
if (rep->refcount.IsMutable()) {
- Span<char> avail = rep->GetAppendBuffer(data.length());
- if (!avail.empty()) {
- memcpy(avail.data(), data.data(), avail.length());
- data.remove_prefix(avail.length());
- }
- }
- if (data.empty()) return Validate(rep);
-
- const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
- rep = Mutable(rep, flats);
-
- Filler filler(rep, rep->tail_);
- pos_type pos = rep->begin_pos_ + rep->length;
-
- while (data.length() >= kMaxFlatLength) {
- auto* flat = CreateFlat(data.data(), kMaxFlatLength);
- filler.Add(flat, 0, pos += kMaxFlatLength);
- data.remove_prefix(kMaxFlatLength);
- }
-
- if (data.length()) {
- auto* flat = CreateFlat(data.data(), data.length(), extra);
- filler.Add(flat, 0, pos += data.length());
- }
-
- rep->length = pos - rep->begin_pos_;
- rep->tail_ = filler.pos();
-
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::Prepend(CordRepRing* rep, y_absl::string_view data,
- size_t extra) {
+ Span<char> avail = rep->GetAppendBuffer(data.length());
+ if (!avail.empty()) {
+ memcpy(avail.data(), data.data(), avail.length());
+ data.remove_prefix(avail.length());
+ }
+ }
+ if (data.empty()) return Validate(rep);
+
+ const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+ rep = Mutable(rep, flats);
+
+ Filler filler(rep, rep->tail_);
+ pos_type pos = rep->begin_pos_ + rep->length;
+
+ while (data.length() >= kMaxFlatLength) {
+ auto* flat = CreateFlat(data.data(), kMaxFlatLength);
+ filler.Add(flat, 0, pos += kMaxFlatLength);
+ data.remove_prefix(kMaxFlatLength);
+ }
+
+ if (data.length()) {
+ auto* flat = CreateFlat(data.data(), data.length(), extra);
+ filler.Add(flat, 0, pos += data.length());
+ }
+
+ rep->length = pos - rep->begin_pos_;
+ rep->tail_ = filler.pos();
+
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::Prepend(CordRepRing* rep, y_absl::string_view data,
+ size_t extra) {
if (rep->refcount.IsMutable()) {
- Span<char> avail = rep->GetPrependBuffer(data.length());
- if (!avail.empty()) {
- const char* tail = data.data() + data.length() - avail.length();
- memcpy(avail.data(), tail, avail.length());
- data.remove_suffix(avail.length());
- }
- }
- if (data.empty()) return rep;
-
- const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
- rep = Mutable(rep, flats);
- pos_type pos = rep->begin_pos_;
- Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats)));
-
- size_t first_size = data.size() - (flats - 1) * kMaxFlatLength;
- CordRepFlat* flat = CordRepFlat::New(first_size + extra);
- flat->length = first_size + extra;
- memcpy(flat->Data() + extra, data.data(), first_size);
- data.remove_prefix(first_size);
- filler.Add(flat, extra, pos);
- pos -= first_size;
-
- while (!data.empty()) {
- assert(data.size() >= kMaxFlatLength);
- flat = CreateFlat(data.data(), kMaxFlatLength);
- filler.Add(flat, 0, pos);
- pos -= kMaxFlatLength;
- data.remove_prefix(kMaxFlatLength);
- }
-
- rep->head_ = filler.head();
- rep->length += rep->begin_pos_ - pos;
- rep->begin_pos_ = pos;
-
- return Validate(rep);
-}
-
-// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86
-static constexpr index_type kBinarySearchThreshold = 32;
-static constexpr index_type kBinarySearchEndCount = 8;
-
-template <bool wrap>
-CordRepRing::index_type CordRepRing::FindBinary(index_type head,
- index_type tail,
- size_t offset) const {
- index_type count = tail + (wrap ? capacity_ : 0) - head;
- do {
- count = (count - 1) / 2;
- assert(count < entries(head, tail_));
- index_type mid = wrap ? advance(head, count) : head + count;
- index_type after_mid = wrap ? advance(mid) : mid + 1;
- bool larger = (offset >= entry_end_offset(mid));
- head = larger ? after_mid : head;
- tail = larger ? tail : mid;
- assert(head != tail);
- } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount));
- return head;
-}
-
-CordRepRing::Position CordRepRing::FindSlow(index_type head,
- size_t offset) const {
- index_type tail = tail_;
-
- // Binary search until we are good for linear search
- // Optimize for branchless / non wrapping ops
- if (tail > head) {
- index_type count = tail - head;
- if (count > kBinarySearchThreshold) {
- head = FindBinary<false>(head, tail, offset);
- }
- } else {
- index_type count = capacity_ + tail - head;
- if (count > kBinarySearchThreshold) {
- head = FindBinary<true>(head, tail, offset);
- }
- }
-
- pos_type pos = entry_begin_pos(head);
- pos_type end_pos = entry_end_pos(head);
- while (offset >= Distance(begin_pos_, end_pos)) {
- head = advance(head);
- pos = end_pos;
- end_pos = entry_end_pos(head);
- }
-
- return {head, offset - Distance(begin_pos_, pos)};
-}
-
-CordRepRing::Position CordRepRing::FindTailSlow(index_type head,
- size_t offset) const {
- index_type tail = tail_;
- const size_t tail_offset = offset - 1;
-
- // Binary search until we are good for linear search
- // Optimize for branchless / non wrapping ops
- if (tail > head) {
- index_type count = tail - head;
- if (count > kBinarySearchThreshold) {
- head = FindBinary<false>(head, tail, tail_offset);
- }
- } else {
- index_type count = capacity_ + tail - head;
- if (count > kBinarySearchThreshold) {
- head = FindBinary<true>(head, tail, tail_offset);
- }
- }
-
- size_t end_offset = entry_end_offset(head);
- while (tail_offset >= end_offset) {
- head = advance(head);
- end_offset = entry_end_offset(head);
- }
-
- return {advance(head), end_offset - offset};
-}
-
-char CordRepRing::GetCharacter(size_t offset) const {
- assert(offset < length);
-
- Position pos = Find(offset);
- size_t data_offset = entry_data_offset(pos.index) + pos.offset;
- return GetRepData(entry_child(pos.index))[data_offset];
-}
-
-CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset,
+ Span<char> avail = rep->GetPrependBuffer(data.length());
+ if (!avail.empty()) {
+ const char* tail = data.data() + data.length() - avail.length();
+ memcpy(avail.data(), tail, avail.length());
+ data.remove_suffix(avail.length());
+ }
+ }
+ if (data.empty()) return rep;
+
+ const size_t flats = (data.length() - 1) / kMaxFlatLength + 1;
+ rep = Mutable(rep, flats);
+ pos_type pos = rep->begin_pos_;
+ Filler filler(rep, rep->retreat(rep->head_, static_cast<index_type>(flats)));
+
+ size_t first_size = data.size() - (flats - 1) * kMaxFlatLength;
+ CordRepFlat* flat = CordRepFlat::New(first_size + extra);
+ flat->length = first_size + extra;
+ memcpy(flat->Data() + extra, data.data(), first_size);
+ data.remove_prefix(first_size);
+ filler.Add(flat, extra, pos);
+ pos -= first_size;
+
+ while (!data.empty()) {
+ assert(data.size() >= kMaxFlatLength);
+ flat = CreateFlat(data.data(), kMaxFlatLength);
+ filler.Add(flat, 0, pos);
+ pos -= kMaxFlatLength;
+ data.remove_prefix(kMaxFlatLength);
+ }
+
+ rep->head_ = filler.head();
+ rep->length += rep->begin_pos_ - pos;
+ rep->begin_pos_ = pos;
+
+ return Validate(rep);
+}
+
+// 32 entries is 32 * sizeof(pos_type) = 4 cache lines on x86
+static constexpr index_type kBinarySearchThreshold = 32;
+static constexpr index_type kBinarySearchEndCount = 8;
+
+template <bool wrap>
+CordRepRing::index_type CordRepRing::FindBinary(index_type head,
+ index_type tail,
+ size_t offset) const {
+ index_type count = tail + (wrap ? capacity_ : 0) - head;
+ do {
+ count = (count - 1) / 2;
+ assert(count < entries(head, tail_));
+ index_type mid = wrap ? advance(head, count) : head + count;
+ index_type after_mid = wrap ? advance(mid) : mid + 1;
+ bool larger = (offset >= entry_end_offset(mid));
+ head = larger ? after_mid : head;
+ tail = larger ? tail : mid;
+ assert(head != tail);
+ } while (ABSL_PREDICT_TRUE(count > kBinarySearchEndCount));
+ return head;
+}
+
+CordRepRing::Position CordRepRing::FindSlow(index_type head,
+ size_t offset) const {
+ index_type tail = tail_;
+
+ // Binary search until we are good for linear search
+ // Optimize for branchless / non wrapping ops
+ if (tail > head) {
+ index_type count = tail - head;
+ if (count > kBinarySearchThreshold) {
+ head = FindBinary<false>(head, tail, offset);
+ }
+ } else {
+ index_type count = capacity_ + tail - head;
+ if (count > kBinarySearchThreshold) {
+ head = FindBinary<true>(head, tail, offset);
+ }
+ }
+
+ pos_type pos = entry_begin_pos(head);
+ pos_type end_pos = entry_end_pos(head);
+ while (offset >= Distance(begin_pos_, end_pos)) {
+ head = advance(head);
+ pos = end_pos;
+ end_pos = entry_end_pos(head);
+ }
+
+ return {head, offset - Distance(begin_pos_, pos)};
+}
+
+CordRepRing::Position CordRepRing::FindTailSlow(index_type head,
+ size_t offset) const {
+ index_type tail = tail_;
+ const size_t tail_offset = offset - 1;
+
+ // Binary search until we are good for linear search
+ // Optimize for branchless / non wrapping ops
+ if (tail > head) {
+ index_type count = tail - head;
+ if (count > kBinarySearchThreshold) {
+ head = FindBinary<false>(head, tail, tail_offset);
+ }
+ } else {
+ index_type count = capacity_ + tail - head;
+ if (count > kBinarySearchThreshold) {
+ head = FindBinary<true>(head, tail, tail_offset);
+ }
+ }
+
+ size_t end_offset = entry_end_offset(head);
+ while (tail_offset >= end_offset) {
+ head = advance(head);
+ end_offset = entry_end_offset(head);
+ }
+
+ return {advance(head), end_offset - offset};
+}
+
+char CordRepRing::GetCharacter(size_t offset) const {
+ assert(offset < length);
+
+ Position pos = Find(offset);
+ size_t data_offset = entry_data_offset(pos.index) + pos.offset;
+ return GetRepData(entry_child(pos.index))[data_offset];
+}
+
+CordRepRing* CordRepRing::SubRing(CordRepRing* rep, size_t offset,
size_t len, size_t extra) {
- assert(offset <= rep->length);
+ assert(offset <= rep->length);
assert(offset <= rep->length - len);
-
+
if (len == 0) {
- CordRep::Unref(rep);
- return nullptr;
- }
-
- // Find position of first byte
- Position head = rep->Find(offset);
+ CordRep::Unref(rep);
+ return nullptr;
+ }
+
+ // Find position of first byte
+ Position head = rep->Find(offset);
Position tail = rep->FindTail(head.index, offset + len);
- const size_t new_entries = rep->entries(head.index, tail.index);
-
+ const size_t new_entries = rep->entries(head.index, tail.index);
+
if (rep->refcount.IsMutable() && extra <= (rep->capacity() - new_entries)) {
- // We adopt a privately owned rep and no extra entries needed.
- if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
- if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
- rep->head_ = head.index;
- rep->tail_ = tail.index;
- } else {
- // Copy subset to new rep
- rep = Copy(rep, head.index, tail.index, extra);
- head.index = rep->head_;
- tail.index = rep->tail_;
- }
-
- // Adjust begin_pos and length
+ // We adopt a privately owned rep and no extra entries needed.
+ if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+ if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+ rep->head_ = head.index;
+ rep->tail_ = tail.index;
+ } else {
+ // Copy subset to new rep
+ rep = Copy(rep, head.index, tail.index, extra);
+ head.index = rep->head_;
+ tail.index = rep->tail_;
+ }
+
+ // Adjust begin_pos and length
rep->length = len;
- rep->begin_pos_ += offset;
-
- // Adjust head and tail blocks
- if (head.offset) {
- rep->AddDataOffset(head.index, head.offset);
- }
- if (tail.offset) {
- rep->SubLength(rep->retreat(tail.index), tail.offset);
- }
-
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len,
- size_t extra) {
- assert(len <= rep->length);
- if (len == rep->length) {
- CordRep::Unref(rep);
- return nullptr;
- }
-
- Position head = rep->Find(len);
+ rep->begin_pos_ += offset;
+
+ // Adjust head and tail blocks
+ if (head.offset) {
+ rep->AddDataOffset(head.index, head.offset);
+ }
+ if (tail.offset) {
+ rep->SubLength(rep->retreat(tail.index), tail.offset);
+ }
+
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemovePrefix(CordRepRing* rep, size_t len,
+ size_t extra) {
+ assert(len <= rep->length);
+ if (len == rep->length) {
+ CordRep::Unref(rep);
+ return nullptr;
+ }
+
+ Position head = rep->Find(len);
if (rep->refcount.IsMutable()) {
- if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
- rep->head_ = head.index;
- } else {
- rep = Copy(rep, head.index, rep->tail_, extra);
- head.index = rep->head_;
- }
-
- // Adjust begin_pos and length
- rep->length -= len;
- rep->begin_pos_ += len;
-
- // Adjust head block
- if (head.offset) {
- rep->AddDataOffset(head.index, head.offset);
- }
-
- return Validate(rep);
-}
-
-CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len,
- size_t extra) {
- assert(len <= rep->length);
-
- if (len == rep->length) {
- CordRep::Unref(rep);
- return nullptr;
- }
-
- Position tail = rep->FindTail(rep->length - len);
+ if (head.index != rep->head_) UnrefEntries(rep, rep->head_, head.index);
+ rep->head_ = head.index;
+ } else {
+ rep = Copy(rep, head.index, rep->tail_, extra);
+ head.index = rep->head_;
+ }
+
+ // Adjust begin_pos and length
+ rep->length -= len;
+ rep->begin_pos_ += len;
+
+ // Adjust head block
+ if (head.offset) {
+ rep->AddDataOffset(head.index, head.offset);
+ }
+
+ return Validate(rep);
+}
+
+CordRepRing* CordRepRing::RemoveSuffix(CordRepRing* rep, size_t len,
+ size_t extra) {
+ assert(len <= rep->length);
+
+ if (len == rep->length) {
+ CordRep::Unref(rep);
+ return nullptr;
+ }
+
+ Position tail = rep->FindTail(rep->length - len);
if (rep->refcount.IsMutable()) {
- // We adopt a privately owned rep, scrub.
- if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
- rep->tail_ = tail.index;
- } else {
- // Copy subset to new rep
- rep = Copy(rep, rep->head_, tail.index, extra);
- tail.index = rep->tail_;
- }
-
- // Adjust length
- rep->length -= len;
-
- // Adjust tail block
- if (tail.offset) {
- rep->SubLength(rep->retreat(tail.index), tail.offset);
- }
-
- return Validate(rep);
-}
-
-} // namespace cord_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
+ // We adopt a privately owned rep, scrub.
+ if (tail.index != rep->tail_) UnrefEntries(rep, tail.index, rep->tail_);
+ rep->tail_ = tail.index;
+ } else {
+ // Copy subset to new rep
+ rep = Copy(rep, rep->head_, tail.index, extra);
+ tail.index = rep->tail_;
+ }
+
+ // Adjust length
+ rep->length -= len;
+
+ // Adjust tail block
+ if (tail.offset) {
+ rep->SubLength(rep->retreat(tail.index), tail.offset);
+ }
+
+ return Validate(rep);
+}
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h
index 5f9784d8da..a6a4890ab4 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring.h
@@ -1,233 +1,233 @@
-// Copyright 2020 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
-#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <iosfwd>
-#include <limits>
-#include <memory>
-
-#include "y_absl/container/internal/layout.h"
-#include "y_absl/strings/internal/cord_internal.h"
-#include "y_absl/strings/internal/cord_rep_flat.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace cord_internal {
-
-// All operations modifying a ring buffer are implemented as static methods
-// requiring a CordRepRing instance with a reference adopted by the method.
-//
-// The methods return the modified ring buffer, which may be equal to the input
-// if the input was not shared, and having large enough capacity to accommodate
-// any newly added node(s). Otherwise, a copy of the input rep with the new
-// node(s) added is returned.
-//
-// Any modification on non shared ring buffers with enough capacity will then
-// require minimum atomic operations. Caller should where possible provide
-// reasonable `extra` hints for both anticipated extra `flat` byte space, as
-// well as anticipated extra nodes required for complex operations.
-//
-// Example of code creating a ring buffer, adding some data to it,
-// and discarding the buffer when done:
-//
-// void FunWithRings() {
-// // Create ring with 3 flats
-// CordRep* flat = CreateFlat("Hello");
-// CordRepRing* ring = CordRepRing::Create(flat, 2);
-// ring = CordRepRing::Append(ring, CreateFlat(" "));
-// ring = CordRepRing::Append(ring, CreateFlat("world"));
-// DoSomethingWithRing(ring);
-// CordRep::Unref(ring);
-// }
-//
-// Example of code Copying an existing ring buffer and modifying it:
-//
-// void MoreFunWithRings(CordRepRing* src) {
-// CordRepRing* ring = CordRep::Ref(src)->ring();
-// ring = CordRepRing::Append(ring, CreateFlat("Hello"));
-// ring = CordRepRing::Append(ring, CreateFlat(" "));
-// ring = CordRepRing::Append(ring, CreateFlat("world"));
-// DoSomethingWithRing(ring);
-// CordRep::Unref(ring);
-// }
-//
-class CordRepRing : public CordRep {
- public:
- // `pos_type` represents a 'logical position'. A CordRepRing instance has a
- // `begin_pos` (default 0), and each node inside the buffer will have an
- // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus
- // this node's length. The purpose is to allow for a binary search on this
- // position, while allowing O(1) prepend and append operations.
- using pos_type = size_t;
-
- // `index_type` is the type for the `head`, `tail` and `capacity` indexes.
- // Ring buffers are limited to having no more than four billion entries.
- using index_type = uint32_t;
-
- // `offset_type` is the type for the data offset inside a child rep's data.
- using offset_type = uint32_t;
-
- // Position holds the node index and relative offset into the node for
- // some physical offset in the contained data as returned by the Find()
- // and FindTail() methods.
- struct Position {
- index_type index;
- size_t offset;
- };
-
- // The maximum # of child nodes that can be hosted inside a CordRepRing.
- static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)();
-
- // CordRepring can not be default constructed, moved, copied or assigned.
- CordRepRing() = delete;
- CordRepRing(const CordRepRing&) = delete;
- CordRepRing& operator=(const CordRepRing&) = delete;
-
- // Returns true if this instance is valid, false if some or all of the
- // invariants are broken. Intended for debug purposes only.
- // `output` receives an explanation of the broken invariants.
- bool IsValid(std::ostream& output) const;
-
- // Returns the size in bytes for a CordRepRing with `capacity' entries.
- static constexpr size_t AllocSize(size_t capacity);
-
- // Returns the distance in bytes from `pos` to `end_pos`.
- static constexpr size_t Distance(pos_type pos, pos_type end_pos);
-
- // Creates a new ring buffer from the provided `rep`. Adopts a reference
- // on `rep`. The returned ring buffer has a capacity of at least `extra + 1`
- static CordRepRing* Create(CordRep* child, size_t extra = 0);
-
- // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries.
- index_type head() const { return head_; }
- index_type tail() const { return tail_; }
- index_type capacity() const { return capacity_; }
-
- // Returns the number of entries in this instance.
- index_type entries() const { return entries(head_, tail_); }
-
- // Returns the logical begin position of this instance.
- pos_type begin_pos() const { return begin_pos_; }
-
- // Returns the number of entries for a given head-tail range.
- // Requires `head` and `tail` values to be less than `capacity()`.
- index_type entries(index_type head, index_type tail) const {
- assert(head < capacity_ && tail < capacity_);
- return tail - head + ((tail > head) ? 0 : capacity_);
- }
-
- // Returns the logical end position of entry `index`.
- pos_type const& entry_end_pos(index_type index) const {
- assert(IsValidIndex(index));
- return Layout::Partial().Pointer<0>(data_)[index];
- }
-
- // Returns the child pointer of entry `index`.
- CordRep* const& entry_child(index_type index) const {
- assert(IsValidIndex(index));
- return Layout::Partial(capacity()).Pointer<1>(data_)[index];
- }
-
- // Returns the data offset of entry `index`
- offset_type const& entry_data_offset(index_type index) const {
- assert(IsValidIndex(index));
- return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index];
- }
-
- // Appends the provided child node to the `rep` instance.
- // Adopts a reference from `rep` and `child` which may not be null.
- // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
- // containing a FLAT or EXTERNAL node, then flat or external the node is added
- // 'as is', with an offset added for the SUBSTRING case.
- // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or
- // CONCAT tree, then all child nodes not excluded by any start offset or
- // length values are added recursively.
- static CordRepRing* Append(CordRepRing* rep, CordRep* child);
-
- // Appends the provided string data to the `rep` instance.
- // This function will attempt to utilize any remaining capacity in the last
- // node of the input if that node is not shared (directly or indirectly), and
- // of type FLAT. Remaining data will be added as one or more FLAT nodes.
- // Any last node added to the ring buffer will be allocated with up to
- // `extra` bytes of capacity for (anticipated) subsequent append actions.
- static CordRepRing* Append(CordRepRing* rep, string_view data,
- size_t extra = 0);
-
- // Prepends the provided child node to the `rep` instance.
- // Adopts a reference from `rep` and `child` which may not be null.
- // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
- // containing a FLAT or EXTERNAL node, then flat or external the node is
- // prepended 'as is', with an optional offset added for the SUBSTRING case.
- // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING
- // or CONCAT tree, then all child nodes not excluded by any start offset or
- // length values are added recursively.
- static CordRepRing* Prepend(CordRepRing* rep, CordRep* child);
-
- // Prepends the provided string data to the `rep` instance.
- // This function will attempt to utilize any remaining capacity in the first
- // node of the input if that node is not shared (directly or indirectly), and
- // of type FLAT. Remaining data will be added as one or more FLAT nodes.
- // Any first node prepnded to the ring buffer will be allocated with up to
- // `extra` bytes of capacity for (anticipated) subsequent prepend actions.
- static CordRepRing* Prepend(CordRepRing* rep, string_view data,
- size_t extra = 0);
-
- // Returns a span referencing potentially unused capacity in the last node.
- // The returned span may be empty if no such capacity is available, or if the
- // current instance is shared. Else, a span of size `n <= size` is returned.
- // If non empty, the ring buffer is adjusted to the new length, with the newly
- // added capacity left uninitialized. Callers should assign a value to the
- // entire span before any other operations on this instance.
- Span<char> GetAppendBuffer(size_t size);
-
- // Returns a span referencing potentially unused capacity in the first node.
- // This function is identical to GetAppendBuffer except that it returns a span
- // referencing up to `size` capacity directly before the existing data.
- Span<char> GetPrependBuffer(size_t size);
-
+// Copyright 2020 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iosfwd>
+#include <limits>
+#include <memory>
+
+#include "y_absl/container/internal/layout.h"
+#include "y_absl/strings/internal/cord_internal.h"
+#include "y_absl/strings/internal/cord_rep_flat.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// All operations modifying a ring buffer are implemented as static methods
+// requiring a CordRepRing instance with a reference adopted by the method.
+//
+// The methods return the modified ring buffer, which may be equal to the input
+// if the input was not shared, and having large enough capacity to accommodate
+// any newly added node(s). Otherwise, a copy of the input rep with the new
+// node(s) added is returned.
+//
+// Any modification on non shared ring buffers with enough capacity will then
+// require minimum atomic operations. Caller should where possible provide
+// reasonable `extra` hints for both anticipated extra `flat` byte space, as
+// well as anticipated extra nodes required for complex operations.
+//
+// Example of code creating a ring buffer, adding some data to it,
+// and discarding the buffer when done:
+//
+// void FunWithRings() {
+// // Create ring with 3 flats
+// CordRep* flat = CreateFlat("Hello");
+// CordRepRing* ring = CordRepRing::Create(flat, 2);
+// ring = CordRepRing::Append(ring, CreateFlat(" "));
+// ring = CordRepRing::Append(ring, CreateFlat("world"));
+// DoSomethingWithRing(ring);
+// CordRep::Unref(ring);
+// }
+//
+// Example of code Copying an existing ring buffer and modifying it:
+//
+// void MoreFunWithRings(CordRepRing* src) {
+// CordRepRing* ring = CordRep::Ref(src)->ring();
+// ring = CordRepRing::Append(ring, CreateFlat("Hello"));
+// ring = CordRepRing::Append(ring, CreateFlat(" "));
+// ring = CordRepRing::Append(ring, CreateFlat("world"));
+// DoSomethingWithRing(ring);
+// CordRep::Unref(ring);
+// }
+//
+class CordRepRing : public CordRep {
+ public:
+ // `pos_type` represents a 'logical position'. A CordRepRing instance has a
+ // `begin_pos` (default 0), and each node inside the buffer will have an
+ // `end_pos` which is the `end_pos` of the previous node (or `begin_pos`) plus
+ // this node's length. The purpose is to allow for a binary search on this
+ // position, while allowing O(1) prepend and append operations.
+ using pos_type = size_t;
+
+ // `index_type` is the type for the `head`, `tail` and `capacity` indexes.
+ // Ring buffers are limited to having no more than four billion entries.
+ using index_type = uint32_t;
+
+ // `offset_type` is the type for the data offset inside a child rep's data.
+ using offset_type = uint32_t;
+
+ // Position holds the node index and relative offset into the node for
+ // some physical offset in the contained data as returned by the Find()
+ // and FindTail() methods.
+ struct Position {
+ index_type index;
+ size_t offset;
+ };
+
+ // The maximum # of child nodes that can be hosted inside a CordRepRing.
+ static constexpr size_t kMaxCapacity = (std::numeric_limits<uint32_t>::max)();
+
+ // CordRepring can not be default constructed, moved, copied or assigned.
+ CordRepRing() = delete;
+ CordRepRing(const CordRepRing&) = delete;
+ CordRepRing& operator=(const CordRepRing&) = delete;
+
+ // Returns true if this instance is valid, false if some or all of the
+ // invariants are broken. Intended for debug purposes only.
+ // `output` receives an explanation of the broken invariants.
+ bool IsValid(std::ostream& output) const;
+
+ // Returns the size in bytes for a CordRepRing with `capacity' entries.
+ static constexpr size_t AllocSize(size_t capacity);
+
+ // Returns the distance in bytes from `pos` to `end_pos`.
+ static constexpr size_t Distance(pos_type pos, pos_type end_pos);
+
+ // Creates a new ring buffer from the provided `rep`. Adopts a reference
+ // on `rep`. The returned ring buffer has a capacity of at least `extra + 1`
+ static CordRepRing* Create(CordRep* child, size_t extra = 0);
+
+ // `head`, `tail` and `capacity` indexes defining the ring buffer boundaries.
+ index_type head() const { return head_; }
+ index_type tail() const { return tail_; }
+ index_type capacity() const { return capacity_; }
+
+ // Returns the number of entries in this instance.
+ index_type entries() const { return entries(head_, tail_); }
+
+ // Returns the logical begin position of this instance.
+ pos_type begin_pos() const { return begin_pos_; }
+
+ // Returns the number of entries for a given head-tail range.
+ // Requires `head` and `tail` values to be less than `capacity()`.
+ index_type entries(index_type head, index_type tail) const {
+ assert(head < capacity_ && tail < capacity_);
+ return tail - head + ((tail > head) ? 0 : capacity_);
+ }
+
+ // Returns the logical end position of entry `index`.
+ pos_type const& entry_end_pos(index_type index) const {
+ assert(IsValidIndex(index));
+ return Layout::Partial().Pointer<0>(data_)[index];
+ }
+
+ // Returns the child pointer of entry `index`.
+ CordRep* const& entry_child(index_type index) const {
+ assert(IsValidIndex(index));
+ return Layout::Partial(capacity()).Pointer<1>(data_)[index];
+ }
+
+ // Returns the data offset of entry `index`
+ offset_type const& entry_data_offset(index_type index) const {
+ assert(IsValidIndex(index));
+ return Layout::Partial(capacity(), capacity()).Pointer<2>(data_)[index];
+ }
+
+ // Appends the provided child node to the `rep` instance.
+ // Adopts a reference from `rep` and `child` which may not be null.
+ // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+ // containing a FLAT or EXTERNAL node, then flat or external the node is added
+ // 'as is', with an offset added for the SUBSTRING case.
+ // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING or
+ // CONCAT tree, then all child nodes not excluded by any start offset or
+ // length values are added recursively.
+ static CordRepRing* Append(CordRepRing* rep, CordRep* child);
+
+ // Appends the provided string data to the `rep` instance.
+ // This function will attempt to utilize any remaining capacity in the last
+ // node of the input if that node is not shared (directly or indirectly), and
+ // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+ // Any last node added to the ring buffer will be allocated with up to
+ // `extra` bytes of capacity for (anticipated) subsequent append actions.
+ static CordRepRing* Append(CordRepRing* rep, string_view data,
+ size_t extra = 0);
+
+ // Prepends the provided child node to the `rep` instance.
+ // Adopts a reference from `rep` and `child` which may not be null.
+ // If the provided child is a FLAT or EXTERNAL node, or a SUBSTRING node
+ // containing a FLAT or EXTERNAL node, then flat or external the node is
+ // prepended 'as is', with an optional offset added for the SUBSTRING case.
+ // If the provided child is a RING or CONCAT tree, or a SUBSTRING of a RING
+ // or CONCAT tree, then all child nodes not excluded by any start offset or
+ // length values are added recursively.
+ static CordRepRing* Prepend(CordRepRing* rep, CordRep* child);
+
+ // Prepends the provided string data to the `rep` instance.
+ // This function will attempt to utilize any remaining capacity in the first
+ // node of the input if that node is not shared (directly or indirectly), and
+ // of type FLAT. Remaining data will be added as one or more FLAT nodes.
+ // Any first node prepnded to the ring buffer will be allocated with up to
+ // `extra` bytes of capacity for (anticipated) subsequent prepend actions.
+ static CordRepRing* Prepend(CordRepRing* rep, string_view data,
+ size_t extra = 0);
+
+ // Returns a span referencing potentially unused capacity in the last node.
+ // The returned span may be empty if no such capacity is available, or if the
+ // current instance is shared. Else, a span of size `n <= size` is returned.
+ // If non empty, the ring buffer is adjusted to the new length, with the newly
+ // added capacity left uninitialized. Callers should assign a value to the
+ // entire span before any other operations on this instance.
+ Span<char> GetAppendBuffer(size_t size);
+
+ // Returns a span referencing potentially unused capacity in the first node.
+ // This function is identical to GetAppendBuffer except that it returns a span
+ // referencing up to `size` capacity directly before the existing data.
+ Span<char> GetPrependBuffer(size_t size);
+
// Returns a cord ring buffer containing `len` bytes of data starting at
- // `offset`. If the input is not shared, this function will remove all head
- // and tail child nodes outside of the requested range, and adjust the new
- // head and tail nodes as required. If the input is shared, this function
- // returns a new instance sharing some or all of the nodes from the input.
+ // `offset`. If the input is not shared, this function will remove all head
+ // and tail child nodes outside of the requested range, and adjust the new
+ // head and tail nodes as required. If the input is shared, this function
+ // returns a new instance sharing some or all of the nodes from the input.
static CordRepRing* SubRing(CordRepRing* r, size_t offset, size_t len,
- size_t extra = 0);
-
+ size_t extra = 0);
+
// Returns a cord ring buffer with the first `len` bytes removed.
- // If the input is not shared, this function will remove all head child nodes
- // fully inside the first `length` bytes, and adjust the new head as required.
- // If the input is shared, this function returns a new instance sharing some
- // or all of the nodes from the input.
+ // If the input is not shared, this function will remove all head child nodes
+ // fully inside the first `length` bytes, and adjust the new head as required.
+ // If the input is shared, this function returns a new instance sharing some
+ // or all of the nodes from the input.
static CordRepRing* RemoveSuffix(CordRepRing* r, size_t len,
- size_t extra = 0);
-
+ size_t extra = 0);
+
// Returns a cord ring buffer with the last `len` bytes removed.
- // If the input is not shared, this function will remove all head child nodes
- // fully inside the first `length` bytes, and adjust the new head as required.
- // If the input is shared, this function returns a new instance sharing some
- // or all of the nodes from the input.
- static CordRepRing* RemovePrefix(CordRepRing* r, size_t len,
- size_t extra = 0);
-
- // Returns the character at `offset`. Requires that `offset < length`.
- char GetCharacter(size_t offset) const;
-
+ // If the input is not shared, this function will remove all head child nodes
+ // fully inside the first `length` bytes, and adjust the new head as required.
+ // If the input is shared, this function returns a new instance sharing some
+ // or all of the nodes from the input.
+ static CordRepRing* RemovePrefix(CordRepRing* r, size_t len,
+ size_t extra = 0);
+
+ // Returns the character at `offset`. Requires that `offset < length`.
+ char GetCharacter(size_t offset) const;
+
// Returns true if this instance manages a single contiguous buffer, in which
// case the (optional) output parameter `fragment` is set. Otherwise, the
// function returns false, and `fragment` is left unchanged.
@@ -240,345 +240,345 @@ class CordRepRing : public CordRep {
// returns false, and `fragment` is left unchanged.
bool IsFlat(size_t offset, size_t len, y_absl::string_view* fragment) const;
- // Testing only: set capacity to requested capacity.
- void SetCapacityForTesting(size_t capacity);
-
- // Returns the CordRep data pointer for the provided CordRep.
- // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep.
- static const char* GetLeafData(const CordRep* rep);
-
- // Returns the CordRep data pointer for the provided CordRep.
- // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep.
- static const char* GetRepData(const CordRep* rep);
-
- // Advances the provided position, wrapping around capacity as needed.
- // Requires `index` < capacity()
- inline index_type advance(index_type index) const;
-
- // Advances the provided position by 'n`, wrapping around capacity as needed.
- // Requires `index` < capacity() and `n` <= capacity.
- inline index_type advance(index_type index, index_type n) const;
-
- // Retreats the provided position, wrapping around 0 as needed.
- // Requires `index` < capacity()
- inline index_type retreat(index_type index) const;
-
- // Retreats the provided position by 'n', wrapping around 0 as needed.
- // Requires `index` < capacity()
- inline index_type retreat(index_type index, index_type n) const;
-
- // Returns the logical begin position of entry `index`
- pos_type const& entry_begin_pos(index_type index) const {
- return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index));
- }
-
- // Returns the physical start offset of entry `index`
- size_t entry_start_offset(index_type index) const {
- return Distance(begin_pos_, entry_begin_pos(index));
- }
-
- // Returns the physical end offset of entry `index`
- size_t entry_end_offset(index_type index) const {
- return Distance(begin_pos_, entry_end_pos(index));
- }
-
- // Returns the data length for entry `index`
- size_t entry_length(index_type index) const {
- return Distance(entry_begin_pos(index), entry_end_pos(index));
- }
-
- // Returns the data for entry `index`
- y_absl::string_view entry_data(index_type index) const;
-
- // Returns the position for `offset` as {index, prefix}. `index` holds the
- // index of the entry at the specified offset and `prefix` holds the relative
- // offset inside that entry.
- // Requires `offset` < length.
- //
- // For example we can implement GetCharacter(offset) as:
- // char GetCharacter(size_t offset) {
- // Position pos = this->Find(offset);
- // return this->entry_data(pos.pos)[pos.offset];
- // }
- inline Position Find(size_t offset) const;
-
- // Find starting at `head`
- inline Position Find(index_type head, size_t offset) const;
-
- // Returns the tail position for `offset` as {tail index, suffix}.
- // `tail index` holds holds the index of the entry holding the offset directly
- // before 'offset` advanced by one. 'suffix` holds the relative offset from
- // that relative offset in the entry to the end of the entry.
- // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5)
- // will return {retreat(tail), 5)} provided the preceding entry contains at
- // least 5 bytes of data.
- // Requires offset >= 1 && offset <= length.
- //
- // This function is very useful in functions that need to clip the end of some
- // ring buffer such as 'RemovePrefix'.
- // For example, we could implement RemovePrefix for non shared instances as:
- // void RemoveSuffix(size_t n) {
- // Position pos = FindTail(length - n);
- // UnrefEntries(pos.pos, this->tail_);
- // this->tail_ = pos.pos;
- // entry(retreat(pos.pos)).end_pos -= pos.offset;
- // }
- inline Position FindTail(size_t offset) const;
-
- // Find tail starting at `head`
- inline Position FindTail(index_type head, size_t offset) const;
-
- // Invokes f(index_type index) for each entry inside the range [head, tail>
- template <typename F>
- void ForEach(index_type head, index_type tail, F&& f) const {
- index_type n1 = (tail > head) ? tail : capacity_;
- for (index_type i = head; i < n1; ++i) f(i);
- if (tail <= head) {
- for (index_type i = 0; i < tail; ++i) f(i);
- }
- }
-
- // Invokes f(index_type index) for each entry inside this instance.
- template <typename F>
- void ForEach(F&& f) const {
- ForEach(head_, tail_, std::forward<F>(f));
- }
-
- // Dump this instance's data tp stream `s` in human readable format, excluding
- // the actual data content itself. Intended for debug purposes only.
- friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
-
- private:
- enum class AddMode { kAppend, kPrepend };
-
- using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>;
-
- class Filler;
- class Transaction;
- class CreateTransaction;
-
- static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment();
-
- // Creates a new CordRepRing.
- explicit CordRepRing(index_type capacity) : capacity_(capacity) {}
-
- // Returns true if `index` is a valid index into this instance.
- bool IsValidIndex(index_type index) const;
-
- // Debug use only: validates the provided CordRepRing invariants.
- // Verification of all CordRepRing methods can be enabled by defining
- // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION`
- // Verification is VERY expensive, so only do it for debugging purposes.
- static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr,
- int line = 0);
-
- // Allocates a CordRepRing large enough to hold `capacity + extra' entries.
- // The returned capacity may be larger if the allocated memory allows for it.
- // The maximum capacity of a CordRepRing is capped at kMaxCapacity.
- // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity.
- static CordRepRing* New(size_t capacity, size_t extra);
-
- // Deallocates (but does not destroy) the provided ring buffer.
- static void Delete(CordRepRing* rep);
-
- // Destroys the provided ring buffer, decrementing the reference count of all
- // contained child CordReps. The provided 1\`rep` should have a ref count of
+ // Testing only: set capacity to requested capacity.
+ void SetCapacityForTesting(size_t capacity);
+
+ // Returns the CordRep data pointer for the provided CordRep.
+ // Requires that the provided `rep` is either a FLAT or EXTERNAL CordRep.
+ static const char* GetLeafData(const CordRep* rep);
+
+ // Returns the CordRep data pointer for the provided CordRep.
+ // Requires that `rep` is either a FLAT, EXTERNAL, or SUBSTRING CordRep.
+ static const char* GetRepData(const CordRep* rep);
+
+ // Advances the provided position, wrapping around capacity as needed.
+ // Requires `index` < capacity()
+ inline index_type advance(index_type index) const;
+
+ // Advances the provided position by 'n`, wrapping around capacity as needed.
+ // Requires `index` < capacity() and `n` <= capacity.
+ inline index_type advance(index_type index, index_type n) const;
+
+ // Retreats the provided position, wrapping around 0 as needed.
+ // Requires `index` < capacity()
+ inline index_type retreat(index_type index) const;
+
+ // Retreats the provided position by 'n', wrapping around 0 as needed.
+ // Requires `index` < capacity()
+ inline index_type retreat(index_type index, index_type n) const;
+
+ // Returns the logical begin position of entry `index`
+ pos_type const& entry_begin_pos(index_type index) const {
+ return (index == head_) ? begin_pos_ : entry_end_pos(retreat(index));
+ }
+
+ // Returns the physical start offset of entry `index`
+ size_t entry_start_offset(index_type index) const {
+ return Distance(begin_pos_, entry_begin_pos(index));
+ }
+
+ // Returns the physical end offset of entry `index`
+ size_t entry_end_offset(index_type index) const {
+ return Distance(begin_pos_, entry_end_pos(index));
+ }
+
+ // Returns the data length for entry `index`
+ size_t entry_length(index_type index) const {
+ return Distance(entry_begin_pos(index), entry_end_pos(index));
+ }
+
+ // Returns the data for entry `index`
+ y_absl::string_view entry_data(index_type index) const;
+
+ // Returns the position for `offset` as {index, prefix}. `index` holds the
+ // index of the entry at the specified offset and `prefix` holds the relative
+ // offset inside that entry.
+ // Requires `offset` < length.
+ //
+ // For example we can implement GetCharacter(offset) as:
+ // char GetCharacter(size_t offset) {
+ // Position pos = this->Find(offset);
+ // return this->entry_data(pos.pos)[pos.offset];
+ // }
+ inline Position Find(size_t offset) const;
+
+ // Find starting at `head`
+ inline Position Find(index_type head, size_t offset) const;
+
+ // Returns the tail position for `offset` as {tail index, suffix}.
+ // `tail index` holds holds the index of the entry holding the offset directly
+ // before 'offset` advanced by one. 'suffix` holds the relative offset from
+ // that relative offset in the entry to the end of the entry.
+ // For example, FindTail(length) will return {tail(), 0}, FindTail(length - 5)
+ // will return {retreat(tail), 5)} provided the preceding entry contains at
+ // least 5 bytes of data.
+ // Requires offset >= 1 && offset <= length.
+ //
+ // This function is very useful in functions that need to clip the end of some
+ // ring buffer such as 'RemovePrefix'.
+ // For example, we could implement RemovePrefix for non shared instances as:
+ // void RemoveSuffix(size_t n) {
+ // Position pos = FindTail(length - n);
+ // UnrefEntries(pos.pos, this->tail_);
+ // this->tail_ = pos.pos;
+ // entry(retreat(pos.pos)).end_pos -= pos.offset;
+ // }
+ inline Position FindTail(size_t offset) const;
+
+ // Find tail starting at `head`
+ inline Position FindTail(index_type head, size_t offset) const;
+
+ // Invokes f(index_type index) for each entry inside the range [head, tail>
+ template <typename F>
+ void ForEach(index_type head, index_type tail, F&& f) const {
+ index_type n1 = (tail > head) ? tail : capacity_;
+ for (index_type i = head; i < n1; ++i) f(i);
+ if (tail <= head) {
+ for (index_type i = 0; i < tail; ++i) f(i);
+ }
+ }
+
+ // Invokes f(index_type index) for each entry inside this instance.
+ template <typename F>
+ void ForEach(F&& f) const {
+ ForEach(head_, tail_, std::forward<F>(f));
+ }
+
+ // Dump this instance's data tp stream `s` in human readable format, excluding
+ // the actual data content itself. Intended for debug purposes only.
+ friend std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+ private:
+ enum class AddMode { kAppend, kPrepend };
+
+ using Layout = container_internal::Layout<pos_type, CordRep*, offset_type>;
+
+ class Filler;
+ class Transaction;
+ class CreateTransaction;
+
+ static constexpr size_t kLayoutAlignment = Layout::Partial().Alignment();
+
+ // Creates a new CordRepRing.
+ explicit CordRepRing(index_type capacity) : capacity_(capacity) {}
+
+ // Returns true if `index` is a valid index into this instance.
+ bool IsValidIndex(index_type index) const;
+
+ // Debug use only: validates the provided CordRepRing invariants.
+ // Verification of all CordRepRing methods can be enabled by defining
+ // EXTRA_CORD_RING_VALIDATION, i.e.: `--copts=-DEXTRA_CORD_RING_VALIDATION`
+ // Verification is VERY expensive, so only do it for debugging purposes.
+ static CordRepRing* Validate(CordRepRing* rep, const char* file = nullptr,
+ int line = 0);
+
+ // Allocates a CordRepRing large enough to hold `capacity + extra' entries.
+ // The returned capacity may be larger if the allocated memory allows for it.
+ // The maximum capacity of a CordRepRing is capped at kMaxCapacity.
+ // Throws `std::length_error` if `capacity + extra' exceeds kMaxCapacity.
+ static CordRepRing* New(size_t capacity, size_t extra);
+
+ // Deallocates (but does not destroy) the provided ring buffer.
+ static void Delete(CordRepRing* rep);
+
+ // Destroys the provided ring buffer, decrementing the reference count of all
+ // contained child CordReps. The provided 1\`rep` should have a ref count of
// one (pre decrement destroy call observing `refcount.IsOne()`) or zero
// (post decrement destroy call observing `!refcount.Decrement()`).
- static void Destroy(CordRepRing* rep);
-
- // Returns a mutable reference to the logical end position array.
- pos_type* entry_end_pos() {
- return Layout::Partial().Pointer<0>(data_);
- }
-
- // Returns a mutable reference to the child pointer array.
- CordRep** entry_child() {
- return Layout::Partial(capacity()).Pointer<1>(data_);
- }
-
- // Returns a mutable reference to the data offset array.
- offset_type* entry_data_offset() {
- return Layout::Partial(capacity(), capacity()).Pointer<2>(data_);
- }
-
- // Find implementations for the non fast path 0 / length cases.
- Position FindSlow(index_type head, size_t offset) const;
- Position FindTailSlow(index_type head, size_t offset) const;
-
- // Finds the index of the first node that is inside a reasonable distance
- // of the node at `offset` from which we can continue with a linear search.
- template <bool wrap>
- index_type FindBinary(index_type head, index_type tail, size_t offset) const;
-
- // Fills the current (initialized) instance from the provided source, copying
- // entries [head, tail). Adds a reference to copied entries if `ref` is true.
- template <bool ref>
- void Fill(const CordRepRing* src, index_type head, index_type tail);
-
- // Create a copy of 'rep', copying all entries [head, tail), allocating room
- // for `extra` entries. Adds a reference on all copied entries.
- static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail,
- size_t extra = 0);
-
- // Returns a Mutable CordRepRing reference from `rep` with room for at least
- // `extra` additional nodes. Adopts a reference count from `rep`.
- // This function will return `rep` if, and only if:
- // - rep.entries + extra <= rep.capacity
- // - rep.refcount == 1
- // Otherwise, this function will create a new copy of `rep` with additional
- // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance.
- //
- // If a new CordRepRing can not be allocated, or the new capacity would exceed
- // the maxmimum capacity, then the input is consumed only, and an exception is
- // thrown.
- static CordRepRing* Mutable(CordRepRing* rep, size_t extra);
-
- // Slow path for Append(CordRepRing* rep, CordRep* child). This function is
- // exercised if the provided `child` in Append() is not a leaf node, i.e., a
- // ring buffer or old (concat) cord tree.
- static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child);
-
- // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
- static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child,
- size_t offset, size_t length);
-
- // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
- static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child,
- size_t offset, size_t length);
-
- // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is
- // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
- // ring buffer or old (concat) cord tree.
- static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child);
-
- // Slow path for Create(CordRep* child, size_t extra). This function is
- // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
- // ring buffer or old (concat) cord tree.
- static CordRepRing* CreateSlow(CordRep* child, size_t extra);
-
- // Creates a new ring buffer from the provided `child` leaf node. Requires
- // `child` to be FLAT or EXTERNAL. on `rep`.
- // The returned ring buffer has a capacity of at least `1 + extra`
- static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset,
- size_t length, size_t extra);
-
- // Appends or prepends (depending on AddMode) the ring buffer in `ring' to
+ static void Destroy(CordRepRing* rep);
+
+ // Returns a mutable reference to the logical end position array.
+ pos_type* entry_end_pos() {
+ return Layout::Partial().Pointer<0>(data_);
+ }
+
+ // Returns a mutable reference to the child pointer array.
+ CordRep** entry_child() {
+ return Layout::Partial(capacity()).Pointer<1>(data_);
+ }
+
+ // Returns a mutable reference to the data offset array.
+ offset_type* entry_data_offset() {
+ return Layout::Partial(capacity(), capacity()).Pointer<2>(data_);
+ }
+
+ // Find implementations for the non fast path 0 / length cases.
+ Position FindSlow(index_type head, size_t offset) const;
+ Position FindTailSlow(index_type head, size_t offset) const;
+
+ // Finds the index of the first node that is inside a reasonable distance
+ // of the node at `offset` from which we can continue with a linear search.
+ template <bool wrap>
+ index_type FindBinary(index_type head, index_type tail, size_t offset) const;
+
+ // Fills the current (initialized) instance from the provided source, copying
+ // entries [head, tail). Adds a reference to copied entries if `ref` is true.
+ template <bool ref>
+ void Fill(const CordRepRing* src, index_type head, index_type tail);
+
+ // Create a copy of 'rep', copying all entries [head, tail), allocating room
+ // for `extra` entries. Adds a reference on all copied entries.
+ static CordRepRing* Copy(CordRepRing* rep, index_type head, index_type tail,
+ size_t extra = 0);
+
+ // Returns a Mutable CordRepRing reference from `rep` with room for at least
+ // `extra` additional nodes. Adopts a reference count from `rep`.
+ // This function will return `rep` if, and only if:
+ // - rep.entries + extra <= rep.capacity
+ // - rep.refcount == 1
+ // Otherwise, this function will create a new copy of `rep` with additional
+ // capacity to satisfy `extra` extra nodes, and unref the old `rep` instance.
+ //
+ // If a new CordRepRing can not be allocated, or the new capacity would exceed
+ // the maxmimum capacity, then the input is consumed only, and an exception is
+ // thrown.
+ static CordRepRing* Mutable(CordRepRing* rep, size_t extra);
+
+ // Slow path for Append(CordRepRing* rep, CordRep* child). This function is
+ // exercised if the provided `child` in Append() is not a leaf node, i.e., a
+ // ring buffer or old (concat) cord tree.
+ static CordRepRing* AppendSlow(CordRepRing* rep, CordRep* child);
+
+ // Appends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+ static CordRepRing* AppendLeaf(CordRepRing* rep, CordRep* child,
+ size_t offset, size_t length);
+
+ // Prepends the provided leaf node. Requires `child` to be FLAT or EXTERNAL.
+ static CordRepRing* PrependLeaf(CordRepRing* rep, CordRep* child,
+ size_t offset, size_t length);
+
+ // Slow path for Prepend(CordRepRing* rep, CordRep* child). This function is
+ // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+ // ring buffer or old (concat) cord tree.
+ static CordRepRing* PrependSlow(CordRepRing* rep, CordRep* child);
+
+ // Slow path for Create(CordRep* child, size_t extra). This function is
+ // exercised if the provided `child` in Prepend() is not a leaf node, i.e., a
+ // ring buffer or old (concat) cord tree.
+ static CordRepRing* CreateSlow(CordRep* child, size_t extra);
+
+ // Creates a new ring buffer from the provided `child` leaf node. Requires
+ // `child` to be FLAT or EXTERNAL. on `rep`.
+ // The returned ring buffer has a capacity of at least `1 + extra`
+ static CordRepRing* CreateFromLeaf(CordRep* child, size_t offset,
+ size_t length, size_t extra);
+
+ // Appends or prepends (depending on AddMode) the ring buffer in `ring' to
// `rep` starting at `offset` with length `len`.
- template <AddMode mode>
- static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring,
+ template <AddMode mode>
+ static CordRepRing* AddRing(CordRepRing* rep, CordRepRing* ring,
size_t offset, size_t len);
-
- // Increases the data offset for entry `index` by `n`.
- void AddDataOffset(index_type index, size_t n);
-
- // Descreases the length for entry `index` by `n`.
- void SubLength(index_type index, size_t n);
-
- index_type head_;
- index_type tail_;
- index_type capacity_;
- pos_type begin_pos_;
-
- alignas(kLayoutAlignment) char data_[kLayoutAlignment];
-
- friend struct CordRep;
-};
-
-constexpr size_t CordRepRing::AllocSize(size_t capacity) {
- return sizeof(CordRepRing) - sizeof(data_) +
- Layout(capacity, capacity, capacity).AllocSize();
-}
-
-inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) {
- return (end_pos - pos);
-}
-
-inline const char* CordRepRing::GetLeafData(const CordRep* rep) {
- return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base;
-}
-
-inline const char* CordRepRing::GetRepData(const CordRep* rep) {
- if (rep->tag >= FLAT) return rep->flat()->Data();
- if (rep->tag == EXTERNAL) return rep->external()->base;
- return GetLeafData(rep->substring()->child) + rep->substring()->start;
-}
-
-inline CordRepRing::index_type CordRepRing::advance(index_type index) const {
- assert(index < capacity_);
- return ++index == capacity_ ? 0 : index;
-}
-
-inline CordRepRing::index_type CordRepRing::advance(index_type index,
- index_type n) const {
- assert(index < capacity_ && n <= capacity_);
- return (index += n) >= capacity_ ? index - capacity_ : index;
-}
-
-inline CordRepRing::index_type CordRepRing::retreat(index_type index) const {
- assert(index < capacity_);
- return (index > 0 ? index : capacity_) - 1;
-}
-
-inline CordRepRing::index_type CordRepRing::retreat(index_type index,
- index_type n) const {
- assert(index < capacity_ && n <= capacity_);
- return index >= n ? index - n : capacity_ - n + index;
-}
-
-inline y_absl::string_view CordRepRing::entry_data(index_type index) const {
- size_t data_offset = entry_data_offset(index);
- return {GetRepData(entry_child(index)) + data_offset, entry_length(index)};
-}
-
-inline bool CordRepRing::IsValidIndex(index_type index) const {
- if (index >= capacity_) return false;
- return (tail_ > head_) ? (index >= head_ && index < tail_)
- : (index >= head_ || index < tail_);
-}
-
-#ifndef EXTRA_CORD_RING_VALIDATION
-inline CordRepRing* CordRepRing::Validate(CordRepRing* rep,
- const char* /*file*/, int /*line*/) {
- return rep;
-}
-#endif
-
-inline CordRepRing::Position CordRepRing::Find(size_t offset) const {
- assert(offset < length);
- return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset);
-}
-
-inline CordRepRing::Position CordRepRing::Find(index_type head,
- size_t offset) const {
- assert(offset < length);
- assert(IsValidIndex(head) && offset >= entry_start_offset(head));
- return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset);
-}
-
-inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const {
- assert(offset > 0 && offset <= length);
- return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset);
-}
-
-inline CordRepRing::Position CordRepRing::FindTail(index_type head,
- size_t offset) const {
- assert(offset > 0 && offset <= length);
- assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1);
- return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset);
-}
-
-// Now that CordRepRing is defined, we can define CordRep's helper casts:
-inline CordRepRing* CordRep::ring() {
+
+ // Increases the data offset for entry `index` by `n`.
+ void AddDataOffset(index_type index, size_t n);
+
+ // Descreases the length for entry `index` by `n`.
+ void SubLength(index_type index, size_t n);
+
+ index_type head_;
+ index_type tail_;
+ index_type capacity_;
+ pos_type begin_pos_;
+
+ alignas(kLayoutAlignment) char data_[kLayoutAlignment];
+
+ friend struct CordRep;
+};
+
+constexpr size_t CordRepRing::AllocSize(size_t capacity) {
+ return sizeof(CordRepRing) - sizeof(data_) +
+ Layout(capacity, capacity, capacity).AllocSize();
+}
+
+inline constexpr size_t CordRepRing::Distance(pos_type pos, pos_type end_pos) {
+ return (end_pos - pos);
+}
+
+inline const char* CordRepRing::GetLeafData(const CordRep* rep) {
+ return rep->tag != EXTERNAL ? rep->flat()->Data() : rep->external()->base;
+}
+
+inline const char* CordRepRing::GetRepData(const CordRep* rep) {
+ if (rep->tag >= FLAT) return rep->flat()->Data();
+ if (rep->tag == EXTERNAL) return rep->external()->base;
+ return GetLeafData(rep->substring()->child) + rep->substring()->start;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index) const {
+ assert(index < capacity_);
+ return ++index == capacity_ ? 0 : index;
+}
+
+inline CordRepRing::index_type CordRepRing::advance(index_type index,
+ index_type n) const {
+ assert(index < capacity_ && n <= capacity_);
+ return (index += n) >= capacity_ ? index - capacity_ : index;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index) const {
+ assert(index < capacity_);
+ return (index > 0 ? index : capacity_) - 1;
+}
+
+inline CordRepRing::index_type CordRepRing::retreat(index_type index,
+ index_type n) const {
+ assert(index < capacity_ && n <= capacity_);
+ return index >= n ? index - n : capacity_ - n + index;
+}
+
+inline y_absl::string_view CordRepRing::entry_data(index_type index) const {
+ size_t data_offset = entry_data_offset(index);
+ return {GetRepData(entry_child(index)) + data_offset, entry_length(index)};
+}
+
+inline bool CordRepRing::IsValidIndex(index_type index) const {
+ if (index >= capacity_) return false;
+ return (tail_ > head_) ? (index >= head_ && index < tail_)
+ : (index >= head_ || index < tail_);
+}
+
+#ifndef EXTRA_CORD_RING_VALIDATION
+inline CordRepRing* CordRepRing::Validate(CordRepRing* rep,
+ const char* /*file*/, int /*line*/) {
+ return rep;
+}
+#endif
+
+inline CordRepRing::Position CordRepRing::Find(size_t offset) const {
+ assert(offset < length);
+ return (offset == 0) ? Position{head_, 0} : FindSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::Find(index_type head,
+ size_t offset) const {
+ assert(offset < length);
+ assert(IsValidIndex(head) && offset >= entry_start_offset(head));
+ return (offset == 0) ? Position{head_, 0} : FindSlow(head, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(size_t offset) const {
+ assert(offset > 0 && offset <= length);
+ return (offset == length) ? Position{tail_, 0} : FindTailSlow(head_, offset);
+}
+
+inline CordRepRing::Position CordRepRing::FindTail(index_type head,
+ size_t offset) const {
+ assert(offset > 0 && offset <= length);
+ assert(IsValidIndex(head) && offset >= entry_start_offset(head) + 1);
+ return (offset == length) ? Position{tail_, 0} : FindTailSlow(head, offset);
+}
+
+// Now that CordRepRing is defined, we can define CordRep's helper casts:
+inline CordRepRing* CordRep::ring() {
assert(IsRing());
- return static_cast<CordRepRing*>(this);
-}
-
-inline const CordRepRing* CordRep::ring() const {
+ return static_cast<CordRepRing*>(this);
+}
+
+inline const CordRepRing* CordRep::ring() const {
assert(IsRing());
- return static_cast<const CordRepRing*>(this);
-}
-
+ return static_cast<const CordRepRing*>(this);
+}
+
inline bool CordRepRing::IsFlat(y_absl::string_view* fragment) const {
if (entries() == 1) {
if (fragment) *fragment = entry_data(head());
@@ -598,10 +598,10 @@ inline bool CordRepRing::IsFlat(size_t offset, size_t len,
return false;
}
-std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
-
-} // namespace cord_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
-
-#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
+std::ostream& operator<<(std::ostream& s, const CordRepRing& rep);
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
+
+#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_H_
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h
index 3f64d04fae..98ea8c170a 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cord_rep_ring_reader.h
@@ -1,118 +1,118 @@
-// Copyright 2021 The Abseil Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
-#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-
-#include "y_absl/strings/internal/cord_internal.h"
-#include "y_absl/strings/internal/cord_rep_ring.h"
-#include "y_absl/strings/string_view.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace cord_internal {
-
-// CordRepRingReader provides basic navigation over CordRepRing data.
-class CordRepRingReader {
- public:
- // Returns true if this instance is not empty.
- explicit operator bool() const { return ring_ != nullptr; }
-
- // Returns the ring buffer reference for this instance, or nullptr if empty.
- CordRepRing* ring() const { return ring_; }
-
- // Returns the current node index inside the ring buffer for this instance.
- // The returned value is undefined if this instance is empty.
- CordRepRing::index_type index() const { return index_; }
-
+// Copyright 2021 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+#define ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+#include "y_absl/strings/internal/cord_internal.h"
+#include "y_absl/strings/internal/cord_rep_ring.h"
+#include "y_absl/strings/string_view.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace cord_internal {
+
+// CordRepRingReader provides basic navigation over CordRepRing data.
+class CordRepRingReader {
+ public:
+ // Returns true if this instance is not empty.
+ explicit operator bool() const { return ring_ != nullptr; }
+
+ // Returns the ring buffer reference for this instance, or nullptr if empty.
+ CordRepRing* ring() const { return ring_; }
+
+ // Returns the current node index inside the ring buffer for this instance.
+ // The returned value is undefined if this instance is empty.
+ CordRepRing::index_type index() const { return index_; }
+
// Returns the current node inside the ring buffer for this instance.
// The returned value is undefined if this instance is empty.
CordRep* node() const { return ring_->entry_child(index_); }
- // Returns the length of the referenced ring buffer.
- // Requires the current instance to be non empty.
- size_t length() const {
- assert(ring_);
- return ring_->length;
- }
-
- // Returns the end offset of the last navigated-to chunk, which represents the
- // total bytes 'consumed' relative to the start of the ring. The returned
- // value is never zero. For example, initializing a reader with a ring buffer
- // with a first chunk of 19 bytes will return consumed() = 19.
- // Requires the current instance to be non empty.
- size_t consumed() const {
- assert(ring_);
- return ring_->entry_end_offset(index_);
- }
-
- // Returns the number of bytes remaining beyond the last navigated-to chunk.
- // Requires the current instance to be non empty.
- size_t remaining() const {
- assert(ring_);
- return length() - consumed();
- }
-
- // Resets this instance to an empty value
- void Reset() { ring_ = nullptr; }
-
- // Resets this instance to the start of `ring`. `ring` must not be null.
- // Returns a reference into the first chunk of the provided ring.
- y_absl::string_view Reset(CordRepRing* ring) {
- assert(ring);
- ring_ = ring;
- index_ = ring_->head();
- return ring_->entry_data(index_);
- }
-
- // Navigates to the next chunk inside the reference ring buffer.
- // Returns a reference into the navigated-to chunk.
- // Requires remaining() to be non zero.
- y_absl::string_view Next() {
- assert(remaining());
- index_ = ring_->advance(index_);
- return ring_->entry_data(index_);
- }
-
- // Navigates to the chunk at offset `offset`.
- // Returns a reference into the navigated-to chunk, adjusted for the relative
- // position of `offset` into that chunk. For example, calling Seek(13) on a
- // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return
- // a string view into the second chunk starting at offset 3 with a size of 17.
- // Requires `offset` to be less than `length()`
- y_absl::string_view Seek(size_t offset) {
- assert(offset < length());
- size_t current = ring_->entry_end_offset(index_);
- CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head();
- const CordRepRing::Position head = ring_->Find(hint, offset);
- index_ = head.index;
- auto data = ring_->entry_data(head.index);
- data.remove_prefix(head.offset);
- return data;
- }
-
- private:
- CordRepRing* ring_ = nullptr;
- CordRepRing::index_type index_;
-};
-
-} // namespace cord_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
-
-#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
+ // Returns the length of the referenced ring buffer.
+ // Requires the current instance to be non empty.
+ size_t length() const {
+ assert(ring_);
+ return ring_->length;
+ }
+
+ // Returns the end offset of the last navigated-to chunk, which represents the
+ // total bytes 'consumed' relative to the start of the ring. The returned
+ // value is never zero. For example, initializing a reader with a ring buffer
+ // with a first chunk of 19 bytes will return consumed() = 19.
+ // Requires the current instance to be non empty.
+ size_t consumed() const {
+ assert(ring_);
+ return ring_->entry_end_offset(index_);
+ }
+
+ // Returns the number of bytes remaining beyond the last navigated-to chunk.
+ // Requires the current instance to be non empty.
+ size_t remaining() const {
+ assert(ring_);
+ return length() - consumed();
+ }
+
+ // Resets this instance to an empty value
+ void Reset() { ring_ = nullptr; }
+
+ // Resets this instance to the start of `ring`. `ring` must not be null.
+ // Returns a reference into the first chunk of the provided ring.
+ y_absl::string_view Reset(CordRepRing* ring) {
+ assert(ring);
+ ring_ = ring;
+ index_ = ring_->head();
+ return ring_->entry_data(index_);
+ }
+
+ // Navigates to the next chunk inside the reference ring buffer.
+ // Returns a reference into the navigated-to chunk.
+ // Requires remaining() to be non zero.
+ y_absl::string_view Next() {
+ assert(remaining());
+ index_ = ring_->advance(index_);
+ return ring_->entry_data(index_);
+ }
+
+ // Navigates to the chunk at offset `offset`.
+ // Returns a reference into the navigated-to chunk, adjusted for the relative
+ // position of `offset` into that chunk. For example, calling Seek(13) on a
+ // ring buffer containing 2 chunks of 10 and 20 bytes respectively will return
+ // a string view into the second chunk starting at offset 3 with a size of 17.
+ // Requires `offset` to be less than `length()`
+ y_absl::string_view Seek(size_t offset) {
+ assert(offset < length());
+ size_t current = ring_->entry_end_offset(index_);
+ CordRepRing::index_type hint = (offset >= current) ? index_ : ring_->head();
+ const CordRepRing::Position head = ring_->Find(hint, offset);
+ index_ = head.index;
+ auto data = ring_->entry_data(head.index);
+ data.remove_prefix(head.offset);
+ return data;
+ }
+
+ private:
+ CordRepRing* ring_ = nullptr;
+ CordRepRing::index_type index_;
+};
+
+} // namespace cord_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
+
+#endif // ABSL_STRINGS_INTERNAL_CORD_REP_RING_READER_H_
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make
index 06e99346da..d2522532e2 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions/ya.make
@@ -2,13 +2,13 @@
LIBRARY()
-WITHOUT_LICENSE_TEXTS()
-
-OWNER(
- somov
- g:cpp-contrib
-)
+WITHOUT_LICENSE_TEXTS()
+OWNER(
+ somov
+ g:cpp-contrib
+)
+
LICENSE(Apache-2.0)
PEERDIR(
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make
index e181217139..0220a75bd1 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_handle/ya.make
@@ -1,47 +1,47 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
-WITHOUT_LICENSE_TEXTS()
-
-OWNER(
- somov
- g:cpp-contrib
-)
-
-LICENSE(Apache-2.0)
-
-PEERDIR(
- contrib/restricted/abseil-cpp-tstring/y_absl/base
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ somov
+ g:cpp-contrib
+)
+
+LICENSE(Apache-2.0)
+
+PEERDIR(
+ contrib/restricted/abseil-cpp-tstring/y_absl/base
contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/low_level_alloc
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
- contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
contrib/restricted/abseil-cpp-tstring/y_absl/debugging
contrib/restricted/abseil-cpp-tstring/y_absl/debugging/stacktrace
contrib/restricted/abseil-cpp-tstring/y_absl/debugging/symbolize
contrib/restricted/abseil-cpp-tstring/y_absl/demangle
- contrib/restricted/abseil-cpp-tstring/y_absl/numeric
- contrib/restricted/abseil-cpp-tstring/y_absl/strings
+ contrib/restricted/abseil-cpp-tstring/y_absl/numeric
+ contrib/restricted/abseil-cpp-tstring/y_absl/strings
contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal
contrib/restricted/abseil-cpp-tstring/y_absl/synchronization
contrib/restricted/abseil-cpp-tstring/y_absl/synchronization/internal
contrib/restricted/abseil-cpp-tstring/y_absl/time
contrib/restricted/abseil-cpp-tstring/y_absl/time/civil_time
contrib/restricted/abseil-cpp-tstring/y_absl/time/time_zone
-)
-
-ADDINCL(
- GLOBAL contrib/restricted/abseil-cpp-tstring
-)
-
-NO_COMPILER_WARNINGS()
-
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/abseil-cpp-tstring
+)
+
+NO_COMPILER_WARNINGS()
+
SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal)
-
-SRCS(
+
+SRCS(
cordz_handle.cc
-)
-
-END()
+)
+
+END()
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make
index 930eaa8b05..4d749dc50b 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_info/ya.make
@@ -1,30 +1,30 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
-WITHOUT_LICENSE_TEXTS()
-
-OWNER(
- somov
- g:cpp-contrib
-)
-
-LICENSE(Apache-2.0)
-
-PEERDIR(
- contrib/restricted/abseil-cpp-tstring/y_absl/base
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+WITHOUT_LICENSE_TEXTS()
+
+OWNER(
+ somov
+ g:cpp-contrib
+)
+
+LICENSE(Apache-2.0)
+
+PEERDIR(
+ contrib/restricted/abseil-cpp-tstring/y_absl/base
contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/low_level_alloc
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
- contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
- contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/spinlock_wait
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/throw_delegate
+ contrib/restricted/abseil-cpp-tstring/y_absl/base/log_severity
contrib/restricted/abseil-cpp-tstring/y_absl/debugging
contrib/restricted/abseil-cpp-tstring/y_absl/debugging/stacktrace
contrib/restricted/abseil-cpp-tstring/y_absl/debugging/symbolize
contrib/restricted/abseil-cpp-tstring/y_absl/demangle
- contrib/restricted/abseil-cpp-tstring/y_absl/numeric
+ contrib/restricted/abseil-cpp-tstring/y_absl/numeric
contrib/restricted/abseil-cpp-tstring/y_absl/profiling/internal/exponential_biased
- contrib/restricted/abseil-cpp-tstring/y_absl/strings
+ contrib/restricted/abseil-cpp-tstring/y_absl/strings
contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_cord_internal
contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/absl_strings_internal
contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/cordz_functions
@@ -34,18 +34,18 @@ PEERDIR(
contrib/restricted/abseil-cpp-tstring/y_absl/time
contrib/restricted/abseil-cpp-tstring/y_absl/time/civil_time
contrib/restricted/abseil-cpp-tstring/y_absl/time/time_zone
-)
-
-ADDINCL(
- GLOBAL contrib/restricted/abseil-cpp-tstring
-)
-
-NO_COMPILER_WARNINGS()
-
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/abseil-cpp-tstring
+)
+
+NO_COMPILER_WARNINGS()
+
SRCDIR(contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal)
-
-SRCS(
+
+SRCS(
cordz_info.cc
-)
-
-END()
+)
+
+END()
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h
index 12aec3ac11..022633ac82 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/numbers_test_common.h
@@ -170,7 +170,7 @@ inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() {
{"0x1234", true, 16, 0x1234},
- // Base-10 string version.
+ // Base-10 string version.
{"1234", true, 0, 1234},
{nullptr, false, 0, 0},
}};
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt
index 33d60b3d2b..95cff783b8 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/.yandex_meta/licenses.list.txt
@@ -1,20 +1,20 @@
-====================Apache-2.0====================
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-
-====================COPYRIGHT====================
-// Copyright 2017 The Abseil Authors.
-
-
-====================COPYRIGHT====================
-// Copyright 2020 The Abseil Authors.
+====================Apache-2.0====================
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+====================COPYRIGHT====================
+// Copyright 2017 The Abseil Authors.
+
+
+====================COPYRIGHT====================
+// Copyright 2020 The Abseil Authors.
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc
index 8d5c3b61ac..dbd80e7052 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.cc
@@ -1,18 +1,18 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//
// POSIX spec:
// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
//
@@ -26,7 +26,7 @@
#include "y_absl/base/port.h"
#include "y_absl/strings/internal/str_format/float_conversion.h"
-#include "y_absl/strings/numbers.h"
+#include "y_absl/strings/numbers.h"
namespace y_absl {
ABSL_NAMESPACE_BEGIN
@@ -61,179 +61,179 @@ struct IsSigned<y_absl::int128> : std::true_type {};
template <>
struct IsSigned<y_absl::uint128> : std::false_type {};
-// Integral digit printer.
-// Call one of the PrintAs* routines after construction once.
-// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
-class IntDigits {
+// Integral digit printer.
+// Call one of the PrintAs* routines after construction once.
+// Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
+class IntDigits {
public:
- // Print the unsigned integer as octal.
- // Supports unsigned integral types and uint128.
+ // Print the unsigned integer as octal.
+ // Supports unsigned integral types and uint128.
template <typename T>
- void PrintAsOct(T v) {
- static_assert(!IsSigned<T>::value, "");
- char *p = storage_ + sizeof(storage_);
- do {
- *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
- v >>= 3;
- } while (v);
- start_ = p;
- size_ = storage_ + sizeof(storage_) - p;
- }
-
- // Print the signed or unsigned integer as decimal.
- // Supports all integral types.
- template <typename T>
- void PrintAsDec(T v) {
- static_assert(std::is_integral<T>::value, "");
- start_ = storage_;
- size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
- }
-
- void PrintAsDec(int128 v) {
- auto u = static_cast<uint128>(v);
- bool add_neg = false;
- if (v < 0) {
- add_neg = true;
- u = uint128{} - u;
+ void PrintAsOct(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+ do {
+ *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
+ v >>= 3;
+ } while (v);
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
+ }
+
+ // Print the signed or unsigned integer as decimal.
+ // Supports all integral types.
+ template <typename T>
+ void PrintAsDec(T v) {
+ static_assert(std::is_integral<T>::value, "");
+ start_ = storage_;
+ size_ = numbers_internal::FastIntToBuffer(v, storage_) - storage_;
+ }
+
+ void PrintAsDec(int128 v) {
+ auto u = static_cast<uint128>(v);
+ bool add_neg = false;
+ if (v < 0) {
+ add_neg = true;
+ u = uint128{} - u;
}
- PrintAsDec(u, add_neg);
+ PrintAsDec(u, add_neg);
}
- void PrintAsDec(uint128 v, bool add_neg = false) {
- // This function can be sped up if needed. We can call FastIntToBuffer
- // twice, or fix FastIntToBuffer to support uint128.
- char *p = storage_ + sizeof(storage_);
- do {
- p -= 2;
- numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
- v /= 100;
- } while (v);
- if (p[0] == '0') {
- // We printed one too many hexits.
- ++p;
- }
- if (add_neg) {
- *--p = '-';
- }
- size_ = storage_ + sizeof(storage_) - p;
- start_ = p;
+ void PrintAsDec(uint128 v, bool add_neg = false) {
+ // This function can be sped up if needed. We can call FastIntToBuffer
+ // twice, or fix FastIntToBuffer to support uint128.
+ char *p = storage_ + sizeof(storage_);
+ do {
+ p -= 2;
+ numbers_internal::PutTwoDigits(static_cast<size_t>(v % 100), p);
+ v /= 100;
+ } while (v);
+ if (p[0] == '0') {
+ // We printed one too many hexits.
+ ++p;
+ }
+ if (add_neg) {
+ *--p = '-';
+ }
+ size_ = storage_ + sizeof(storage_) - p;
+ start_ = p;
}
- // Print the unsigned integer as hex using lowercase.
- // Supports unsigned integral types and uint128.
+ // Print the unsigned integer as hex using lowercase.
+ // Supports unsigned integral types and uint128.
template <typename T>
- void PrintAsHexLower(T v) {
- static_assert(!IsSigned<T>::value, "");
- char *p = storage_ + sizeof(storage_);
-
- do {
- p -= 2;
- constexpr const char* table = numbers_internal::kHexTable;
- std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
- if (sizeof(T) == 1) break;
- v >>= 8;
- } while (v);
- if (p[0] == '0') {
- // We printed one too many digits.
- ++p;
+ void PrintAsHexLower(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+
+ do {
+ p -= 2;
+ constexpr const char* table = numbers_internal::kHexTable;
+ std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
+ if (sizeof(T) == 1) break;
+ v >>= 8;
+ } while (v);
+ if (p[0] == '0') {
+ // We printed one too many digits.
+ ++p;
}
- start_ = p;
- size_ = storage_ + sizeof(storage_) - p;
- }
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
+ }
- // Print the unsigned integer as hex using uppercase.
- // Supports unsigned integral types and uint128.
+ // Print the unsigned integer as hex using uppercase.
+ // Supports unsigned integral types and uint128.
template <typename T>
- void PrintAsHexUpper(T v) {
- static_assert(!IsSigned<T>::value, "");
- char *p = storage_ + sizeof(storage_);
-
- // kHexTable is only lowercase, so do it manually for uppercase.
- do {
- *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
- v >>= 4;
- } while (v);
- start_ = p;
- size_ = storage_ + sizeof(storage_) - p;
+ void PrintAsHexUpper(T v) {
+ static_assert(!IsSigned<T>::value, "");
+ char *p = storage_ + sizeof(storage_);
+
+ // kHexTable is only lowercase, so do it manually for uppercase.
+ do {
+ *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
+ v >>= 4;
+ } while (v);
+ start_ = p;
+ size_ = storage_ + sizeof(storage_) - p;
}
- // The printed value including the '-' sign if available.
- // For inputs of value `0`, this will return "0"
- string_view with_neg_and_zero() const { return {start_, size_}; }
-
- // The printed value not including the '-' sign.
- // For inputs of value `0`, this will return "".
- string_view without_neg_or_zero() const {
- static_assert('-' < '0', "The check below verifies both.");
- size_t advance = start_[0] <= '0' ? 1 : 0;
- return {start_ + advance, size_ - advance};
+ // The printed value including the '-' sign if available.
+ // For inputs of value `0`, this will return "0"
+ string_view with_neg_and_zero() const { return {start_, size_}; }
+
+ // The printed value not including the '-' sign.
+ // For inputs of value `0`, this will return "".
+ string_view without_neg_or_zero() const {
+ static_assert('-' < '0', "The check below verifies both.");
+ size_t advance = start_[0] <= '0' ? 1 : 0;
+ return {start_ + advance, size_ - advance};
}
- bool is_negative() const { return start_[0] == '-'; }
+ bool is_negative() const { return start_[0] == '-'; }
- private:
- const char *start_;
- size_t size_;
- // Max size: 128 bit value as octal -> 43 digits, plus sign char
- char storage_[128 / 3 + 1 + 1];
+ private:
+ const char *start_;
+ size_t size_;
+ // Max size: 128 bit value as octal -> 43 digits, plus sign char
+ char storage_[128 / 3 + 1 + 1];
};
// Note: 'o' conversions do not have a base indicator, it's just that
// the '#' flag is specified to modify the precision for 'o' conversions.
-string_view BaseIndicator(const IntDigits &as_digits,
- const FormatConversionSpecImpl conv) {
- // always show 0x for %p.
- bool alt = conv.has_alt_flag() ||
- conv.conversion_char() == FormatConversionCharInternal::p;
- bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
- conv.conversion_char() == FormatConversionCharInternal::X ||
- conv.conversion_char() == FormatConversionCharInternal::p);
+string_view BaseIndicator(const IntDigits &as_digits,
+ const FormatConversionSpecImpl conv) {
+ // always show 0x for %p.
+ bool alt = conv.has_alt_flag() ||
+ conv.conversion_char() == FormatConversionCharInternal::p;
+ bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
+ conv.conversion_char() == FormatConversionCharInternal::X ||
+ conv.conversion_char() == FormatConversionCharInternal::p);
// From the POSIX description of '#' flag:
// "For x or X conversion specifiers, a non-zero result shall have
// 0x (or 0X) prefixed to it."
- if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
- return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
- : "0x";
+ if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
+ return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
+ : "0x";
}
return {};
}
-string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
- if (conv.conversion_char() == FormatConversionCharInternal::d ||
- conv.conversion_char() == FormatConversionCharInternal::i) {
+string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
+ if (conv.conversion_char() == FormatConversionCharInternal::d ||
+ conv.conversion_char() == FormatConversionCharInternal::i) {
if (neg) return "-";
- if (conv.has_show_pos_flag()) return "+";
- if (conv.has_sign_col_flag()) return " ";
+ if (conv.has_show_pos_flag()) return "+";
+ if (conv.has_sign_col_flag()) return " ";
}
return {};
}
-bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
+bool ConvertCharImpl(unsigned char v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
size_t fill = 0;
if (conv.width() >= 0) fill = conv.width();
ReducePadding(1, &fill);
- if (!conv.has_left_flag()) sink->Append(fill, ' ');
+ if (!conv.has_left_flag()) sink->Append(fill, ' ');
sink->Append(1, v);
- if (conv.has_left_flag()) sink->Append(fill, ' ');
+ if (conv.has_left_flag()) sink->Append(fill, ' ');
return true;
}
-bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
// Print as a sequence of Substrings:
// [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
size_t fill = 0;
if (conv.width() >= 0) fill = conv.width();
- string_view formatted = as_digits.without_neg_or_zero();
+ string_view formatted = as_digits.without_neg_or_zero();
ReducePadding(formatted, &fill);
- string_view sign = SignColumn(as_digits.is_negative(), conv);
+ string_view sign = SignColumn(as_digits.is_negative(), conv);
ReducePadding(sign, &fill);
- string_view base_indicator = BaseIndicator(as_digits, conv);
+ string_view base_indicator = BaseIndicator(as_digits, conv);
ReducePadding(base_indicator, &fill);
int precision = conv.precision();
@@ -241,8 +241,8 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
if (!precision_specified)
precision = 1;
- if (conv.has_alt_flag() &&
- conv.conversion_char() == FormatConversionCharInternal::o) {
+ if (conv.has_alt_flag() &&
+ conv.conversion_char() == FormatConversionCharInternal::o) {
// From POSIX description of the '#' (alt) flag:
// "For o conversion, it increases the precision (if necessary) to
// force the first digit of the result to be zero."
@@ -255,13 +255,13 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
size_t num_zeroes = Excess(formatted.size(), precision);
ReducePadding(num_zeroes, &fill);
- size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
- size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
+ size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
+ size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
// From POSIX description of the '0' (zero) flag:
// "For d, i, o, u, x, and X conversion specifiers, if a precision
// is specified, the '0' flag is ignored."
- if (!precision_specified && conv.has_zero_flag()) {
+ if (!precision_specified && conv.has_zero_flag()) {
num_zeroes += num_left_spaces;
num_left_spaces = 0;
}
@@ -276,97 +276,97 @@ bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
}
template <typename T>
-bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
- using U = typename MakeUnsigned<T>::type;
- IntDigits as_digits;
-
- // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
- // it to complain about a switch/case type mismatch, even though both are
- // FormatConverionChar. Likely this is because at this point
- // FormatConversionChar is declared, but not defined.
- switch (static_cast<uint8_t>(conv.conversion_char())) {
- case static_cast<uint8_t>(FormatConversionCharInternal::c):
- return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
-
- case static_cast<uint8_t>(FormatConversionCharInternal::o):
- as_digits.PrintAsOct(static_cast<U>(v));
- break;
-
- case static_cast<uint8_t>(FormatConversionCharInternal::x):
- as_digits.PrintAsHexLower(static_cast<U>(v));
- break;
- case static_cast<uint8_t>(FormatConversionCharInternal::X):
- as_digits.PrintAsHexUpper(static_cast<U>(v));
- break;
-
- case static_cast<uint8_t>(FormatConversionCharInternal::u):
- as_digits.PrintAsDec(static_cast<U>(v));
- break;
-
- case static_cast<uint8_t>(FormatConversionCharInternal::d):
- case static_cast<uint8_t>(FormatConversionCharInternal::i):
- as_digits.PrintAsDec(v);
- break;
-
- case static_cast<uint8_t>(FormatConversionCharInternal::a):
- case static_cast<uint8_t>(FormatConversionCharInternal::e):
- case static_cast<uint8_t>(FormatConversionCharInternal::f):
- case static_cast<uint8_t>(FormatConversionCharInternal::g):
- case static_cast<uint8_t>(FormatConversionCharInternal::A):
- case static_cast<uint8_t>(FormatConversionCharInternal::E):
- case static_cast<uint8_t>(FormatConversionCharInternal::F):
- case static_cast<uint8_t>(FormatConversionCharInternal::G):
- return ConvertFloatImpl(static_cast<double>(v), conv, sink);
-
- default:
- ABSL_INTERNAL_ASSUME(false);
+bool ConvertIntArg(T v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ using U = typename MakeUnsigned<T>::type;
+ IntDigits as_digits;
+
+ // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
+ // it to complain about a switch/case type mismatch, even though both are
+ // FormatConverionChar. Likely this is because at this point
+ // FormatConversionChar is declared, but not defined.
+ switch (static_cast<uint8_t>(conv.conversion_char())) {
+ case static_cast<uint8_t>(FormatConversionCharInternal::c):
+ return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::o):
+ as_digits.PrintAsOct(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::x):
+ as_digits.PrintAsHexLower(static_cast<U>(v));
+ break;
+ case static_cast<uint8_t>(FormatConversionCharInternal::X):
+ as_digits.PrintAsHexUpper(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::u):
+ as_digits.PrintAsDec(static_cast<U>(v));
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::d):
+ case static_cast<uint8_t>(FormatConversionCharInternal::i):
+ as_digits.PrintAsDec(v);
+ break;
+
+ case static_cast<uint8_t>(FormatConversionCharInternal::a):
+ case static_cast<uint8_t>(FormatConversionCharInternal::e):
+ case static_cast<uint8_t>(FormatConversionCharInternal::f):
+ case static_cast<uint8_t>(FormatConversionCharInternal::g):
+ case static_cast<uint8_t>(FormatConversionCharInternal::A):
+ case static_cast<uint8_t>(FormatConversionCharInternal::E):
+ case static_cast<uint8_t>(FormatConversionCharInternal::F):
+ case static_cast<uint8_t>(FormatConversionCharInternal::G):
+ return ConvertFloatImpl(static_cast<double>(v), conv, sink);
+
+ default:
+ ABSL_INTERNAL_ASSUME(false);
}
- if (conv.is_basic()) {
- sink->Append(as_digits.with_neg_and_zero());
- return true;
+ if (conv.is_basic()) {
+ sink->Append(as_digits.with_neg_and_zero());
+ return true;
}
- return ConvertIntImplInnerSlow(as_digits, conv, sink);
+ return ConvertIntImplInnerSlow(as_digits, conv, sink);
}
template <typename T>
-bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
- return FormatConversionCharIsFloat(conv.conversion_char()) &&
+bool ConvertFloatArg(T v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ return FormatConversionCharIsFloat(conv.conversion_char()) &&
ConvertFloatImpl(v, conv, sink);
}
-inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
+inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
- if (conv.is_basic()) {
+ if (conv.is_basic()) {
sink->Append(v);
return true;
}
return sink->PutPaddedString(v, conv.width(), conv.precision(),
- conv.has_left_flag());
+ conv.has_left_flag());
}
} // namespace
// ==================== Strings ====================
-StringConvertResult FormatConvertImpl(const TString &v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(const TString &v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
-StringConvertResult FormatConvertImpl(string_view v,
- const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
+StringConvertResult FormatConvertImpl(string_view v,
+ const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
return {ConvertStringArg(v, conv, sink)};
}
-ArgConvertResult<FormatConversionCharSetUnion(
- FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
-FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
- FormatSinkImpl *sink) {
- if (conv.conversion_char() == FormatConversionCharInternal::p)
+ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl *sink) {
+ if (conv.conversion_char() == FormatConversionCharInternal::p)
return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
size_t len;
if (v == nullptr) {
@@ -381,99 +381,99 @@ FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
}
// ==================== Raw pointers ====================
-ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
- VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+ VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
if (!v.value) {
sink->Append("(nil)");
return {true};
}
- IntDigits as_digits;
- as_digits.PrintAsHexLower(v.value);
- return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
+ IntDigits as_digits;
+ as_digits.PrintAsHexLower(v.value);
+ return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
}
// ==================== Floats ====================
-FloatingConvertResult FormatConvertImpl(float v,
- const FormatConversionSpecImpl conv,
+FloatingConvertResult FormatConvertImpl(float v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
-FloatingConvertResult FormatConvertImpl(double v,
- const FormatConversionSpecImpl conv,
+FloatingConvertResult FormatConvertImpl(double v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
FloatingConvertResult FormatConvertImpl(long double v,
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertFloatArg(v, conv, sink)};
}
// ==================== Chars ====================
-IntegralConvertResult FormatConvertImpl(char v,
- const FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(char v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(signed char v,
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned char v,
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
// ==================== Ints ====================
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(int v,
- const FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(int v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
-IntegralConvertResult FormatConvertImpl(unsigned v,
- const FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(long v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(y_absl::int128 v,
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
IntegralConvertResult FormatConvertImpl(y_absl::uint128 v,
- const FormatConversionSpecImpl conv,
+ const FormatConversionSpecImpl conv,
FormatSinkImpl *sink) {
return {ConvertIntArg(v, conv, sink)};
}
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h
index 59b7bcc727..fee261cbe3 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/arg.h
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
@@ -24,7 +24,7 @@
#include <memory>
#include <sstream>
#include <util/generic/string.h>
-#include <util/stream/str.h>
+#include <util/stream/str.h>
#include <type_traits>
#include "y_absl/base/port.h"
@@ -40,52 +40,52 @@ class Cord;
class FormatCountCapture;
class FormatSink;
-template <y_absl::FormatConversionCharSet C>
-struct FormatConvertResult;
-class FormatConversionSpec;
-
+template <y_absl::FormatConversionCharSet C>
+struct FormatConvertResult;
+class FormatConversionSpec;
+
namespace str_format_internal {
template <typename T, typename = void>
struct HasUserDefinedConvert : std::false_type {};
template <typename T>
-struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
- std::declval<const T&>(),
- std::declval<const FormatConversionSpec&>(),
- std::declval<FormatSink*>()))>>
- : std::true_type {};
-
-void AbslFormatConvert(); // Stops the lexical name lookup
-template <typename T>
-auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
- FormatSinkImpl* sink)
- -> decltype(AbslFormatConvert(v,
- std::declval<const FormatConversionSpec&>(),
- std::declval<FormatSink*>())) {
- using FormatConversionSpecT =
- y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
- using FormatSinkT =
- y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
- auto fcs = conv.Wrap<FormatConversionSpecT>();
- auto fs = sink->Wrap<FormatSinkT>();
- return AbslFormatConvert(v, fcs, &fs);
-}
+struct HasUserDefinedConvert<T, void_t<decltype(AbslFormatConvert(
+ std::declval<const T&>(),
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>()))>>
+ : std::true_type {};
+void AbslFormatConvert(); // Stops the lexical name lookup
template <typename T>
+auto FormatConvertImpl(const T& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink)
+ -> decltype(AbslFormatConvert(v,
+ std::declval<const FormatConversionSpec&>(),
+ std::declval<FormatSink*>())) {
+ using FormatConversionSpecT =
+ y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatConversionSpec>;
+ using FormatSinkT =
+ y_absl::enable_if_t<sizeof(const T& (*)()) != 0, FormatSink>;
+ auto fcs = conv.Wrap<FormatConversionSpecT>();
+ auto fs = sink->Wrap<FormatSinkT>();
+ return AbslFormatConvert(v, fcs, &fs);
+}
+
+template <typename T>
class StreamedWrapper;
// If 'v' can be converted (in the printf sense) according to 'conv',
// then convert it, appending to `sink` and return `true`.
// Otherwise fail and return `false`.
-// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
-// as an extension mechanism. These FormatConvertImpl functions are the default
-// implementations.
-// The ADL search is augmented via the 'Sink*' parameter, which also
-// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
-// functions in the namespaces associated with 'v'.
-
+// AbslFormatConvert(v, conv, sink) is intended to be found by ADL on 'v'
+// as an extension mechanism. These FormatConvertImpl functions are the default
+// implementations.
+// The ADL search is augmented via the 'Sink*' parameter, which also
+// serves as a disambiguator to reject possible unintended 'AbslFormatConvert'
+// functions in the namespaces associated with 'v'.
+
// Raw pointers.
struct VoidPtr {
VoidPtr() = default;
@@ -96,33 +96,33 @@ struct VoidPtr {
uintptr_t value;
};
-template <FormatConversionCharSet C>
-struct ArgConvertResult {
- bool value;
-};
-
-template <FormatConversionCharSet C>
-constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
- return C;
-}
-
-template <FormatConversionCharSet C>
-constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
- return C;
-}
-
-using StringConvertResult =
- ArgConvertResult<FormatConversionCharSetInternal::s>;
-ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
- VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
-
+template <FormatConversionCharSet C>
+struct ArgConvertResult {
+ bool value;
+};
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(FormatConvertResult<C>) {
+ return C;
+}
+
+template <FormatConversionCharSet C>
+constexpr FormatConversionCharSet ExtractCharSet(ArgConvertResult<C>) {
+ return C;
+}
+
+using StringConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::s>;
+ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
+ VoidPtr v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
+
// Strings.
-StringConvertResult FormatConvertImpl(const TString& v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
-StringConvertResult FormatConvertImpl(string_view v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(const TString& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+StringConvertResult FormatConvertImpl(string_view v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
#if defined(ABSL_HAVE_STD_STRING_VIEW) && !defined(ABSL_USES_STD_STRING_VIEW)
inline StringConvertResult FormatConvertImpl(std::string_view v,
FormatConversionSpecImpl conv,
@@ -131,17 +131,17 @@ inline StringConvertResult FormatConvertImpl(std::string_view v,
}
#endif // ABSL_HAVE_STD_STRING_VIEW && !ABSL_USES_STD_STRING_VIEW
-ArgConvertResult<FormatConversionCharSetUnion(
- FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
-FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
- FormatSinkImpl* sink);
-
-template <class AbslCord, typename std::enable_if<std::is_same<
- AbslCord, y_absl::Cord>::value>::type* = nullptr>
-StringConvertResult FormatConvertImpl(const AbslCord& value,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* sink) {
- bool is_left = conv.has_left_flag();
+ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
+FormatConvertImpl(const char* v, const FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink);
+
+template <class AbslCord, typename std::enable_if<std::is_same<
+ AbslCord, y_absl::Cord>::value>::type* = nullptr>
+StringConvertResult FormatConvertImpl(const AbslCord& value,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
+ bool is_left = conv.has_left_flag();
size_t space_remaining = 0;
int width = conv.width();
@@ -174,63 +174,63 @@ StringConvertResult FormatConvertImpl(const AbslCord& value,
return {true};
}
-using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
- FormatConversionCharSetInternal::c,
- FormatConversionCharSetInternal::kNumeric,
- FormatConversionCharSetInternal::kStar)>;
-using FloatingConvertResult =
- ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
+using IntegralConvertResult = ArgConvertResult<FormatConversionCharSetUnion(
+ FormatConversionCharSetInternal::c,
+ FormatConversionCharSetInternal::kNumeric,
+ FormatConversionCharSetInternal::kStar)>;
+using FloatingConvertResult =
+ ArgConvertResult<FormatConversionCharSetInternal::kFloating>;
// Floats.
-FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
+FloatingConvertResult FormatConvertImpl(float v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
+FloatingConvertResult FormatConvertImpl(double v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-FloatingConvertResult FormatConvertImpl(long double v,
- FormatConversionSpecImpl conv,
+FloatingConvertResult FormatConvertImpl(long double v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Chars.
-IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(char v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(signed char v,
- FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(signed char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned char v,
- FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(unsigned char v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
// Ints.
IntegralConvertResult FormatConvertImpl(short v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(int v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(unsigned v,
- FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(unsigned v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(long long v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT
- FormatConversionSpecImpl conv,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(int128 v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
-IntegralConvertResult FormatConvertImpl(uint128 v,
- FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(uint128 v,
+ FormatConversionSpecImpl conv,
FormatSinkImpl* sink);
template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0>
-IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
+IntegralConvertResult FormatConvertImpl(T v, FormatConversionSpecImpl conv,
FormatSinkImpl* sink) {
return FormatConvertImpl(static_cast<int>(v), conv, sink);
}
@@ -241,41 +241,41 @@ template <typename T>
typename std::enable_if<std::is_enum<T>::value &&
!HasUserDefinedConvert<T>::value,
IntegralConvertResult>::type
-FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
+FormatConvertImpl(T v, FormatConversionSpecImpl conv, FormatSinkImpl* sink);
template <typename T>
-StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
- FormatConversionSpecImpl conv,
- FormatSinkImpl* out) {
- TString buf;
- TStringOutput oss(buf);
+StringConvertResult FormatConvertImpl(const StreamedWrapper<T>& v,
+ FormatConversionSpecImpl conv,
+ FormatSinkImpl* out) {
+ TString buf;
+ TStringOutput oss(buf);
oss << v.v_;
- if (!buf) return {false};
- return str_format_internal::FormatConvertImpl(buf, conv, out);
+ if (!buf) return {false};
+ return str_format_internal::FormatConvertImpl(buf, conv, out);
}
// Use templates and dependent types to delay evaluation of the function
// until after FormatCountCapture is fully defined.
struct FormatCountCaptureHelper {
template <class T = int>
- static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
- const FormatCountCapture& v, FormatConversionSpecImpl conv,
- FormatSinkImpl* sink) {
+ static ArgConvertResult<FormatConversionCharSetInternal::n> ConvertHelper(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
const y_absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v;
- if (conv.conversion_char() !=
- str_format_internal::FormatConversionCharInternal::n) {
- return {false};
- }
+ if (conv.conversion_char() !=
+ str_format_internal::FormatConversionCharInternal::n) {
+ return {false};
+ }
*v2.p_ = static_cast<int>(sink->size());
return {true};
}
};
template <class T = int>
-ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
- const FormatCountCapture& v, FormatConversionSpecImpl conv,
- FormatSinkImpl* sink) {
+ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
+ const FormatCountCapture& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* sink) {
return FormatCountCaptureHelper::ConvertHelper(v, conv, sink);
}
@@ -284,13 +284,13 @@ ArgConvertResult<FormatConversionCharSetInternal::n> FormatConvertImpl(
struct FormatArgImplFriend {
template <typename Arg>
static bool ToInt(Arg arg, int* out) {
- // A value initialized FormatConversionSpecImpl has a `none` conv, which
- // tells the dispatcher to run the `int` conversion.
+ // A value initialized FormatConversionSpecImpl has a `none` conv, which
+ // tells the dispatcher to run the `int` conversion.
return arg.dispatcher_(arg.data_, {}, out);
}
template <typename Arg>
- static bool Convert(Arg arg, FormatConversionSpecImpl conv,
+ static bool Convert(Arg arg, FormatConversionSpecImpl conv,
FormatSinkImpl* out) {
return arg.dispatcher_(arg.data_, conv, out);
}
@@ -301,15 +301,15 @@ struct FormatArgImplFriend {
}
};
-template <typename Arg>
-constexpr FormatConversionCharSet ArgumentToConv() {
- return y_absl::str_format_internal::ExtractCharSet(
- decltype(str_format_internal::FormatConvertImpl(
- std::declval<const Arg&>(),
- std::declval<const FormatConversionSpecImpl&>(),
- std::declval<FormatSinkImpl*>())){});
-}
-
+template <typename Arg>
+constexpr FormatConversionCharSet ArgumentToConv() {
+ return y_absl::str_format_internal::ExtractCharSet(
+ decltype(str_format_internal::FormatConvertImpl(
+ std::declval<const Arg&>(),
+ std::declval<const FormatConversionSpecImpl&>(),
+ std::declval<FormatSinkImpl*>())){});
+}
+
// A type-erased handle to a format argument.
class FormatArgImpl {
private:
@@ -323,7 +323,7 @@ class FormatArgImpl {
char buf[kInlinedSpace];
};
- using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
+ using Dispatcher = bool (*)(Data, FormatConversionSpecImpl, void* out);
template <typename T>
struct store_by_value
@@ -465,20 +465,20 @@ class FormatArgImpl {
}
template <typename T>
- static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
+ static bool Dispatch(Data arg, FormatConversionSpecImpl spec, void* out) {
// A `none` conv indicates that we want the `int` conversion.
- if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
- FormatConversionCharInternal::kNone)) {
+ if (ABSL_PREDICT_FALSE(spec.conversion_char() ==
+ FormatConversionCharInternal::kNone)) {
return ToInt<T>(arg, static_cast<int*>(out), std::is_integral<T>(),
std::is_enum<T>());
}
- if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
- spec.conversion_char()))) {
- return false;
- }
+ if (ABSL_PREDICT_FALSE(!Contains(ArgumentToConv<T>(),
+ spec.conversion_char()))) {
+ return false;
+ }
return str_format_internal::FormatConvertImpl(
- Manager<T>::Value(arg), spec,
- static_cast<FormatSinkImpl*>(out))
+ Manager<T>::Value(arg), spec,
+ static_cast<FormatSinkImpl*>(out))
.value;
}
@@ -486,9 +486,9 @@ class FormatArgImpl {
Dispatcher dispatcher_;
};
-#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
- E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
- void*)
+#define ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(T, E) \
+ E template bool FormatArgImpl::Dispatch<T>(Data, FormatConversionSpecImpl, \
+ void*)
#define ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_(...) \
ABSL_INTERNAL_FORMAT_DISPATCH_INSTANTIATE_(str_format_internal::VoidPtr, \
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc
index 211ce25dea..5a62088bff 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.cc
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "y_absl/strings/internal/str_format/bind.h"
#include <cerrno>
@@ -160,7 +160,7 @@ class SummarizingConverter {
<< FormatConversionSpecImplFriend::FlagsToString(bound);
if (bound.width() >= 0) ss << bound.width();
if (bound.precision() >= 0) ss << "." << bound.precision();
- ss << bound.conversion_char() << "}";
+ ss << bound.conversion_char() << "}";
Append(ss.str());
return true;
}
@@ -234,7 +234,7 @@ int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
errno = sink.error();
return -1;
}
- if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+ if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
errno = EFBIG;
return -1;
}
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h
index 3966610710..f0e73a6db2 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/bind.h
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
@@ -33,7 +33,7 @@ class UntypedFormatSpec;
namespace str_format_internal {
-class BoundConversion : public FormatConversionSpecImpl {
+class BoundConversion : public FormatConversionSpecImpl {
public:
const FormatArgImpl* arg() const { return arg_; }
void set_arg(const FormatArgImpl* a) { arg_ = a; }
@@ -74,7 +74,7 @@ class UntypedFormatSpecImpl {
size_t size_;
};
-template <typename T, FormatConversionCharSet...>
+template <typename T, FormatConversionCharSet...>
struct MakeDependent {
using type = T;
};
@@ -82,7 +82,7 @@ struct MakeDependent {
// Implicitly convertible from `const char*`, `string_view`, and the
// `ExtendedParsedFormat` type. This abstraction allows all format functions to
// operate on any without providing too many overloads.
-template <FormatConversionCharSet... Args>
+template <FormatConversionCharSet... Args>
class FormatSpecTemplate
: public MakeDependent<UntypedFormatSpec, Args...>::type {
using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type;
@@ -90,11 +90,11 @@ class FormatSpecTemplate
public:
#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
- // Honeypot overload for when the string is not constexpr.
+ // Honeypot overload for when the string is not constexpr.
// We use the 'unavailable' attribute to give a better compiler error than
// just 'method is deleted'.
FormatSpecTemplate(...) // NOLINT
- __attribute__((unavailable("Format string is not constexpr.")));
+ __attribute__((unavailable("Format string is not constexpr.")));
// Honeypot overload for when the format is constexpr and invalid.
// We use the 'unavailable' attribute to give a better compiler error than
@@ -119,11 +119,11 @@ class FormatSpecTemplate
// Good format overload.
FormatSpecTemplate(const char* s) // NOLINT
- __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
+ __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
: Base(s) {}
FormatSpecTemplate(string_view s) // NOLINT
- __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
+ __attribute__((enable_if(ValidFormatImpl<Args...>(s), "bad format trap")))
: Base(s) {}
#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
@@ -133,11 +133,11 @@ class FormatSpecTemplate
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
- template <
- FormatConversionCharSet... C,
- typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
- typename = typename std::enable_if<AllOf(Contains(Args,
- C)...)>::type>
+ template <
+ FormatConversionCharSet... C,
+ typename = typename std::enable_if<sizeof...(C) == sizeof...(Args)>::type,
+ typename = typename std::enable_if<AllOf(Contains(Args,
+ C)...)>::type>
FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT
: Base(&pc) {}
};
@@ -204,9 +204,9 @@ class StreamedWrapper {
private:
template <typename S>
- friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
- const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
- FormatSinkImpl* out);
+ friend ArgConvertResult<FormatConversionCharSetInternal::s> FormatConvertImpl(
+ const StreamedWrapper<S>& v, FormatConversionSpecImpl conv,
+ FormatSinkImpl* out);
const T& v_;
};
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h
index 7c530d2507..ba3b3d02f3 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/checker.h
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
@@ -46,14 +46,14 @@ constexpr bool ContainsChar(const char* chars, char c) {
// A constexpr compatible list of Convs.
struct ConvList {
- const FormatConversionCharSet* array;
+ const FormatConversionCharSet* array;
int count;
// We do the bound check here to avoid having to do it on the callers.
- // Returning an empty FormatConversionCharSet has the same effect as
- // short circuiting because it will never match any conversion.
- constexpr FormatConversionCharSet operator[](int i) const {
- return i < count ? array[i] : FormatConversionCharSet{};
+ // Returning an empty FormatConversionCharSet has the same effect as
+ // short circuiting because it will never match any conversion.
+ constexpr FormatConversionCharSet operator[](int i) const {
+ return i < count ? array[i] : FormatConversionCharSet{};
}
constexpr ConvList without_front() const {
@@ -64,7 +64,7 @@ struct ConvList {
template <size_t count>
struct ConvListT {
// Make sure the array has size > 0.
- FormatConversionCharSet list[count ? count : 1];
+ FormatConversionCharSet list[count ? count : 1];
};
constexpr char GetChar(string_view str, size_t index) {
@@ -317,7 +317,7 @@ class FormatParser {
ConvList args_;
};
-template <FormatConversionCharSet... C>
+template <FormatConversionCharSet... C>
constexpr bool ValidFormatImpl(string_view format) {
return FormatParser(format,
{ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)})
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc
index f2a4169ae7..13c452cb8e 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.cc
@@ -33,40 +33,40 @@ TString FlagsToString(Flags v) {
return s;
}
-#define ABSL_INTERNAL_X_VAL(id) \
- constexpr y_absl::FormatConversionChar FormatConversionCharInternal::id;
-ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
-#undef ABSL_INTERNAL_X_VAL
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr y_absl::FormatConversionChar FormatConversionCharInternal::kNone;
-
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
- constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
-ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
-#undef ABSL_INTERNAL_CHAR_SET_CASE
-
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
-// NOLINTNEXTLINE(readability-redundant-declaration)
-constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
-
-bool FormatSinkImpl::PutPaddedString(string_view value, int width,
- int precision, bool left) {
+#define ABSL_INTERNAL_X_VAL(id) \
+ constexpr y_absl::FormatConversionChar FormatConversionCharInternal::id;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr y_absl::FormatConversionChar FormatConversionCharInternal::kNone;
+
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ constexpr FormatConversionCharSet FormatConversionCharSetInternal::c;
+ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
+#undef ABSL_INTERNAL_CHAR_SET_CASE
+
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kStar;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kIntegral;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kFloating;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kNumeric;
+// NOLINTNEXTLINE(readability-redundant-declaration)
+constexpr FormatConversionCharSet FormatConversionCharSetInternal::kPointer;
+
+bool FormatSinkImpl::PutPaddedString(string_view value, int width,
+ int precision, bool left) {
size_t space_remaining = 0;
- if (width >= 0) space_remaining = width;
- size_t n = value.size();
- if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
- string_view shown(value.data(), n);
+ if (width >= 0) space_remaining = width;
+ size_t n = value.size();
+ if (precision >= 0) n = std::min(n, static_cast<size_t>(precision));
+ string_view shown(value.data(), n);
space_remaining = Excess(shown.size(), space_remaining);
- if (!left) Append(space_remaining, ' ');
+ if (!left) Append(space_remaining, ' ');
Append(shown);
- if (left) Append(space_remaining, ' ');
+ if (left) Append(space_remaining, ' ');
return true;
}
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h
index e5de5cb6a1..1548d56578 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/extension.h
@@ -24,16 +24,16 @@
#include "y_absl/base/config.h"
#include "y_absl/base/port.h"
-#include "y_absl/meta/type_traits.h"
+#include "y_absl/meta/type_traits.h"
#include "y_absl/strings/internal/str_format/output.h"
#include "y_absl/strings/string_view.h"
namespace y_absl {
ABSL_NAMESPACE_BEGIN
-
-enum class FormatConversionChar : uint8_t;
-enum class FormatConversionCharSet : uint64_t;
-
+
+enum class FormatConversionChar : uint8_t;
+enum class FormatConversionCharSet : uint64_t;
+
namespace str_format_internal {
class FormatRawSinkImpl {
@@ -107,7 +107,7 @@ class FormatSinkImpl {
size_t size() const { return size_; }
// Put 'v' to 'sink' with specified width, precision, and left flag.
- bool PutPaddedString(string_view v, int width, int precision, bool left);
+ bool PutPaddedString(string_view v, int width, int precision, bool left);
template <typename T>
T Wrap() {
@@ -158,7 +158,7 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) {
// clang-format off
#define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
/* text */ \
- X_VAL(c) X_SEP X_VAL(s) X_SEP \
+ X_VAL(c) X_SEP X_VAL(s) X_SEP \
/* ints */ \
X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
@@ -167,39 +167,39 @@ inline std::ostream& operator<<(std::ostream& os, Flags v) {
X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
/* misc */ \
X_VAL(n) X_SEP X_VAL(p)
-// clang-format on
-
-// This type should not be referenced, it exists only to provide labels
-// internally that match the values declared in FormatConversionChar in
-// str_format.h. This is meant to allow internal libraries to use the same
-// declared interface type as the public interface
-// (y_absl::StrFormatConversionChar) while keeping the definition in a public
-// header.
-// Internal libraries should use the form
-// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
-// comparisons. Use in switch statements is not recommended due to a bug in how
-// gcc 4.9 -Wswitch handles declared but undefined enums.
-struct FormatConversionCharInternal {
- FormatConversionCharInternal() = delete;
-
- private:
- // clang-format off
- enum class Enum : uint8_t {
- c, s, // text
+// clang-format on
+
+// This type should not be referenced, it exists only to provide labels
+// internally that match the values declared in FormatConversionChar in
+// str_format.h. This is meant to allow internal libraries to use the same
+// declared interface type as the public interface
+// (y_absl::StrFormatConversionChar) while keeping the definition in a public
+// header.
+// Internal libraries should use the form
+// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
+// comparisons. Use in switch statements is not recommended due to a bug in how
+// gcc 4.9 -Wswitch handles declared but undefined enums.
+struct FormatConversionCharInternal {
+ FormatConversionCharInternal() = delete;
+
+ private:
+ // clang-format off
+ enum class Enum : uint8_t {
+ c, s, // text
d, i, o, u, x, X, // int
f, F, e, E, g, G, a, A, // float
n, p, // misc
- kNone
- };
- // clang-format on
- public:
-#define ABSL_INTERNAL_X_VAL(id) \
- static constexpr FormatConversionChar id = \
- static_cast<FormatConversionChar>(Enum::id);
- ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
-#undef ABSL_INTERNAL_X_VAL
- static constexpr FormatConversionChar kNone =
- static_cast<FormatConversionChar>(Enum::kNone);
+ kNone
+ };
+ // clang-format on
+ public:
+#define ABSL_INTERNAL_X_VAL(id) \
+ static constexpr FormatConversionChar id = \
+ static_cast<FormatConversionChar>(Enum::id);
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
+#undef ABSL_INTERNAL_X_VAL
+ static constexpr FormatConversionChar kNone =
+ static_cast<FormatConversionChar>(Enum::kNone);
};
// clang-format on
@@ -207,54 +207,54 @@ inline FormatConversionChar FormatConversionCharFromChar(char c) {
switch (c) {
#define ABSL_INTERNAL_X_VAL(id) \
case #id[0]: \
- return FormatConversionCharInternal::id;
+ return FormatConversionCharInternal::id;
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
#undef ABSL_INTERNAL_X_VAL
}
- return FormatConversionCharInternal::kNone;
+ return FormatConversionCharInternal::kNone;
}
inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
- if (c == FormatConversionCharInternal::X ||
- c == FormatConversionCharInternal::F ||
- c == FormatConversionCharInternal::E ||
- c == FormatConversionCharInternal::G ||
- c == FormatConversionCharInternal::A) {
- return true;
- } else {
- return false;
+ if (c == FormatConversionCharInternal::X ||
+ c == FormatConversionCharInternal::F ||
+ c == FormatConversionCharInternal::E ||
+ c == FormatConversionCharInternal::G ||
+ c == FormatConversionCharInternal::A) {
+ return true;
+ } else {
+ return false;
}
}
inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
- if (c == FormatConversionCharInternal::a ||
- c == FormatConversionCharInternal::e ||
- c == FormatConversionCharInternal::f ||
- c == FormatConversionCharInternal::g ||
- c == FormatConversionCharInternal::A ||
- c == FormatConversionCharInternal::E ||
- c == FormatConversionCharInternal::F ||
- c == FormatConversionCharInternal::G) {
- return true;
- } else {
- return false;
+ if (c == FormatConversionCharInternal::a ||
+ c == FormatConversionCharInternal::e ||
+ c == FormatConversionCharInternal::f ||
+ c == FormatConversionCharInternal::g ||
+ c == FormatConversionCharInternal::A ||
+ c == FormatConversionCharInternal::E ||
+ c == FormatConversionCharInternal::F ||
+ c == FormatConversionCharInternal::G) {
+ return true;
+ } else {
+ return false;
}
}
inline char FormatConversionCharToChar(FormatConversionChar c) {
- if (c == FormatConversionCharInternal::kNone) {
- return '\0';
-
-#define ABSL_INTERNAL_X_VAL(e) \
- } else if (c == FormatConversionCharInternal::e) { \
+ if (c == FormatConversionCharInternal::kNone) {
+ return '\0';
+
+#define ABSL_INTERNAL_X_VAL(e) \
+ } else if (c == FormatConversionCharInternal::e) { \
return #e[0];
#define ABSL_INTERNAL_X_SEP
- ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
- ABSL_INTERNAL_X_SEP)
- } else {
- return '\0';
- }
-
+ ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
+ ABSL_INTERNAL_X_SEP)
+ } else {
+ return '\0';
+ }
+
#undef ABSL_INTERNAL_X_VAL
#undef ABSL_INTERNAL_X_SEP
}
@@ -268,7 +268,7 @@ inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
struct FormatConversionSpecImplFriend;
-class FormatConversionSpecImpl {
+class FormatConversionSpecImpl {
public:
// Width and precison are not specified, no flags are set.
bool is_basic() const { return flags_ == Flags::kBasic; }
@@ -285,7 +285,7 @@ class FormatConversionSpecImpl {
FormatConversionChar conversion_char() const {
// Keep this field first in the struct . It generates better code when
// accessing it when ConversionSpec is passed by value in registers.
- static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
+ static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
return conv_;
}
@@ -296,65 +296,65 @@ class FormatConversionSpecImpl {
// negative value.
int precision() const { return precision_; }
- template <typename T>
- T Wrap() {
- return T(*this);
- }
+ template <typename T>
+ T Wrap() {
+ return T(*this);
+ }
private:
friend struct str_format_internal::FormatConversionSpecImplFriend;
- FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
+ FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
Flags flags_;
int width_;
int precision_;
};
struct FormatConversionSpecImplFriend final {
- static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
+ static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
conv->flags_ = f;
}
static void SetConversionChar(FormatConversionChar c,
- FormatConversionSpecImpl* conv) {
+ FormatConversionSpecImpl* conv) {
conv->conv_ = c;
}
- static void SetWidth(int w, FormatConversionSpecImpl* conv) {
- conv->width_ = w;
- }
- static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
+ static void SetWidth(int w, FormatConversionSpecImpl* conv) {
+ conv->width_ = w;
+ }
+ static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
conv->precision_ = p;
}
- static TString FlagsToString(const FormatConversionSpecImpl& spec) {
+ static TString FlagsToString(const FormatConversionSpecImpl& spec) {
return str_format_internal::FlagsToString(spec.flags_);
}
};
-// Type safe OR operator.
-// We need this for two reasons:
-// 1. operator| on enums makes them decay to integers and the result is an
-// integer. We need the result to stay as an enum.
-// 2. We use "enum class" which would not work even if we accepted the decay.
-constexpr FormatConversionCharSet FormatConversionCharSetUnion(
- FormatConversionCharSet a) {
- return a;
-}
-
-template <typename... CharSet>
-constexpr FormatConversionCharSet FormatConversionCharSetUnion(
- FormatConversionCharSet a, CharSet... rest) {
- return static_cast<FormatConversionCharSet>(
- static_cast<uint64_t>(a) |
- static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
-}
-
-constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
- return uint64_t{1} << (1 + static_cast<uint8_t>(c));
-}
-
-constexpr uint64_t FormatConversionCharToConvInt(char conv) {
+// Type safe OR operator.
+// We need this for two reasons:
+// 1. operator| on enums makes them decay to integers and the result is an
+// integer. We need the result to stay as an enum.
+// 2. We use "enum class" which would not work even if we accepted the decay.
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+ FormatConversionCharSet a) {
+ return a;
+}
+
+template <typename... CharSet>
+constexpr FormatConversionCharSet FormatConversionCharSetUnion(
+ FormatConversionCharSet a, CharSet... rest) {
+ return static_cast<FormatConversionCharSet>(
+ static_cast<uint64_t>(a) |
+ static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
+ return uint64_t{1} << (1 + static_cast<uint8_t>(c));
+}
+
+constexpr uint64_t FormatConversionCharToConvInt(char conv) {
return
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
- conv == #c[0] \
- ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ conv == #c[0] \
+ ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
:
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
#undef ABSL_INTERNAL_CHAR_SET_CASE
@@ -363,29 +363,29 @@ constexpr uint64_t FormatConversionCharToConvInt(char conv) {
: 0;
}
-constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
- return static_cast<FormatConversionCharSet>(
- FormatConversionCharToConvInt(conv));
-}
-
-struct FormatConversionCharSetInternal {
-#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
- static constexpr FormatConversionCharSet c = \
- FormatConversionCharToConvValue(#c[0]);
+constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
+ return static_cast<FormatConversionCharSet>(
+ FormatConversionCharToConvInt(conv));
+}
+
+struct FormatConversionCharSetInternal {
+#define ABSL_INTERNAL_CHAR_SET_CASE(c) \
+ static constexpr FormatConversionCharSet c = \
+ FormatConversionCharToConvValue(#c[0]);
ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
#undef ABSL_INTERNAL_CHAR_SET_CASE
// Used for width/precision '*' specification.
- static constexpr FormatConversionCharSet kStar =
- FormatConversionCharToConvValue('*');
-
- static constexpr FormatConversionCharSet kIntegral =
- FormatConversionCharSetUnion(d, i, u, o, x, X);
- static constexpr FormatConversionCharSet kFloating =
- FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
- static constexpr FormatConversionCharSet kNumeric =
- FormatConversionCharSetUnion(kIntegral, kFloating);
- static constexpr FormatConversionCharSet kPointer = p;
+ static constexpr FormatConversionCharSet kStar =
+ FormatConversionCharToConvValue('*');
+
+ static constexpr FormatConversionCharSet kIntegral =
+ FormatConversionCharSetUnion(d, i, u, o, x, X);
+ static constexpr FormatConversionCharSet kFloating =
+ FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
+ static constexpr FormatConversionCharSet kNumeric =
+ FormatConversionCharSetUnion(kIntegral, kFloating);
+ static constexpr FormatConversionCharSet kPointer = p;
};
// Type safe OR operator.
@@ -395,29 +395,29 @@ struct FormatConversionCharSetInternal {
// 2. We use "enum class" which would not work even if we accepted the decay.
constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
FormatConversionCharSet b) {
- return FormatConversionCharSetUnion(a, b);
-}
-
-// Overloaded conversion functions to support y_absl::ParsedFormat.
-// Get a conversion with a single character in it.
-constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
- return static_cast<FormatConversionCharSet>(
- FormatConversionCharToConvValue(c));
+ return FormatConversionCharSetUnion(a, b);
}
+// Overloaded conversion functions to support y_absl::ParsedFormat.
// Get a conversion with a single character in it.
-constexpr FormatConversionCharSet ToFormatConversionCharSet(
- FormatConversionCharSet c) {
- return c;
+constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
+ return static_cast<FormatConversionCharSet>(
+ FormatConversionCharToConvValue(c));
}
-template <typename T>
-void ToFormatConversionCharSet(T) = delete;
-
+// Get a conversion with a single character in it.
+constexpr FormatConversionCharSet ToFormatConversionCharSet(
+ FormatConversionCharSet c) {
+ return c;
+}
+
+template <typename T>
+void ToFormatConversionCharSet(T) = delete;
+
// Checks whether `c` exists in `set`.
constexpr bool Contains(FormatConversionCharSet set, char c) {
- return (static_cast<uint64_t>(set) &
- static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
+ return (static_cast<uint64_t>(set) &
+ static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
}
// Checks whether all the characters in `c` are contained in `set`
@@ -427,10 +427,10 @@ constexpr bool Contains(FormatConversionCharSet set,
static_cast<uint64_t>(c);
}
-// Checks whether all the characters in `c` are contained in `set`
-constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
- return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
-}
+// Checks whether all the characters in `c` are contained in `set`
+constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
+ return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
+}
// Return capacity - used, clipped to a minimum of 0.
inline size_t Excess(size_t used, size_t capacity) {
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc
index c49062538d..af48a71cde 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.cc
@@ -1,38 +1,38 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "y_absl/strings/internal/str_format/float_conversion.h"
#include <string.h>
-
+
#include <algorithm>
#include <cassert>
#include <cmath>
-#include <limits>
+#include <limits>
#include <util/generic/string.h>
-#include "y_absl/base/attributes.h"
+#include "y_absl/base/attributes.h"
#include "y_absl/base/config.h"
-#include "y_absl/base/optimization.h"
-#include "y_absl/functional/function_ref.h"
-#include "y_absl/meta/type_traits.h"
-#include "y_absl/numeric/bits.h"
-#include "y_absl/numeric/int128.h"
-#include "y_absl/numeric/internal/representation.h"
-#include "y_absl/strings/numbers.h"
-#include "y_absl/types/optional.h"
-#include "y_absl/types/span.h"
+#include "y_absl/base/optimization.h"
+#include "y_absl/functional/function_ref.h"
+#include "y_absl/meta/type_traits.h"
+#include "y_absl/numeric/bits.h"
+#include "y_absl/numeric/int128.h"
+#include "y_absl/numeric/internal/representation.h"
+#include "y_absl/strings/numbers.h"
+#include "y_absl/types/optional.h"
+#include "y_absl/types/span.h"
namespace y_absl {
ABSL_NAMESPACE_BEGIN
@@ -40,905 +40,905 @@ namespace str_format_internal {
namespace {
-using ::y_absl::numeric_internal::IsDoubleDouble;
-
-// The code below wants to avoid heap allocations.
-// To do so it needs to allocate memory on the stack.
-// `StackArray` will allocate memory on the stack in the form of a uint32_t
-// array and call the provided callback with said memory.
-// It will allocate memory in increments of 512 bytes. We could allocate the
-// largest needed unconditionally, but that is more than we need in most of
-// cases. This way we use less stack in the common cases.
-class StackArray {
- using Func = y_absl::FunctionRef<void(y_absl::Span<uint32_t>)>;
- static constexpr size_t kStep = 512 / sizeof(uint32_t);
- // 5 steps is 2560 bytes, which is enough to hold a long double with the
- // largest/smallest exponents.
- // The operations below will static_assert their particular maximum.
- static constexpr size_t kNumSteps = 5;
-
- // We do not want this function to be inlined.
- // Otherwise the caller will allocate the stack space unnecessarily for all
- // the variants even though it only calls one.
- template <size_t steps>
- ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
- uint32_t values[steps * kStep]{};
- f(y_absl::MakeSpan(values));
- }
-
- public:
- static constexpr size_t kMaxCapacity = kStep * kNumSteps;
-
- static void RunWithCapacity(size_t capacity, Func f) {
- assert(capacity <= kMaxCapacity);
- const size_t step = (capacity + kStep - 1) / kStep;
- assert(step <= kNumSteps);
- switch (step) {
- case 1:
- return RunWithCapacityImpl<1>(f);
- case 2:
- return RunWithCapacityImpl<2>(f);
- case 3:
- return RunWithCapacityImpl<3>(f);
- case 4:
- return RunWithCapacityImpl<4>(f);
- case 5:
- return RunWithCapacityImpl<5>(f);
- }
-
- assert(false && "Invalid capacity");
- }
-};
-
-// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
-// the carry.
-template <typename Int>
-inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
- using BiggerInt = y_absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
- BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
- *v = static_cast<Int>(tmp);
- return static_cast<Int>(tmp >> (sizeof(Int) * 8));
-}
-
-// Calculates `(2^64 * carry + *v) / 10`.
-// Stores the quotient in `*v` and returns the remainder.
-// Requires: `0 <= carry <= 9`
-inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
- constexpr uint64_t divisor = 10;
- // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
- constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
- constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
-
- const uint64_t mod = *v % divisor;
- const uint64_t next_carry = chunk_remainder * carry + mod;
- *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
- return next_carry % divisor;
-}
-
-using MaxFloatType =
- typename std::conditional<IsDoubleDouble(), double, long double>::type;
-
-// Generates the decimal representation for an integer of the form `v * 2^exp`,
-// where `v` and `exp` are both positive integers.
-// It generates the digits from the left (ie the most significant digit first)
-// to allow for direct printing into the sink.
-//
-// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
-class BinaryToDecimal {
- static constexpr int ChunksNeeded(int exp) {
- // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
- // bits. Round up to 32.
- // See constructor for details about adding `10%` to the value.
- return (128 + exp + 31) / 32 * 11 / 10;
- }
-
- public:
- // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
- // This function will allocate enough stack space to perform the conversion.
- static void RunConversion(uint128 v, int exp,
- y_absl::FunctionRef<void(BinaryToDecimal)> f) {
- assert(exp > 0);
- assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
- static_assert(
- static_cast<int>(StackArray::kMaxCapacity) >=
- ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
- "");
-
- StackArray::RunWithCapacity(
- ChunksNeeded(exp),
- [=](y_absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
- }
-
- int TotalDigits() const {
- return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
- CurrentDigits().size());
- }
-
- // See the current block of digits.
- y_absl::string_view CurrentDigits() const {
- return y_absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
- }
-
- // Advance the current view of digits.
- // Returns `false` when no more digits are available.
- bool AdvanceDigits() {
- if (decimal_start_ >= decimal_end_) return false;
-
- uint32_t w = data_[decimal_start_++];
- for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
- digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
- }
- return true;
- }
-
- private:
- BinaryToDecimal(y_absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
- // We need to print the digits directly into the sink object without
- // buffering them all first. To do this we need two things:
- // - to know the total number of digits to do padding when necessary
- // - to generate the decimal digits from the left.
- //
- // In order to do this, we do a two pass conversion.
- // On the first pass we convert the binary representation of the value into
- // a decimal representation in which each uint32_t chunk holds up to 9
- // decimal digits. In the second pass we take each decimal-holding-uint32_t
- // value and generate the ascii decimal digits into `digits_`.
- //
- // The binary and decimal representations actually share the same memory
- // region. As we go converting the chunks from binary to decimal we free
- // them up and reuse them for the decimal representation. One caveat is that
- // the decimal representation is around 7% less efficient in space than the
- // binary one. We allocate an extra 10% memory to account for this. See
- // ChunksNeeded for this calculation.
- int chunk_index = exp / 32;
- decimal_start_ = decimal_end_ = ChunksNeeded(exp);
- const int offset = exp % 32;
- // Left shift v by exp bits.
- data_[chunk_index] = static_cast<uint32_t>(v << offset);
- for (v >>= (32 - offset); v; v >>= 32)
- data_[++chunk_index] = static_cast<uint32_t>(v);
-
- while (chunk_index >= 0) {
- // While we have more than one chunk available, go in steps of 1e9.
- // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
- // the variable updated.
- uint32_t carry = 0;
- for (int i = chunk_index; i >= 0; --i) {
- uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
- data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
- carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
- }
-
- // If the highest chunk is now empty, remove it from view.
- if (data_[chunk_index] == 0) --chunk_index;
-
- --decimal_start_;
- assert(decimal_start_ != chunk_index);
- data_[decimal_start_] = carry;
- }
-
- // Fill the first set of digits. The first chunk might not be complete, so
- // handle differently.
- for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
- digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
- }
- }
-
- private:
- static constexpr int kDigitsPerChunk = 9;
-
- int decimal_start_;
- int decimal_end_;
-
- char digits_[kDigitsPerChunk];
- int size_ = 0;
-
- y_absl::Span<uint32_t> data_;
-};
-
-// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
-// Requires `-exp < 0` and
-// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`.
-class FractionalDigitGenerator {
- public:
- // Run the conversion for `v * 2^exp` and call `f(generator)`.
- // This function will allocate enough stack space to perform the conversion.
- static void RunConversion(
- uint128 v, int exp, y_absl::FunctionRef<void(FractionalDigitGenerator)> f) {
- using Limits = std::numeric_limits<MaxFloatType>;
- assert(-exp < 0);
- assert(-exp >= Limits::min_exponent - 128);
- static_assert(StackArray::kMaxCapacity >=
- (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
- "");
- StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
- [=](y_absl::Span<uint32_t> input) {
- f(FractionalDigitGenerator(input, v, exp));
- });
- }
-
- // Returns true if there are any more non-zero digits left.
- bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
-
- // Returns true if the remainder digits are greater than 5000...
- bool IsGreaterThanHalf() const {
- return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
- }
- // Returns true if the remainder digits are exactly 5000...
- bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
-
- struct Digits {
- int digit_before_nine;
- int num_nines;
- };
-
- // Get the next set of digits.
- // They are composed by a non-9 digit followed by a runs of zero or more 9s.
- Digits GetDigits() {
- Digits digits{next_digit_, 0};
-
- next_digit_ = GetOneDigit();
- while (next_digit_ == 9) {
- ++digits.num_nines;
- next_digit_ = GetOneDigit();
- }
-
- return digits;
- }
-
- private:
- // Return the next digit.
- int GetOneDigit() {
- if (chunk_index_ < 0) return 0;
-
- uint32_t carry = 0;
- for (int i = chunk_index_; i >= 0; --i) {
- carry = MultiplyBy10WithCarry(&data_[i], carry);
- }
- // If the lowest chunk is now empty, remove it from view.
- if (data_[chunk_index_] == 0) --chunk_index_;
- return carry;
- }
-
- FractionalDigitGenerator(y_absl::Span<uint32_t> data, uint128 v, int exp)
- : chunk_index_(exp / 32), data_(data) {
- const int offset = exp % 32;
- // Right shift `v` by `exp` bits.
- data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
- v >>= offset;
- // Make sure we don't overflow the data. We already calculated that
- // non-zero bits fit, so we might not have space for leading zero bits.
- for (int pos = chunk_index_; v; v >>= 32)
- data_[--pos] = static_cast<uint32_t>(v);
-
- // Fill next_digit_, as GetDigits expects it to be populated always.
- next_digit_ = GetOneDigit();
- }
-
- int next_digit_;
- int chunk_index_;
- y_absl::Span<uint32_t> data_;
-};
-
-// Count the number of leading zero bits.
-int LeadingZeros(uint64_t v) { return countl_zero(v); }
-int LeadingZeros(uint128 v) {
- auto high = static_cast<uint64_t>(v >> 64);
- auto low = static_cast<uint64_t>(v);
- return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
-}
-
-// Round up the text digits starting at `p`.
-// The buffer must have an extra digit that is known to not need rounding.
-// This is done below by having an extra '0' digit on the left.
-void RoundUp(char *p) {
- while (*p == '9' || *p == '.') {
- if (*p == '9') *p = '0';
- --p;
- }
- ++*p;
-}
-
-// Check the previous digit and round up or down to follow the round-to-even
-// policy.
-void RoundToEven(char *p) {
- if (*p == '.') --p;
- if (*p % 2 == 1) RoundUp(p);
-}
-
-// Simple integral decimal digit printing for values that fit in 64-bits.
-// Returns the pointer to the last written digit.
-char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
- do {
- *--p = DivideBy10WithCarry(&v, 0) + '0';
- } while (v != 0);
- return p;
-}
-
-// Simple integral decimal digit printing for values that fit in 128-bits.
-// Returns the pointer to the last written digit.
-char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
- auto high = static_cast<uint64_t>(v >> 64);
- auto low = static_cast<uint64_t>(v);
-
- while (high != 0) {
- uint64_t carry = DivideBy10WithCarry(&high, 0);
- carry = DivideBy10WithCarry(&low, carry);
- *--p = carry + '0';
- }
- return PrintIntegralDigitsFromRightFast(low, p);
-}
-
-// Simple fractional decimal digit printing for values that fir in 64-bits after
-// shifting.
-// Performs rounding if necessary to fit within `precision`.
-// Returns the pointer to one after the last character written.
-char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
- int precision) {
- char *p = start;
- v <<= (64 - exp);
- while (precision > 0) {
- if (!v) return p;
- *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
- --precision;
- }
-
- // We need to round.
- if (v < 0x8000000000000000) {
- // We round down, so nothing to do.
- } else if (v > 0x8000000000000000) {
- // We round up.
- RoundUp(p - 1);
- } else {
- RoundToEven(p - 1);
- }
-
- assert(precision == 0);
- // Precision can only be zero here.
- return p;
-}
-
-// Simple fractional decimal digit printing for values that fir in 128-bits
-// after shifting.
-// Performs rounding if necessary to fit within `precision`.
-// Returns the pointer to one after the last character written.
-char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
- int precision) {
- char *p = start;
- v <<= (128 - exp);
- auto high = static_cast<uint64_t>(v >> 64);
- auto low = static_cast<uint64_t>(v);
-
- // While we have digits to print and `low` is not empty, do the long
- // multiplication.
- while (precision > 0 && low != 0) {
- uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
- carry = MultiplyBy10WithCarry(&high, carry);
-
- *p++ = carry + '0';
- --precision;
- }
-
- // Now `low` is empty, so use a faster approach for the rest of the digits.
- // This block is pretty much the same as the main loop for the 64-bit case
- // above.
- while (precision > 0) {
- if (!high) return p;
- *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
- --precision;
- }
-
- // We need to round.
- if (high < 0x8000000000000000) {
- // We round down, so nothing to do.
- } else if (high > 0x8000000000000000 || low != 0) {
- // We round up.
- RoundUp(p - 1);
- } else {
- RoundToEven(p - 1);
- }
-
- assert(precision == 0);
- // Precision can only be zero here.
- return p;
-}
-
-struct FormatState {
- char sign_char;
- int precision;
- const FormatConversionSpecImpl &conv;
- FormatSinkImpl *sink;
-
- // In `alt` mode (flag #) we keep the `.` even if there are no fractional
- // digits. In non-alt mode, we strip it.
- bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
-};
-
-struct Padding {
- int left_spaces;
- int zeros;
- int right_spaces;
-};
-
-Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
- if (state.conv.width() < 0 ||
- static_cast<size_t>(state.conv.width()) <= total_size) {
- return {0, 0, 0};
- }
- int missing_chars = state.conv.width() - total_size;
- if (state.conv.has_left_flag()) {
- return {0, 0, missing_chars};
- } else if (state.conv.has_zero_flag()) {
- return {0, missing_chars, 0};
- } else {
- return {missing_chars, 0, 0};
- }
-}
-
-void FinalPrint(const FormatState &state, y_absl::string_view data,
- int padding_offset, int trailing_zeros,
- y_absl::string_view data_postfix) {
- if (state.conv.width() < 0) {
- // No width specified. Fast-path.
- if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
- state.sink->Append(data);
- state.sink->Append(trailing_zeros, '0');
- state.sink->Append(data_postfix);
- return;
- }
-
- auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
- data.size() + data_postfix.size() +
- static_cast<size_t>(trailing_zeros),
- state);
-
- state.sink->Append(padding.left_spaces, ' ');
- if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
- // Padding in general needs to be inserted somewhere in the middle of `data`.
- state.sink->Append(data.substr(0, padding_offset));
- state.sink->Append(padding.zeros, '0');
- state.sink->Append(data.substr(padding_offset));
- state.sink->Append(trailing_zeros, '0');
- state.sink->Append(data_postfix);
- state.sink->Append(padding.right_spaces, ' ');
-}
-
-// Fastpath %f formatter for when the shifted value fits in a simple integral
-// type.
-// Prints `v*2^exp` with the options from `state`.
-template <typename Int>
-void FormatFFast(Int v, int exp, const FormatState &state) {
- constexpr int input_bits = sizeof(Int) * 8;
-
- static constexpr size_t integral_size =
- /* in case we need to round up an extra digit */ 1 +
- /* decimal digits for uint128 */ 40 + 1;
- char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
- buffer[integral_size] = '.';
- char *const integral_digits_end = buffer + integral_size;
- char *integral_digits_start;
- char *const fractional_digits_start = buffer + integral_size + 1;
- char *fractional_digits_end = fractional_digits_start;
-
- if (exp >= 0) {
- const int total_bits = input_bits - LeadingZeros(v) + exp;
- integral_digits_start =
- total_bits <= 64
- ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
- integral_digits_end)
- : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
- integral_digits_end);
- } else {
- exp = -exp;
-
- integral_digits_start = PrintIntegralDigitsFromRightFast(
- exp < input_bits ? v >> exp : 0, integral_digits_end);
- // PrintFractionalDigits may pull a carried 1 all the way up through the
- // integral portion.
- integral_digits_start[-1] = '0';
-
- fractional_digits_end =
- exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
- state.precision)
- : PrintFractionalDigitsFast(static_cast<uint128>(v),
- fractional_digits_start, exp,
- state.precision);
- // There was a carry, so include the first digit too.
- if (integral_digits_start[-1] != '0') --integral_digits_start;
- }
-
- size_t size = fractional_digits_end - integral_digits_start;
-
- // In `alt` mode (flag #) we keep the `.` even if there are no fractional
- // digits. In non-alt mode, we strip it.
- if (!state.ShouldPrintDot()) --size;
- FinalPrint(state, y_absl::string_view(integral_digits_start, size),
- /*padding_offset=*/0,
- static_cast<int>(state.precision - (fractional_digits_end -
- fractional_digits_start)),
- /*data_postfix=*/"");
-}
-
-// Slow %f formatter for when the shifted value does not fit in a uint128, and
-// `exp > 0`.
-// Prints `v*2^exp` with the options from `state`.
-// This one is guaranteed to not have fractional digits, so we don't have to
-// worry about anything after the `.`.
-void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
- BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
- const size_t total_digits =
- btd.TotalDigits() +
- (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
-
- const auto padding = ExtraWidthToPadding(
- total_digits + (state.sign_char != '\0' ? 1 : 0), state);
-
- state.sink->Append(padding.left_spaces, ' ');
- if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
- state.sink->Append(padding.zeros, '0');
-
- do {
- state.sink->Append(btd.CurrentDigits());
- } while (btd.AdvanceDigits());
-
- if (state.ShouldPrintDot()) state.sink->Append(1, '.');
- state.sink->Append(state.precision, '0');
- state.sink->Append(padding.right_spaces, ' ');
- });
-}
-
-// Slow %f formatter for when the shifted value does not fit in a uint128, and
-// `exp < 0`.
-// Prints `v*2^exp` with the options from `state`.
-// This one is guaranteed to be < 1.0, so we don't have to worry about integral
-// digits.
-void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
- const size_t total_digits =
- /* 0 */ 1 +
- (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
- auto padding =
- ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
- padding.zeros += 1;
- state.sink->Append(padding.left_spaces, ' ');
- if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
- state.sink->Append(padding.zeros, '0');
-
- if (state.ShouldPrintDot()) state.sink->Append(1, '.');
-
- // Print digits
- int digits_to_go = state.precision;
-
- FractionalDigitGenerator::RunConversion(
- v, exp, [&](FractionalDigitGenerator digit_gen) {
- // There are no digits to print here.
- if (state.precision == 0) return;
-
- // We go one digit at a time, while keeping track of runs of nines.
- // The runs of nines are used to perform rounding when necessary.
-
- while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
- auto digits = digit_gen.GetDigits();
-
- // Now we have a digit and a run of nines.
- // See if we can print them all.
- if (digits.num_nines + 1 < digits_to_go) {
- // We don't have to round yet, so print them.
- state.sink->Append(1, digits.digit_before_nine + '0');
- state.sink->Append(digits.num_nines, '9');
- digits_to_go -= digits.num_nines + 1;
-
- } else {
- // We can't print all the nines, see where we have to truncate.
-
- bool round_up = false;
- if (digits.num_nines + 1 > digits_to_go) {
- // We round up at a nine. No need to print them.
- round_up = true;
- } else {
- // We can fit all the nines, but truncate just after it.
- if (digit_gen.IsGreaterThanHalf()) {
- round_up = true;
- } else if (digit_gen.IsExactlyHalf()) {
- // Round to even
- round_up =
- digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
- }
- }
-
- if (round_up) {
- state.sink->Append(1, digits.digit_before_nine + '1');
- --digits_to_go;
- // The rest will be zeros.
- } else {
- state.sink->Append(1, digits.digit_before_nine + '0');
- state.sink->Append(digits_to_go - 1, '9');
- digits_to_go = 0;
- }
- return;
- }
- }
- });
-
- state.sink->Append(digits_to_go, '0');
- state.sink->Append(padding.right_spaces, ' ');
-}
-
-template <typename Int>
-void FormatF(Int mantissa, int exp, const FormatState &state) {
- if (exp >= 0) {
- const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
-
- // Fallback to the slow stack-based approach if we can't do it in a 64 or
- // 128 bit state.
- if (ABSL_PREDICT_FALSE(total_bits > 128)) {
- return FormatFPositiveExpSlow(mantissa, exp, state);
- }
- } else {
- // Fallback to the slow stack-based approach if we can't do it in a 64 or
- // 128 bit state.
- if (ABSL_PREDICT_FALSE(exp < -128)) {
- return FormatFNegativeExpSlow(mantissa, -exp, state);
- }
- }
- return FormatFFast(mantissa, exp, state);
-}
-
-// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
-// bits 4-7.
-template <typename Int>
-uint8_t GetNibble(Int n, int nibble_index) {
- constexpr Int mask_low_nibble = Int{0xf};
- int shift = nibble_index * 4;
- n &= mask_low_nibble << shift;
- return static_cast<uint8_t>((n >> shift) & 0xf);
-}
-
-// Add one to the given nibble, applying carry to higher nibbles. Returns true
-// if overflow, false otherwise.
-template <typename Int>
-bool IncrementNibble(int nibble_index, Int *n) {
- constexpr int kShift = sizeof(Int) * 8 - 1;
- constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
- Int before = *n >> kShift;
- // Here we essentially want to take the number 1 and move it into the requsted
- // nibble, then add it to *n to effectively increment the nibble. However,
- // ASan will complain if we try to shift the 1 beyond the limits of the Int,
- // i.e., if the nibble_index is out of range. So therefore we check for this
- // and if we are out of range we just add 0 which leaves *n unchanged, which
- // seems like the reasonable thing to do in that case.
- *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4)));
- Int after = *n >> kShift;
- return (before && !after) || (nibble_index >= kNumNibbles);
-}
-
-// Return a mask with 1's in the given nibble and all lower nibbles.
-template <typename Int>
-Int MaskUpToNibbleInclusive(int nibble_index) {
- constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
- static const Int ones = ~Int{0};
- return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
-}
-
-// Return a mask with 1's below the given nibble.
-template <typename Int>
-Int MaskUpToNibbleExclusive(int nibble_index) {
- return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
-}
-
-template <typename Int>
-Int MoveToNibble(uint8_t nibble, int nibble_index) {
- return Int{nibble} << (4 * nibble_index);
-}
-
-// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
-//
-// In the hex representation we keep a single hex digit to the left of the dot.
-// However, the question as to how many bits of the mantissa should be put into
-// that hex digit in theory is arbitrary, but in practice it is optimal to
-// choose based on the size of the mantissa. E.g., for a `double`, there are 53
-// mantissa bits, so that means that we should put 1 bit to the left of the dot,
-// thereby leaving 52 bits to the right, which is evenly divisible by four and
-// thus all fractional digits represent actual precision. For a `long double`,
-// on the other hand, there are 64 bits of mantissa, thus we can use all four
-// bits for the initial hex digit and still have a number left over (60) that is
-// a multiple of four. Once again, the goal is to have all fractional digits
-// represent real precision.
-template <typename Float>
-constexpr int HexFloatLeadingDigitSizeInBits() {
- return std::numeric_limits<Float>::digits % 4 > 0
- ? std::numeric_limits<Float>::digits % 4
- : 4;
-}
-
-// This function captures the rounding behavior of glibc for hex float
-// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
-// ("%.2a") glibc will round up because it rounds toward the even number (since
-// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
-// point that is not followed by 800000..., it disregards the parity and rounds
-// up if > 8 and rounds down if < 8.
-template <typename Int>
-bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
- uint8_t leading) {
- // If the last nibble (hex digit) to be displayed is the lowest on in the
- // mantissa then that means that we don't have any further nibbles to inform
- // rounding, so don't round.
- if (final_nibble_displayed <= 0) {
- return false;
- }
- int rounding_nibble_idx = final_nibble_displayed - 1;
- constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
- assert(final_nibble_displayed <= kTotalNibbles);
- Int mantissa_up_to_rounding_nibble_inclusive =
- mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
- Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
- if (mantissa_up_to_rounding_nibble_inclusive != eight) {
- return mantissa_up_to_rounding_nibble_inclusive > eight;
- }
- // Nibble in question == 8.
- uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
- ? leading
- : GetNibble(mantissa, final_nibble_displayed);
- return round_if_odd % 2 == 1;
-}
-
-// Stores values associated with a Float type needed by the FormatA
-// implementation in order to avoid templatizing that function by the Float
-// type.
-struct HexFloatTypeParams {
- template <typename Float>
- explicit HexFloatTypeParams(Float)
- : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
- leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
- assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
- }
-
- int min_exponent;
- int leading_digit_size_bits;
-};
-
-// Hex Float Rounding. First check if we need to round; if so, then we do that
-// by manipulating (incrementing) the mantissa, that way we can later print the
-// mantissa digits by iterating through them in the same way regardless of
-// whether a rounding happened.
-template <typename Int>
-void FormatARound(bool precision_specified, const FormatState &state,
- uint8_t *leading, Int *mantissa, int *exp) {
- constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
- // Index of the last nibble that we could display given precision.
- int final_nibble_displayed =
- precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
- if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
- // Need to round up.
- bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
- *leading += (overflow ? 1 : 0);
- if (ABSL_PREDICT_FALSE(*leading > 15)) {
- // We have overflowed the leading digit. This would mean that we would
- // need two hex digits to the left of the dot, which is not allowed. So
- // adjust the mantissa and exponent so that the result is always 1.0eXXX.
- *leading = 1;
- *mantissa = 0;
- *exp += 4;
- }
- }
- // Now that we have handled a possible round-up we can go ahead and zero out
- // all the nibbles of the mantissa that we won't need.
- if (precision_specified) {
- *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
- }
-}
-
-template <typename Int>
-void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
- Int *mantissa, int *exp) {
- constexpr int kIntBits = sizeof(Int) * 8;
- static const Int kHighIntBit = Int{1} << (kIntBits - 1);
- const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
- // Normalize mantissa so that highest bit set is in MSB position, unless we
- // get interrupted by the exponent threshold.
- while (*mantissa && !(*mantissa & kHighIntBit)) {
- if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
- *mantissa >>= (float_traits.min_exponent - *exp);
- *exp = float_traits.min_exponent;
- return;
- }
- *mantissa <<= 1;
- --*exp;
- }
- // Extract bits for leading digit then shift them away leaving the
- // fractional part.
- *leading =
- static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
- *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
- *mantissa <<= kLeadDigitBitsCount;
-}
-
-template <typename Int>
-void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
- bool uppercase, const FormatState &state) {
- // Int properties.
- constexpr int kIntBits = sizeof(Int) * 8;
- constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
- // Did the user specify a precision explicitly?
- const bool precision_specified = state.conv.precision() >= 0;
-
- // ========== Normalize/Denormalize ==========
- exp += kIntBits; // make all digits fractional digits.
- // This holds the (up to four) bits of leading digit, i.e., the '1' in the
- // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
- uint8_t leading = 0;
- FormatANormalize(float_traits, &leading, &mantissa, &exp);
-
- // =============== Rounding ==================
- // Check if we need to round; if so, then we do that by manipulating
- // (incrementing) the mantissa before beginning to print characters.
- FormatARound(precision_specified, state, &leading, &mantissa, &exp);
-
- // ============= Format Result ===============
- // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
- // size with long double which is the largest of the floats.
- constexpr size_t kBufSizeForHexFloatRepr =
- 2 // 0x
- + std::numeric_limits<MaxFloatType>::digits / 4 // number of hex digits
- + 1 // round up
- + 1; // "." (dot)
- char digits_buffer[kBufSizeForHexFloatRepr];
- char *digits_iter = digits_buffer;
- const char *const digits =
- static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
- (uppercase ? 0 : 16);
-
- // =============== Hex Prefix ================
- *digits_iter++ = '0';
- *digits_iter++ = uppercase ? 'X' : 'x';
-
- // ========== Non-Fractional Digit ===========
- *digits_iter++ = digits[leading];
-
- // ================== Dot ====================
- // There are three reasons we might need a dot. Keep in mind that, at this
- // point, the mantissa holds only the fractional part.
- if ((precision_specified && state.precision > 0) ||
- (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
- *digits_iter++ = '.';
- }
-
- // ============ Fractional Digits ============
- int digits_emitted = 0;
- while (mantissa > 0) {
- *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
- mantissa <<= 4;
- ++digits_emitted;
- }
- int trailing_zeros =
- precision_specified ? state.precision - digits_emitted : 0;
- assert(trailing_zeros >= 0);
- auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
-
- // =============== Exponent ==================
- constexpr size_t kBufSizeForExpDecRepr =
- numbers_internal::kFastToBufferSize // requred for FastIntToBuffer
- + 1 // 'p' or 'P'
- + 1; // '+' or '-'
- char exp_buffer[kBufSizeForExpDecRepr];
- exp_buffer[0] = uppercase ? 'P' : 'p';
- exp_buffer[1] = exp >= 0 ? '+' : '-';
- numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
-
- // ============ Assemble Result ==============
- FinalPrint(state, //
- digits_result, // 0xN.NNN...
- 2, // offset in `data` to start padding if needed.
- trailing_zeros, // num remaining mantissa padding zeros
- exp_buffer); // exponent
-}
-
-char *CopyStringTo(y_absl::string_view v, char *out) {
+using ::y_absl::numeric_internal::IsDoubleDouble;
+
+// The code below wants to avoid heap allocations.
+// To do so it needs to allocate memory on the stack.
+// `StackArray` will allocate memory on the stack in the form of a uint32_t
+// array and call the provided callback with said memory.
+// It will allocate memory in increments of 512 bytes. We could allocate the
+// largest needed unconditionally, but that is more than we need in most of
+// cases. This way we use less stack in the common cases.
+class StackArray {
+ using Func = y_absl::FunctionRef<void(y_absl::Span<uint32_t>)>;
+ static constexpr size_t kStep = 512 / sizeof(uint32_t);
+ // 5 steps is 2560 bytes, which is enough to hold a long double with the
+ // largest/smallest exponents.
+ // The operations below will static_assert their particular maximum.
+ static constexpr size_t kNumSteps = 5;
+
+ // We do not want this function to be inlined.
+ // Otherwise the caller will allocate the stack space unnecessarily for all
+ // the variants even though it only calls one.
+ template <size_t steps>
+ ABSL_ATTRIBUTE_NOINLINE static void RunWithCapacityImpl(Func f) {
+ uint32_t values[steps * kStep]{};
+ f(y_absl::MakeSpan(values));
+ }
+
+ public:
+ static constexpr size_t kMaxCapacity = kStep * kNumSteps;
+
+ static void RunWithCapacity(size_t capacity, Func f) {
+ assert(capacity <= kMaxCapacity);
+ const size_t step = (capacity + kStep - 1) / kStep;
+ assert(step <= kNumSteps);
+ switch (step) {
+ case 1:
+ return RunWithCapacityImpl<1>(f);
+ case 2:
+ return RunWithCapacityImpl<2>(f);
+ case 3:
+ return RunWithCapacityImpl<3>(f);
+ case 4:
+ return RunWithCapacityImpl<4>(f);
+ case 5:
+ return RunWithCapacityImpl<5>(f);
+ }
+
+ assert(false && "Invalid capacity");
+ }
+};
+
+// Calculates `10 * (*v) + carry` and stores the result in `*v` and returns
+// the carry.
+template <typename Int>
+inline Int MultiplyBy10WithCarry(Int *v, Int carry) {
+ using BiggerInt = y_absl::conditional_t<sizeof(Int) == 4, uint64_t, uint128>;
+ BiggerInt tmp = 10 * static_cast<BiggerInt>(*v) + carry;
+ *v = static_cast<Int>(tmp);
+ return static_cast<Int>(tmp >> (sizeof(Int) * 8));
+}
+
+// Calculates `(2^64 * carry + *v) / 10`.
+// Stores the quotient in `*v` and returns the remainder.
+// Requires: `0 <= carry <= 9`
+inline uint64_t DivideBy10WithCarry(uint64_t *v, uint64_t carry) {
+ constexpr uint64_t divisor = 10;
+ // 2^64 / divisor = chunk_quotient + chunk_remainder / divisor
+ constexpr uint64_t chunk_quotient = (uint64_t{1} << 63) / (divisor / 2);
+ constexpr uint64_t chunk_remainder = uint64_t{} - chunk_quotient * divisor;
+
+ const uint64_t mod = *v % divisor;
+ const uint64_t next_carry = chunk_remainder * carry + mod;
+ *v = *v / divisor + carry * chunk_quotient + next_carry / divisor;
+ return next_carry % divisor;
+}
+
+using MaxFloatType =
+ typename std::conditional<IsDoubleDouble(), double, long double>::type;
+
+// Generates the decimal representation for an integer of the form `v * 2^exp`,
+// where `v` and `exp` are both positive integers.
+// It generates the digits from the left (ie the most significant digit first)
+// to allow for direct printing into the sink.
+//
+// Requires `0 <= exp` and `exp <= numeric_limits<MaxFloatType>::max_exponent`.
+class BinaryToDecimal {
+ static constexpr int ChunksNeeded(int exp) {
+ // We will left shift a uint128 by `exp` bits, so we need `128+exp` total
+ // bits. Round up to 32.
+ // See constructor for details about adding `10%` to the value.
+ return (128 + exp + 31) / 32 * 11 / 10;
+ }
+
+ public:
+ // Run the conversion for `v * 2^exp` and call `f(binary_to_decimal)`.
+ // This function will allocate enough stack space to perform the conversion.
+ static void RunConversion(uint128 v, int exp,
+ y_absl::FunctionRef<void(BinaryToDecimal)> f) {
+ assert(exp > 0);
+ assert(exp <= std::numeric_limits<MaxFloatType>::max_exponent);
+ static_assert(
+ static_cast<int>(StackArray::kMaxCapacity) >=
+ ChunksNeeded(std::numeric_limits<MaxFloatType>::max_exponent),
+ "");
+
+ StackArray::RunWithCapacity(
+ ChunksNeeded(exp),
+ [=](y_absl::Span<uint32_t> input) { f(BinaryToDecimal(input, v, exp)); });
+ }
+
+ int TotalDigits() const {
+ return static_cast<int>((decimal_end_ - decimal_start_) * kDigitsPerChunk +
+ CurrentDigits().size());
+ }
+
+ // See the current block of digits.
+ y_absl::string_view CurrentDigits() const {
+ return y_absl::string_view(digits_ + kDigitsPerChunk - size_, size_);
+ }
+
+ // Advance the current view of digits.
+ // Returns `false` when no more digits are available.
+ bool AdvanceDigits() {
+ if (decimal_start_ >= decimal_end_) return false;
+
+ uint32_t w = data_[decimal_start_++];
+ for (size_ = 0; size_ < kDigitsPerChunk; w /= 10) {
+ digits_[kDigitsPerChunk - ++size_] = w % 10 + '0';
+ }
+ return true;
+ }
+
+ private:
+ BinaryToDecimal(y_absl::Span<uint32_t> data, uint128 v, int exp) : data_(data) {
+ // We need to print the digits directly into the sink object without
+ // buffering them all first. To do this we need two things:
+ // - to know the total number of digits to do padding when necessary
+ // - to generate the decimal digits from the left.
+ //
+ // In order to do this, we do a two pass conversion.
+ // On the first pass we convert the binary representation of the value into
+ // a decimal representation in which each uint32_t chunk holds up to 9
+ // decimal digits. In the second pass we take each decimal-holding-uint32_t
+ // value and generate the ascii decimal digits into `digits_`.
+ //
+ // The binary and decimal representations actually share the same memory
+ // region. As we go converting the chunks from binary to decimal we free
+ // them up and reuse them for the decimal representation. One caveat is that
+ // the decimal representation is around 7% less efficient in space than the
+ // binary one. We allocate an extra 10% memory to account for this. See
+ // ChunksNeeded for this calculation.
+ int chunk_index = exp / 32;
+ decimal_start_ = decimal_end_ = ChunksNeeded(exp);
+ const int offset = exp % 32;
+ // Left shift v by exp bits.
+ data_[chunk_index] = static_cast<uint32_t>(v << offset);
+ for (v >>= (32 - offset); v; v >>= 32)
+ data_[++chunk_index] = static_cast<uint32_t>(v);
+
+ while (chunk_index >= 0) {
+ // While we have more than one chunk available, go in steps of 1e9.
+ // `data_[chunk_index]` holds the highest non-zero binary chunk, so keep
+ // the variable updated.
+ uint32_t carry = 0;
+ for (int i = chunk_index; i >= 0; --i) {
+ uint64_t tmp = uint64_t{data_[i]} + (uint64_t{carry} << 32);
+ data_[i] = static_cast<uint32_t>(tmp / uint64_t{1000000000});
+ carry = static_cast<uint32_t>(tmp % uint64_t{1000000000});
+ }
+
+ // If the highest chunk is now empty, remove it from view.
+ if (data_[chunk_index] == 0) --chunk_index;
+
+ --decimal_start_;
+ assert(decimal_start_ != chunk_index);
+ data_[decimal_start_] = carry;
+ }
+
+ // Fill the first set of digits. The first chunk might not be complete, so
+ // handle differently.
+ for (uint32_t first = data_[decimal_start_++]; first != 0; first /= 10) {
+ digits_[kDigitsPerChunk - ++size_] = first % 10 + '0';
+ }
+ }
+
+ private:
+ static constexpr int kDigitsPerChunk = 9;
+
+ int decimal_start_;
+ int decimal_end_;
+
+ char digits_[kDigitsPerChunk];
+ int size_ = 0;
+
+ y_absl::Span<uint32_t> data_;
+};
+
+// Converts a value of the form `x * 2^-exp` into a sequence of decimal digits.
+// Requires `-exp < 0` and
+// `-exp >= limits<MaxFloatType>::min_exponent - limits<MaxFloatType>::digits`.
+class FractionalDigitGenerator {
+ public:
+ // Run the conversion for `v * 2^exp` and call `f(generator)`.
+ // This function will allocate enough stack space to perform the conversion.
+ static void RunConversion(
+ uint128 v, int exp, y_absl::FunctionRef<void(FractionalDigitGenerator)> f) {
+ using Limits = std::numeric_limits<MaxFloatType>;
+ assert(-exp < 0);
+ assert(-exp >= Limits::min_exponent - 128);
+ static_assert(StackArray::kMaxCapacity >=
+ (Limits::digits + 128 - Limits::min_exponent + 31) / 32,
+ "");
+ StackArray::RunWithCapacity((Limits::digits + exp + 31) / 32,
+ [=](y_absl::Span<uint32_t> input) {
+ f(FractionalDigitGenerator(input, v, exp));
+ });
+ }
+
+ // Returns true if there are any more non-zero digits left.
+ bool HasMoreDigits() const { return next_digit_ != 0 || chunk_index_ >= 0; }
+
+ // Returns true if the remainder digits are greater than 5000...
+ bool IsGreaterThanHalf() const {
+ return next_digit_ > 5 || (next_digit_ == 5 && chunk_index_ >= 0);
+ }
+ // Returns true if the remainder digits are exactly 5000...
+ bool IsExactlyHalf() const { return next_digit_ == 5 && chunk_index_ < 0; }
+
+ struct Digits {
+ int digit_before_nine;
+ int num_nines;
+ };
+
+ // Get the next set of digits.
+ // They are composed by a non-9 digit followed by a runs of zero or more 9s.
+ Digits GetDigits() {
+ Digits digits{next_digit_, 0};
+
+ next_digit_ = GetOneDigit();
+ while (next_digit_ == 9) {
+ ++digits.num_nines;
+ next_digit_ = GetOneDigit();
+ }
+
+ return digits;
+ }
+
+ private:
+ // Return the next digit.
+ int GetOneDigit() {
+ if (chunk_index_ < 0) return 0;
+
+ uint32_t carry = 0;
+ for (int i = chunk_index_; i >= 0; --i) {
+ carry = MultiplyBy10WithCarry(&data_[i], carry);
+ }
+ // If the lowest chunk is now empty, remove it from view.
+ if (data_[chunk_index_] == 0) --chunk_index_;
+ return carry;
+ }
+
+ FractionalDigitGenerator(y_absl::Span<uint32_t> data, uint128 v, int exp)
+ : chunk_index_(exp / 32), data_(data) {
+ const int offset = exp % 32;
+ // Right shift `v` by `exp` bits.
+ data_[chunk_index_] = static_cast<uint32_t>(v << (32 - offset));
+ v >>= offset;
+ // Make sure we don't overflow the data. We already calculated that
+ // non-zero bits fit, so we might not have space for leading zero bits.
+ for (int pos = chunk_index_; v; v >>= 32)
+ data_[--pos] = static_cast<uint32_t>(v);
+
+ // Fill next_digit_, as GetDigits expects it to be populated always.
+ next_digit_ = GetOneDigit();
+ }
+
+ int next_digit_;
+ int chunk_index_;
+ y_absl::Span<uint32_t> data_;
+};
+
+// Count the number of leading zero bits.
+int LeadingZeros(uint64_t v) { return countl_zero(v); }
+int LeadingZeros(uint128 v) {
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+ return high != 0 ? countl_zero(high) : 64 + countl_zero(low);
+}
+
+// Round up the text digits starting at `p`.
+// The buffer must have an extra digit that is known to not need rounding.
+// This is done below by having an extra '0' digit on the left.
+void RoundUp(char *p) {
+ while (*p == '9' || *p == '.') {
+ if (*p == '9') *p = '0';
+ --p;
+ }
+ ++*p;
+}
+
+// Check the previous digit and round up or down to follow the round-to-even
+// policy.
+void RoundToEven(char *p) {
+ if (*p == '.') --p;
+ if (*p % 2 == 1) RoundUp(p);
+}
+
+// Simple integral decimal digit printing for values that fit in 64-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint64_t v, char *p) {
+ do {
+ *--p = DivideBy10WithCarry(&v, 0) + '0';
+ } while (v != 0);
+ return p;
+}
+
+// Simple integral decimal digit printing for values that fit in 128-bits.
+// Returns the pointer to the last written digit.
+char *PrintIntegralDigitsFromRightFast(uint128 v, char *p) {
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+
+ while (high != 0) {
+ uint64_t carry = DivideBy10WithCarry(&high, 0);
+ carry = DivideBy10WithCarry(&low, carry);
+ *--p = carry + '0';
+ }
+ return PrintIntegralDigitsFromRightFast(low, p);
+}
+
+// Simple fractional decimal digit printing for values that fir in 64-bits after
+// shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint64_t v, char *start, int exp,
+ int precision) {
+ char *p = start;
+ v <<= (64 - exp);
+ while (precision > 0) {
+ if (!v) return p;
+ *p++ = MultiplyBy10WithCarry(&v, uint64_t{0}) + '0';
+ --precision;
+ }
+
+ // We need to round.
+ if (v < 0x8000000000000000) {
+ // We round down, so nothing to do.
+ } else if (v > 0x8000000000000000) {
+ // We round up.
+ RoundUp(p - 1);
+ } else {
+ RoundToEven(p - 1);
+ }
+
+ assert(precision == 0);
+ // Precision can only be zero here.
+ return p;
+}
+
+// Simple fractional decimal digit printing for values that fir in 128-bits
+// after shifting.
+// Performs rounding if necessary to fit within `precision`.
+// Returns the pointer to one after the last character written.
+char *PrintFractionalDigitsFast(uint128 v, char *start, int exp,
+ int precision) {
+ char *p = start;
+ v <<= (128 - exp);
+ auto high = static_cast<uint64_t>(v >> 64);
+ auto low = static_cast<uint64_t>(v);
+
+ // While we have digits to print and `low` is not empty, do the long
+ // multiplication.
+ while (precision > 0 && low != 0) {
+ uint64_t carry = MultiplyBy10WithCarry(&low, uint64_t{0});
+ carry = MultiplyBy10WithCarry(&high, carry);
+
+ *p++ = carry + '0';
+ --precision;
+ }
+
+ // Now `low` is empty, so use a faster approach for the rest of the digits.
+ // This block is pretty much the same as the main loop for the 64-bit case
+ // above.
+ while (precision > 0) {
+ if (!high) return p;
+ *p++ = MultiplyBy10WithCarry(&high, uint64_t{0}) + '0';
+ --precision;
+ }
+
+ // We need to round.
+ if (high < 0x8000000000000000) {
+ // We round down, so nothing to do.
+ } else if (high > 0x8000000000000000 || low != 0) {
+ // We round up.
+ RoundUp(p - 1);
+ } else {
+ RoundToEven(p - 1);
+ }
+
+ assert(precision == 0);
+ // Precision can only be zero here.
+ return p;
+}
+
+struct FormatState {
+ char sign_char;
+ int precision;
+ const FormatConversionSpecImpl &conv;
+ FormatSinkImpl *sink;
+
+ // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+ // digits. In non-alt mode, we strip it.
+ bool ShouldPrintDot() const { return precision != 0 || conv.has_alt_flag(); }
+};
+
+struct Padding {
+ int left_spaces;
+ int zeros;
+ int right_spaces;
+};
+
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+ if (state.conv.width() < 0 ||
+ static_cast<size_t>(state.conv.width()) <= total_size) {
+ return {0, 0, 0};
+ }
+ int missing_chars = state.conv.width() - total_size;
+ if (state.conv.has_left_flag()) {
+ return {0, 0, missing_chars};
+ } else if (state.conv.has_zero_flag()) {
+ return {0, missing_chars, 0};
+ } else {
+ return {missing_chars, 0, 0};
+ }
+}
+
+void FinalPrint(const FormatState &state, y_absl::string_view data,
+ int padding_offset, int trailing_zeros,
+ y_absl::string_view data_postfix) {
+ if (state.conv.width() < 0) {
+ // No width specified. Fast-path.
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(data);
+ state.sink->Append(trailing_zeros, '0');
+ state.sink->Append(data_postfix);
+ return;
+ }
+
+ auto padding = ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
+ data.size() + data_postfix.size() +
+ static_cast<size_t>(trailing_zeros),
+ state);
+
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ // Padding in general needs to be inserted somewhere in the middle of `data`.
+ state.sink->Append(data.substr(0, padding_offset));
+ state.sink->Append(padding.zeros, '0');
+ state.sink->Append(data.substr(padding_offset));
+ state.sink->Append(trailing_zeros, '0');
+ state.sink->Append(data_postfix);
+ state.sink->Append(padding.right_spaces, ' ');
+}
+
+// Fastpath %f formatter for when the shifted value fits in a simple integral
+// type.
+// Prints `v*2^exp` with the options from `state`.
+template <typename Int>
+void FormatFFast(Int v, int exp, const FormatState &state) {
+ constexpr int input_bits = sizeof(Int) * 8;
+
+ static constexpr size_t integral_size =
+ /* in case we need to round up an extra digit */ 1 +
+ /* decimal digits for uint128 */ 40 + 1;
+ char buffer[integral_size + /* . */ 1 + /* max digits uint128 */ 128];
+ buffer[integral_size] = '.';
+ char *const integral_digits_end = buffer + integral_size;
+ char *integral_digits_start;
+ char *const fractional_digits_start = buffer + integral_size + 1;
+ char *fractional_digits_end = fractional_digits_start;
+
+ if (exp >= 0) {
+ const int total_bits = input_bits - LeadingZeros(v) + exp;
+ integral_digits_start =
+ total_bits <= 64
+ ? PrintIntegralDigitsFromRightFast(static_cast<uint64_t>(v) << exp,
+ integral_digits_end)
+ : PrintIntegralDigitsFromRightFast(static_cast<uint128>(v) << exp,
+ integral_digits_end);
+ } else {
+ exp = -exp;
+
+ integral_digits_start = PrintIntegralDigitsFromRightFast(
+ exp < input_bits ? v >> exp : 0, integral_digits_end);
+ // PrintFractionalDigits may pull a carried 1 all the way up through the
+ // integral portion.
+ integral_digits_start[-1] = '0';
+
+ fractional_digits_end =
+ exp <= 64 ? PrintFractionalDigitsFast(v, fractional_digits_start, exp,
+ state.precision)
+ : PrintFractionalDigitsFast(static_cast<uint128>(v),
+ fractional_digits_start, exp,
+ state.precision);
+ // There was a carry, so include the first digit too.
+ if (integral_digits_start[-1] != '0') --integral_digits_start;
+ }
+
+ size_t size = fractional_digits_end - integral_digits_start;
+
+ // In `alt` mode (flag #) we keep the `.` even if there are no fractional
+ // digits. In non-alt mode, we strip it.
+ if (!state.ShouldPrintDot()) --size;
+ FinalPrint(state, y_absl::string_view(integral_digits_start, size),
+ /*padding_offset=*/0,
+ static_cast<int>(state.precision - (fractional_digits_end -
+ fractional_digits_start)),
+ /*data_postfix=*/"");
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp > 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to not have fractional digits, so we don't have to
+// worry about anything after the `.`.
+void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
+ BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
+ const size_t total_digits =
+ btd.TotalDigits() +
+ (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+
+ const auto padding = ExtraWidthToPadding(
+ total_digits + (state.sign_char != '\0' ? 1 : 0), state);
+
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(padding.zeros, '0');
+
+ do {
+ state.sink->Append(btd.CurrentDigits());
+ } while (btd.AdvanceDigits());
+
+ if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+ state.sink->Append(state.precision, '0');
+ state.sink->Append(padding.right_spaces, ' ');
+ });
+}
+
+// Slow %f formatter for when the shifted value does not fit in a uint128, and
+// `exp < 0`.
+// Prints `v*2^exp` with the options from `state`.
+// This one is guaranteed to be < 1.0, so we don't have to worry about integral
+// digits.
+void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
+ const size_t total_digits =
+ /* 0 */ 1 +
+ (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
+ auto padding =
+ ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
+ padding.zeros += 1;
+ state.sink->Append(padding.left_spaces, ' ');
+ if (state.sign_char != '\0') state.sink->Append(1, state.sign_char);
+ state.sink->Append(padding.zeros, '0');
+
+ if (state.ShouldPrintDot()) state.sink->Append(1, '.');
+
+ // Print digits
+ int digits_to_go = state.precision;
+
+ FractionalDigitGenerator::RunConversion(
+ v, exp, [&](FractionalDigitGenerator digit_gen) {
+ // There are no digits to print here.
+ if (state.precision == 0) return;
+
+ // We go one digit at a time, while keeping track of runs of nines.
+ // The runs of nines are used to perform rounding when necessary.
+
+ while (digits_to_go > 0 && digit_gen.HasMoreDigits()) {
+ auto digits = digit_gen.GetDigits();
+
+ // Now we have a digit and a run of nines.
+ // See if we can print them all.
+ if (digits.num_nines + 1 < digits_to_go) {
+ // We don't have to round yet, so print them.
+ state.sink->Append(1, digits.digit_before_nine + '0');
+ state.sink->Append(digits.num_nines, '9');
+ digits_to_go -= digits.num_nines + 1;
+
+ } else {
+ // We can't print all the nines, see where we have to truncate.
+
+ bool round_up = false;
+ if (digits.num_nines + 1 > digits_to_go) {
+ // We round up at a nine. No need to print them.
+ round_up = true;
+ } else {
+ // We can fit all the nines, but truncate just after it.
+ if (digit_gen.IsGreaterThanHalf()) {
+ round_up = true;
+ } else if (digit_gen.IsExactlyHalf()) {
+ // Round to even
+ round_up =
+ digits.num_nines != 0 || digits.digit_before_nine % 2 == 1;
+ }
+ }
+
+ if (round_up) {
+ state.sink->Append(1, digits.digit_before_nine + '1');
+ --digits_to_go;
+ // The rest will be zeros.
+ } else {
+ state.sink->Append(1, digits.digit_before_nine + '0');
+ state.sink->Append(digits_to_go - 1, '9');
+ digits_to_go = 0;
+ }
+ return;
+ }
+ }
+ });
+
+ state.sink->Append(digits_to_go, '0');
+ state.sink->Append(padding.right_spaces, ' ');
+}
+
+template <typename Int>
+void FormatF(Int mantissa, int exp, const FormatState &state) {
+ if (exp >= 0) {
+ const int total_bits = sizeof(Int) * 8 - LeadingZeros(mantissa) + exp;
+
+ // Fallback to the slow stack-based approach if we can't do it in a 64 or
+ // 128 bit state.
+ if (ABSL_PREDICT_FALSE(total_bits > 128)) {
+ return FormatFPositiveExpSlow(mantissa, exp, state);
+ }
+ } else {
+ // Fallback to the slow stack-based approach if we can't do it in a 64 or
+ // 128 bit state.
+ if (ABSL_PREDICT_FALSE(exp < -128)) {
+ return FormatFNegativeExpSlow(mantissa, -exp, state);
+ }
+ }
+ return FormatFFast(mantissa, exp, state);
+}
+
+// Grab the group of four bits (nibble) from `n`. E.g., nibble 1 corresponds to
+// bits 4-7.
+template <typename Int>
+uint8_t GetNibble(Int n, int nibble_index) {
+ constexpr Int mask_low_nibble = Int{0xf};
+ int shift = nibble_index * 4;
+ n &= mask_low_nibble << shift;
+ return static_cast<uint8_t>((n >> shift) & 0xf);
+}
+
+// Add one to the given nibble, applying carry to higher nibbles. Returns true
+// if overflow, false otherwise.
+template <typename Int>
+bool IncrementNibble(int nibble_index, Int *n) {
+ constexpr int kShift = sizeof(Int) * 8 - 1;
+ constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+ Int before = *n >> kShift;
+ // Here we essentially want to take the number 1 and move it into the requsted
+ // nibble, then add it to *n to effectively increment the nibble. However,
+ // ASan will complain if we try to shift the 1 beyond the limits of the Int,
+ // i.e., if the nibble_index is out of range. So therefore we check for this
+ // and if we are out of range we just add 0 which leaves *n unchanged, which
+ // seems like the reasonable thing to do in that case.
+ *n += ((nibble_index >= kNumNibbles) ? 0 : (Int{1} << (nibble_index * 4)));
+ Int after = *n >> kShift;
+ return (before && !after) || (nibble_index >= kNumNibbles);
+}
+
+// Return a mask with 1's in the given nibble and all lower nibbles.
+template <typename Int>
+Int MaskUpToNibbleInclusive(int nibble_index) {
+ constexpr int kNumNibbles = sizeof(Int) * 8 / 4;
+ static const Int ones = ~Int{0};
+ return ones >> std::max(0, 4 * (kNumNibbles - nibble_index - 1));
+}
+
+// Return a mask with 1's below the given nibble.
+template <typename Int>
+Int MaskUpToNibbleExclusive(int nibble_index) {
+ return nibble_index <= 0 ? 0 : MaskUpToNibbleInclusive<Int>(nibble_index - 1);
+}
+
+template <typename Int>
+Int MoveToNibble(uint8_t nibble, int nibble_index) {
+ return Int{nibble} << (4 * nibble_index);
+}
+
+// Given mantissa size, find optimal # of mantissa bits to put in initial digit.
+//
+// In the hex representation we keep a single hex digit to the left of the dot.
+// However, the question as to how many bits of the mantissa should be put into
+// that hex digit in theory is arbitrary, but in practice it is optimal to
+// choose based on the size of the mantissa. E.g., for a `double`, there are 53
+// mantissa bits, so that means that we should put 1 bit to the left of the dot,
+// thereby leaving 52 bits to the right, which is evenly divisible by four and
+// thus all fractional digits represent actual precision. For a `long double`,
+// on the other hand, there are 64 bits of mantissa, thus we can use all four
+// bits for the initial hex digit and still have a number left over (60) that is
+// a multiple of four. Once again, the goal is to have all fractional digits
+// represent real precision.
+template <typename Float>
+constexpr int HexFloatLeadingDigitSizeInBits() {
+ return std::numeric_limits<Float>::digits % 4 > 0
+ ? std::numeric_limits<Float>::digits % 4
+ : 4;
+}
+
+// This function captures the rounding behavior of glibc for hex float
+// representations. E.g. when rounding 0x1.ab800000 to a precision of .2
+// ("%.2a") glibc will round up because it rounds toward the even number (since
+// 0xb is an odd number, it will round up to 0xc). However, when rounding at a
+// point that is not followed by 800000..., it disregards the parity and rounds
+// up if > 8 and rounds down if < 8.
+template <typename Int>
+bool HexFloatNeedsRoundUp(Int mantissa, int final_nibble_displayed,
+ uint8_t leading) {
+ // If the last nibble (hex digit) to be displayed is the lowest on in the
+ // mantissa then that means that we don't have any further nibbles to inform
+ // rounding, so don't round.
+ if (final_nibble_displayed <= 0) {
+ return false;
+ }
+ int rounding_nibble_idx = final_nibble_displayed - 1;
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ assert(final_nibble_displayed <= kTotalNibbles);
+ Int mantissa_up_to_rounding_nibble_inclusive =
+ mantissa & MaskUpToNibbleInclusive<Int>(rounding_nibble_idx);
+ Int eight = MoveToNibble<Int>(8, rounding_nibble_idx);
+ if (mantissa_up_to_rounding_nibble_inclusive != eight) {
+ return mantissa_up_to_rounding_nibble_inclusive > eight;
+ }
+ // Nibble in question == 8.
+ uint8_t round_if_odd = (final_nibble_displayed == kTotalNibbles)
+ ? leading
+ : GetNibble(mantissa, final_nibble_displayed);
+ return round_if_odd % 2 == 1;
+}
+
+// Stores values associated with a Float type needed by the FormatA
+// implementation in order to avoid templatizing that function by the Float
+// type.
+struct HexFloatTypeParams {
+ template <typename Float>
+ explicit HexFloatTypeParams(Float)
+ : min_exponent(std::numeric_limits<Float>::min_exponent - 1),
+ leading_digit_size_bits(HexFloatLeadingDigitSizeInBits<Float>()) {
+ assert(leading_digit_size_bits >= 1 && leading_digit_size_bits <= 4);
+ }
+
+ int min_exponent;
+ int leading_digit_size_bits;
+};
+
+// Hex Float Rounding. First check if we need to round; if so, then we do that
+// by manipulating (incrementing) the mantissa, that way we can later print the
+// mantissa digits by iterating through them in the same way regardless of
+// whether a rounding happened.
+template <typename Int>
+void FormatARound(bool precision_specified, const FormatState &state,
+ uint8_t *leading, Int *mantissa, int *exp) {
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ // Index of the last nibble that we could display given precision.
+ int final_nibble_displayed =
+ precision_specified ? std::max(0, (kTotalNibbles - state.precision)) : 0;
+ if (HexFloatNeedsRoundUp(*mantissa, final_nibble_displayed, *leading)) {
+ // Need to round up.
+ bool overflow = IncrementNibble(final_nibble_displayed, mantissa);
+ *leading += (overflow ? 1 : 0);
+ if (ABSL_PREDICT_FALSE(*leading > 15)) {
+ // We have overflowed the leading digit. This would mean that we would
+ // need two hex digits to the left of the dot, which is not allowed. So
+ // adjust the mantissa and exponent so that the result is always 1.0eXXX.
+ *leading = 1;
+ *mantissa = 0;
+ *exp += 4;
+ }
+ }
+ // Now that we have handled a possible round-up we can go ahead and zero out
+ // all the nibbles of the mantissa that we won't need.
+ if (precision_specified) {
+ *mantissa &= ~MaskUpToNibbleExclusive<Int>(final_nibble_displayed);
+ }
+}
+
+template <typename Int>
+void FormatANormalize(const HexFloatTypeParams float_traits, uint8_t *leading,
+ Int *mantissa, int *exp) {
+ constexpr int kIntBits = sizeof(Int) * 8;
+ static const Int kHighIntBit = Int{1} << (kIntBits - 1);
+ const int kLeadDigitBitsCount = float_traits.leading_digit_size_bits;
+ // Normalize mantissa so that highest bit set is in MSB position, unless we
+ // get interrupted by the exponent threshold.
+ while (*mantissa && !(*mantissa & kHighIntBit)) {
+ if (ABSL_PREDICT_FALSE(*exp - 1 < float_traits.min_exponent)) {
+ *mantissa >>= (float_traits.min_exponent - *exp);
+ *exp = float_traits.min_exponent;
+ return;
+ }
+ *mantissa <<= 1;
+ --*exp;
+ }
+ // Extract bits for leading digit then shift them away leaving the
+ // fractional part.
+ *leading =
+ static_cast<uint8_t>(*mantissa >> (kIntBits - kLeadDigitBitsCount));
+ *exp -= (*mantissa != 0) ? kLeadDigitBitsCount : *exp;
+ *mantissa <<= kLeadDigitBitsCount;
+}
+
+template <typename Int>
+void FormatA(const HexFloatTypeParams float_traits, Int mantissa, int exp,
+ bool uppercase, const FormatState &state) {
+ // Int properties.
+ constexpr int kIntBits = sizeof(Int) * 8;
+ constexpr int kTotalNibbles = sizeof(Int) * 8 / 4;
+ // Did the user specify a precision explicitly?
+ const bool precision_specified = state.conv.precision() >= 0;
+
+ // ========== Normalize/Denormalize ==========
+ exp += kIntBits; // make all digits fractional digits.
+ // This holds the (up to four) bits of leading digit, i.e., the '1' in the
+ // number 0x1.e6fp+2. It's always > 0 unless number is zero or denormal.
+ uint8_t leading = 0;
+ FormatANormalize(float_traits, &leading, &mantissa, &exp);
+
+ // =============== Rounding ==================
+ // Check if we need to round; if so, then we do that by manipulating
+ // (incrementing) the mantissa before beginning to print characters.
+ FormatARound(precision_specified, state, &leading, &mantissa, &exp);
+
+ // ============= Format Result ===============
+ // This buffer holds the "0x1.ab1de3" portion of "0x1.ab1de3pe+2". Compute the
+ // size with long double which is the largest of the floats.
+ constexpr size_t kBufSizeForHexFloatRepr =
+ 2 // 0x
+ + std::numeric_limits<MaxFloatType>::digits / 4 // number of hex digits
+ + 1 // round up
+ + 1; // "." (dot)
+ char digits_buffer[kBufSizeForHexFloatRepr];
+ char *digits_iter = digits_buffer;
+ const char *const digits =
+ static_cast<const char *>("0123456789ABCDEF0123456789abcdef") +
+ (uppercase ? 0 : 16);
+
+ // =============== Hex Prefix ================
+ *digits_iter++ = '0';
+ *digits_iter++ = uppercase ? 'X' : 'x';
+
+ // ========== Non-Fractional Digit ===========
+ *digits_iter++ = digits[leading];
+
+ // ================== Dot ====================
+ // There are three reasons we might need a dot. Keep in mind that, at this
+ // point, the mantissa holds only the fractional part.
+ if ((precision_specified && state.precision > 0) ||
+ (!precision_specified && mantissa > 0) || state.conv.has_alt_flag()) {
+ *digits_iter++ = '.';
+ }
+
+ // ============ Fractional Digits ============
+ int digits_emitted = 0;
+ while (mantissa > 0) {
+ *digits_iter++ = digits[GetNibble(mantissa, kTotalNibbles - 1)];
+ mantissa <<= 4;
+ ++digits_emitted;
+ }
+ int trailing_zeros =
+ precision_specified ? state.precision - digits_emitted : 0;
+ assert(trailing_zeros >= 0);
+ auto digits_result = string_view(digits_buffer, digits_iter - digits_buffer);
+
+ // =============== Exponent ==================
+ constexpr size_t kBufSizeForExpDecRepr =
+ numbers_internal::kFastToBufferSize // requred for FastIntToBuffer
+ + 1 // 'p' or 'P'
+ + 1; // '+' or '-'
+ char exp_buffer[kBufSizeForExpDecRepr];
+ exp_buffer[0] = uppercase ? 'P' : 'p';
+ exp_buffer[1] = exp >= 0 ? '+' : '-';
+ numbers_internal::FastIntToBuffer(exp < 0 ? -exp : exp, exp_buffer + 2);
+
+ // ============ Assemble Result ==============
+ FinalPrint(state, //
+ digits_result, // 0xN.NNN...
+ 2, // offset in `data` to start padding if needed.
+ trailing_zeros, // num remaining mantissa padding zeros
+ exp_buffer); // exponent
+}
+
+char *CopyStringTo(y_absl::string_view v, char *out) {
std::memcpy(out, v.data(), v.size());
return out + v.size();
}
template <typename Float>
-bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
+bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
int w = conv.width() >= 0 ? conv.width() : 0;
int p = conv.precision() >= 0 ? conv.precision() : -1;
@@ -951,17 +951,17 @@ bool FallbackToSnprintf(const Float v, const FormatConversionSpecImpl &conv,
if (std::is_same<long double, Float>()) {
*fp++ = 'L';
}
- *fp++ = FormatConversionCharToChar(conv.conversion_char());
+ *fp++ = FormatConversionCharToChar(conv.conversion_char());
*fp = 0;
assert(fp < fmt + sizeof(fmt));
}
TString space(512, '\0');
- y_absl::string_view result;
+ y_absl::string_view result;
while (true) {
int n = snprintf(&space[0], space.size(), fmt, w, p, v);
if (n < 0) return false;
if (static_cast<size_t>(n) < space.size()) {
- result = y_absl::string_view(space.data(), n);
+ result = y_absl::string_view(space.data(), n);
break;
}
space.resize(n + 1);
@@ -1014,24 +1014,24 @@ enum class FormatStyle { Fixed, Precision };
// Otherwise, return false.
template <typename Float>
bool ConvertNonNumericFloats(char sign_char, Float v,
- const FormatConversionSpecImpl &conv,
- FormatSinkImpl *sink) {
+ const FormatConversionSpecImpl &conv,
+ FormatSinkImpl *sink) {
char text[4], *ptr = text;
- if (sign_char != '\0') *ptr++ = sign_char;
+ if (sign_char != '\0') *ptr++ = sign_char;
if (std::isnan(v)) {
- ptr = std::copy_n(
- FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
- ptr);
+ ptr = std::copy_n(
+ FormatConversionCharIsUpper(conv.conversion_char()) ? "NAN" : "nan", 3,
+ ptr);
} else if (std::isinf(v)) {
- ptr = std::copy_n(
- FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3,
- ptr);
+ ptr = std::copy_n(
+ FormatConversionCharIsUpper(conv.conversion_char()) ? "INF" : "inf", 3,
+ ptr);
} else {
return false;
}
return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1,
- conv.has_left_flag());
+ conv.has_left_flag());
}
// Round up the last digit of the value.
@@ -1091,12 +1091,12 @@ constexpr bool CanFitMantissa() {
template <typename Float>
struct Decomposed {
- using MantissaType =
- y_absl::conditional_t<std::is_same<long double, Float>::value, uint128,
- uint64_t>;
- static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
- "");
- MantissaType mantissa;
+ using MantissaType =
+ y_absl::conditional_t<std::is_same<long double, Float>::value, uint128,
+ uint64_t>;
+ static_assert(std::numeric_limits<Float>::digits <= sizeof(MantissaType) * 8,
+ "");
+ MantissaType mantissa;
int exponent;
};
@@ -1107,8 +1107,8 @@ Decomposed<Float> Decompose(Float v) {
Float m = std::frexp(v, &exp);
m = std::ldexp(m, std::numeric_limits<Float>::digits);
exp -= std::numeric_limits<Float>::digits;
-
- return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
+
+ return {static_cast<typename Decomposed<Float>::MantissaType>(m), exp};
}
// Print 'digits' as decimal.
@@ -1277,32 +1277,32 @@ bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out,
return false;
}
-void WriteBufferToSink(char sign_char, y_absl::string_view str,
- const FormatConversionSpecImpl &conv,
- FormatSinkImpl *sink) {
+void WriteBufferToSink(char sign_char, y_absl::string_view str,
+ const FormatConversionSpecImpl &conv,
+ FormatSinkImpl *sink) {
int left_spaces = 0, zeros = 0, right_spaces = 0;
int missing_chars =
conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) -
static_cast<int>(sign_char != 0),
0)
: 0;
- if (conv.has_left_flag()) {
+ if (conv.has_left_flag()) {
right_spaces = missing_chars;
- } else if (conv.has_zero_flag()) {
+ } else if (conv.has_zero_flag()) {
zeros = missing_chars;
} else {
left_spaces = missing_chars;
}
sink->Append(left_spaces, ' ');
- if (sign_char != '\0') sink->Append(1, sign_char);
+ if (sign_char != '\0') sink->Append(1, sign_char);
sink->Append(zeros, '0');
sink->Append(str);
sink->Append(right_spaces, ' ');
}
template <typename Float>
-bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
+bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
// Print the sign or the sign column.
Float abs_v = v;
@@ -1310,9 +1310,9 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
if (std::signbit(abs_v)) {
sign_char = '-';
abs_v = -abs_v;
- } else if (conv.has_show_pos_flag()) {
+ } else if (conv.has_show_pos_flag()) {
sign_char = '+';
- } else if (conv.has_sign_col_flag()) {
+ } else if (conv.has_sign_col_flag()) {
sign_char = ' ';
}
@@ -1329,91 +1329,91 @@ bool FloatToSink(const Float v, const FormatConversionSpecImpl &conv,
Buffer buffer;
- FormatConversionChar c = conv.conversion_char();
-
- if (c == FormatConversionCharInternal::f ||
- c == FormatConversionCharInternal::F) {
- FormatF(decomposed.mantissa, decomposed.exponent,
- {sign_char, precision, conv, sink});
- return true;
- } else if (c == FormatConversionCharInternal::e ||
- c == FormatConversionCharInternal::E) {
- if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
- &exp)) {
- return FallbackToSnprintf(v, conv, sink);
- }
- if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
- PrintExponent(
- exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
- &buffer);
- } else if (c == FormatConversionCharInternal::g ||
- c == FormatConversionCharInternal::G) {
- precision = std::max(0, precision - 1);
- if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
- &exp)) {
- return FallbackToSnprintf(v, conv, sink);
- }
- if (precision + 1 > exp && exp >= -4) {
- if (exp < 0) {
- // Have 1.23456, needs 0.00123456
- // Move the first digit
- buffer.begin[1] = *buffer.begin;
- // Add some zeros
- for (; exp < -1; ++exp) *buffer.begin-- = '0';
- *buffer.begin-- = '.';
- *buffer.begin = '0';
- } else if (exp > 0) {
- // Have 1.23456, needs 1234.56
- // Move the '.' exp positions to the right.
- std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
+ FormatConversionChar c = conv.conversion_char();
+
+ if (c == FormatConversionCharInternal::f ||
+ c == FormatConversionCharInternal::F) {
+ FormatF(decomposed.mantissa, decomposed.exponent,
+ {sign_char, precision, conv, sink});
+ return true;
+ } else if (c == FormatConversionCharInternal::e ||
+ c == FormatConversionCharInternal::E) {
+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+ &exp)) {
+ return FallbackToSnprintf(v, conv, sink);
+ }
+ if (!conv.has_alt_flag() && buffer.back() == '.') buffer.pop_back();
+ PrintExponent(
+ exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+ &buffer);
+ } else if (c == FormatConversionCharInternal::g ||
+ c == FormatConversionCharInternal::G) {
+ precision = std::max(0, precision - 1);
+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer,
+ &exp)) {
+ return FallbackToSnprintf(v, conv, sink);
+ }
+ if (precision + 1 > exp && exp >= -4) {
+ if (exp < 0) {
+ // Have 1.23456, needs 0.00123456
+ // Move the first digit
+ buffer.begin[1] = *buffer.begin;
+ // Add some zeros
+ for (; exp < -1; ++exp) *buffer.begin-- = '0';
+ *buffer.begin-- = '.';
+ *buffer.begin = '0';
+ } else if (exp > 0) {
+ // Have 1.23456, needs 1234.56
+ // Move the '.' exp positions to the right.
+ std::rotate(buffer.begin + 1, buffer.begin + 2, buffer.begin + exp + 2);
}
- exp = 0;
- }
- if (!conv.has_alt_flag()) {
- while (buffer.back() == '0') buffer.pop_back();
- if (buffer.back() == '.') buffer.pop_back();
- }
- if (exp) {
- PrintExponent(
- exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
- &buffer);
- }
- } else if (c == FormatConversionCharInternal::a ||
- c == FormatConversionCharInternal::A) {
- bool uppercase = (c == FormatConversionCharInternal::A);
- FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
- decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
- return true;
- } else {
- return false;
+ exp = 0;
+ }
+ if (!conv.has_alt_flag()) {
+ while (buffer.back() == '0') buffer.pop_back();
+ if (buffer.back() == '.') buffer.pop_back();
+ }
+ if (exp) {
+ PrintExponent(
+ exp, FormatConversionCharIsUpper(conv.conversion_char()) ? 'E' : 'e',
+ &buffer);
+ }
+ } else if (c == FormatConversionCharInternal::a ||
+ c == FormatConversionCharInternal::A) {
+ bool uppercase = (c == FormatConversionCharInternal::A);
+ FormatA(HexFloatTypeParams(Float{}), decomposed.mantissa,
+ decomposed.exponent, uppercase, {sign_char, precision, conv, sink});
+ return true;
+ } else {
+ return false;
}
WriteBufferToSink(sign_char,
- y_absl::string_view(buffer.begin, buffer.end - buffer.begin),
- conv, sink);
+ y_absl::string_view(buffer.begin, buffer.end - buffer.begin),
+ conv, sink);
return true;
}
} // namespace
-bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
- if (IsDoubleDouble()) {
- // This is the `double-double` representation of `long double`. We do not
- // handle it natively. Fallback to snprintf.
- return FallbackToSnprintf(v, conv, sink);
- }
-
+ if (IsDoubleDouble()) {
+ // This is the `double-double` representation of `long double`. We do not
+ // handle it natively. Fallback to snprintf.
+ return FallbackToSnprintf(v, conv, sink);
+ }
+
return FloatToSink(v, conv, sink);
}
-bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
- return FloatToSink(static_cast<double>(v), conv, sink);
+ return FloatToSink(static_cast<double>(v), conv, sink);
}
-bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink) {
return FloatToSink(v, conv, sink);
}
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h
index d93a415756..44e8ee2da2 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/float_conversion.h
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
@@ -21,13 +21,13 @@ namespace y_absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
-bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(float v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
-bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
-bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
+bool ConvertFloatImpl(long double v, const FormatConversionSpecImpl &conv,
FormatSinkImpl *sink);
} // namespace str_format_internal
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h
index 8fc46fbafa..ae997ae7f7 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/output.h
@@ -82,11 +82,11 @@ inline void AbslFormatFlush(BufferRawSink* sink, string_view v) {
sink->Write(v);
}
-// This is a SFINAE to get a better compiler error message when the type
-// is not supported.
+// This is a SFINAE to get a better compiler error message when the type
+// is not supported.
template <typename T>
-auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
- AbslFormatFlush(out, s);
+auto InvokeFlush(T* out, string_view s) -> decltype(AbslFormatFlush(out, s)) {
+ AbslFormatFlush(out, s);
}
} // namespace str_format_internal
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc
index af07e32fe5..c48cdc9ea3 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.cc
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#include "y_absl/strings/internal/str_format/parser.h"
#include <assert.h>
@@ -31,7 +31,7 @@ namespace y_absl {
ABSL_NAMESPACE_BEGIN
namespace str_format_internal {
-using CC = FormatConversionCharInternal;
+using CC = FormatConversionCharInternal;
using LM = LengthMod;
// Abbreviations to fit in the table below.
@@ -299,17 +299,17 @@ struct ParsedFormatBase::ParsedFormatConsumer {
char* data_pos;
};
-ParsedFormatBase::ParsedFormatBase(
- string_view format, bool allow_ignored,
- std::initializer_list<FormatConversionCharSet> convs)
+ParsedFormatBase::ParsedFormatBase(
+ string_view format, bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs)
: data_(format.empty() ? nullptr : new char[format.size()]) {
has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) ||
!MatchesConversions(allow_ignored, convs);
}
bool ParsedFormatBase::MatchesConversions(
- bool allow_ignored,
- std::initializer_list<FormatConversionCharSet> convs) const {
+ bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs) const {
std::unordered_set<int> used;
auto add_if_valid_conv = [&](int pos, char c) {
if (static_cast<size_t>(pos) > convs.size() ||
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h
index ba614bb8b4..4fcdc28c5f 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/parser.h
@@ -1,17 +1,17 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
@@ -78,7 +78,7 @@ struct UnboundConversion {
Flags flags = Flags::kBasic;
LengthMod length_mod = LengthMod::none;
- FormatConversionChar conv = FormatConversionCharInternal::kNone;
+ FormatConversionChar conv = FormatConversionCharInternal::kNone;
};
// Consume conversion spec prefix (not including '%') of [p, end) if valid.
@@ -94,7 +94,7 @@ const char* ConsumeUnboundConversion(const char* p, const char* end,
// conversions.
class ConvTag {
public:
- constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT
+ constexpr ConvTag(FormatConversionChar conversion_char) // NOLINT
: tag_(static_cast<uint8_t>(conversion_char)) {}
constexpr ConvTag(LengthMod length_mod) // NOLINT
: tag_(0x80 | static_cast<uint8_t>(length_mod)) {}
@@ -106,11 +106,11 @@ class ConvTag {
bool is_length() const { return (tag_ & 0xC0) == 0x80; }
bool is_flags() const { return (tag_ & 0xE0) == 0xC0; }
- FormatConversionChar as_conv() const {
+ FormatConversionChar as_conv() const {
assert(is_conv());
assert(!is_length());
assert(!is_flags());
- return static_cast<FormatConversionChar>(tag_);
+ return static_cast<FormatConversionChar>(tag_);
}
LengthMod as_length() const {
assert(!is_conv());
@@ -165,7 +165,7 @@ bool ParseFormatString(string_view src, Consumer consumer) {
auto tag = GetTagForChar(percent[1]);
if (tag.is_conv()) {
if (ABSL_PREDICT_FALSE(next_arg < 0)) {
- // This indicates an error in the format string.
+ // This indicates an error in the format string.
// The only way to get `next_arg < 0` here is to have a positional
// argument first which sets next_arg to -1 and then a non-positional
// argument.
@@ -208,9 +208,9 @@ constexpr bool EnsureConstexpr(string_view s) {
class ParsedFormatBase {
public:
- explicit ParsedFormatBase(
- string_view format, bool allow_ignored,
- std::initializer_list<FormatConversionCharSet> convs);
+ explicit ParsedFormatBase(
+ string_view format, bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs);
ParsedFormatBase(const ParsedFormatBase& other) { *this = other; }
@@ -257,9 +257,9 @@ class ParsedFormatBase {
private:
// Returns whether the conversions match and if !allow_ignored it verifies
// that all conversions are used by the format.
- bool MatchesConversions(
- bool allow_ignored,
- std::initializer_list<FormatConversionCharSet> convs) const;
+ bool MatchesConversions(
+ bool allow_ignored,
+ std::initializer_list<FormatConversionCharSet> convs) const;
struct ParsedFormatConsumer;
@@ -304,14 +304,14 @@ class ParsedFormatBase {
// This is the only API that allows the user to pass a runtime specified format
// string. These factory functions will return NULL if the format does not match
// the conversions requested by the user.
-template <FormatConversionCharSet... C>
+template <FormatConversionCharSet... C>
class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase {
public:
explicit ExtendedParsedFormat(string_view format)
#ifdef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
__attribute__((
enable_if(str_format_internal::EnsureConstexpr(format),
- "Format string is not constexpr."),
+ "Format string is not constexpr."),
enable_if(str_format_internal::ValidFormatImpl<C...>(format),
"Format specified does not match the template arguments.")))
#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make
index ff8069cd0f..2c855146e6 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_format/ya.make
@@ -2,15 +2,15 @@
LIBRARY()
-OWNER(
- somov
- g:cpp-contrib
-)
+OWNER(
+ somov
+ g:cpp-contrib
+)
LICENSE(Apache-2.0)
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
PEERDIR(
contrib/restricted/abseil-cpp-tstring/y_absl/base
contrib/restricted/abseil-cpp-tstring/y_absl/base/internal/raw_logging
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h
index 237864c0ed..874f6f1d45 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/str_split_internal.h
@@ -51,9 +51,9 @@ ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// This class is implicitly constructible from everything that y_absl::string_view
-// is implicitly constructible from, except for rvalue strings. This means it
-// can be used as a function parameter in places where passing a temporary
-// string might cause memory lifetime issues.
+// is implicitly constructible from, except for rvalue strings. This means it
+// can be used as a function parameter in places where passing a temporary
+// string might cause memory lifetime issues.
class ConvertibleToStringView {
public:
ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit)
@@ -65,8 +65,8 @@ class ConvertibleToStringView {
: value_(s) {}
// Disable conversion from rvalue strings.
- ConvertibleToStringView(TString&& s) = delete;
- ConvertibleToStringView(const TString&& s) = delete;
+ ConvertibleToStringView(TString&& s) = delete;
+ ConvertibleToStringView(const TString&& s) = delete;
y_absl::string_view value() const { return value_; }
@@ -251,11 +251,11 @@ struct SplitterIsConvertibleTo
// the split strings: only strings for which the predicate returns true will be
// kept. A Predicate object is any unary functor that takes an y_absl::string_view
// and returns bool.
-//
-// The StringType parameter can be either string_view or string, depending on
-// whether the Splitter refers to a string stored elsewhere, or if the string
-// resides inside the Splitter itself.
-template <typename Delimiter, typename Predicate, typename StringType>
+//
+// The StringType parameter can be either string_view or string, depending on
+// whether the Splitter refers to a string stored elsewhere, or if the string
+// resides inside the Splitter itself.
+template <typename Delimiter, typename Predicate, typename StringType>
class Splitter {
public:
using DelimiterType = Delimiter;
@@ -263,12 +263,12 @@ class Splitter {
using const_iterator = strings_internal::SplitIterator<Splitter>;
using value_type = typename std::iterator_traits<const_iterator>::value_type;
- Splitter(StringType input_text, Delimiter d, Predicate p)
+ Splitter(StringType input_text, Delimiter d, Predicate p)
: text_(std::move(input_text)),
delimiter_(std::move(d)),
predicate_(std::move(p)) {}
- y_absl::string_view text() const { return text_; }
+ y_absl::string_view text() const { return text_; }
const Delimiter& delimiter() const { return delimiter_; }
const Predicate& predicate() const { return predicate_; }
@@ -318,7 +318,7 @@ class Splitter {
Container operator()(const Splitter& splitter) const {
Container c;
auto it = std::inserter(c, c.end());
- for (const auto& sp : splitter) {
+ for (const auto& sp : splitter) {
*it++ = ValueType(sp);
}
return c;
@@ -418,7 +418,7 @@ class Splitter {
static iterator ToIter(iterator iter) { return iter; }
};
- StringType text_;
+ StringType text_;
Delimiter delimiter_;
Predicate predicate_;
};
diff --git a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h
index b18e821b49..df4fc0357e 100644
--- a/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h
+++ b/contrib/restricted/abseil-cpp-tstring/y_absl/strings/internal/string_constant.h
@@ -1,64 +1,64 @@
-// Copyright 2020 The Abseil Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
-#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
-
-#include "y_absl/meta/type_traits.h"
-#include "y_absl/strings/string_view.h"
-
-namespace y_absl {
-ABSL_NAMESPACE_BEGIN
-namespace strings_internal {
-
-// StringConstant<T> represents a compile time string constant.
-// It can be accessed via its `y_absl::string_view value` static member.
-// It is guaranteed that the `string_view` returned has constant `.data()`,
-// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
-//
-// The `T` is an opaque type. It is guaranteed that different string constants
-// will have different values of `T`. This allows users to associate the string
-// constant with other static state at compile time.
-//
-// Instances should be made using the `MakeStringConstant()` factory function
-// below.
-template <typename T>
-struct StringConstant {
- static constexpr y_absl::string_view value = T{}();
- constexpr y_absl::string_view operator()() const { return value; }
-
- // Check to be sure `view` points to constant data.
- // Otherwise, it can't be constant evaluated.
- static_assert(value.empty() || 2 * value[0] != 1,
- "The input string_view must point to constant data.");
-};
-
-template <typename T>
-constexpr y_absl::string_view StringConstant<T>::value; // NOLINT
-
-// Factory function for `StringConstant` instances.
-// It supports callables that have a constexpr default constructor and a
-// constexpr operator().
-// It must return an `y_absl::string_view` or `const char*` pointing to constant
-// data. This is validated at compile time.
-template <typename T>
-constexpr StringConstant<T> MakeStringConstant(T) {
- return {};
-}
-
-} // namespace strings_internal
-ABSL_NAMESPACE_END
-} // namespace y_absl
-
-#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
+
+#include "y_absl/meta/type_traits.h"
+#include "y_absl/strings/string_view.h"
+
+namespace y_absl {
+ABSL_NAMESPACE_BEGIN
+namespace strings_internal {
+
+// StringConstant<T> represents a compile time string constant.
+// It can be accessed via its `y_absl::string_view value` static member.
+// It is guaranteed that the `string_view` returned has constant `.data()`,
+// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
+//
+// The `T` is an opaque type. It is guaranteed that different string constants
+// will have different values of `T`. This allows users to associate the string
+// constant with other static state at compile time.
+//
+// Instances should be made using the `MakeStringConstant()` factory function
+// below.
+template <typename T>
+struct StringConstant {
+ static constexpr y_absl::string_view value = T{}();
+ constexpr y_absl::string_view operator()() const { return value; }
+
+ // Check to be sure `view` points to constant data.
+ // Otherwise, it can't be constant evaluated.
+ static_assert(value.empty() || 2 * value[0] != 1,
+ "The input string_view must point to constant data.");
+};
+
+template <typename T>
+constexpr y_absl::string_view StringConstant<T>::value; // NOLINT
+
+// Factory function for `StringConstant` instances.
+// It supports callables that have a constexpr default constructor and a
+// constexpr operator().
+// It must return an `y_absl::string_view` or `const char*` pointing to constant
+// data. This is validated at compile time.
+template <typename T>
+constexpr StringConstant<T> MakeStringConstant(T) {
+ return {};
+}
+
+} // namespace strings_internal
+ABSL_NAMESPACE_END
+} // namespace y_absl
+
+#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_