修改pods
This commit is contained in:
103
Pods/abseil/absl/strings/ascii.cc
generated
103
Pods/abseil/absl/strings/ascii.cc
generated
@@ -15,13 +15,14 @@
|
||||
#include "absl/strings/ascii.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
@@ -162,19 +163,6 @@ ABSL_DLL const char kToUpper[256] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
template <class T>
|
||||
static constexpr T BroadcastByte(unsigned char value) {
|
||||
static_assert(std::is_integral<T>::value && sizeof(T) <= sizeof(uint64_t) &&
|
||||
std::is_unsigned<T>::value,
|
||||
"only unsigned integers up to 64-bit allowed");
|
||||
T result = value;
|
||||
constexpr size_t result_bit_width = sizeof(result) * CHAR_BIT;
|
||||
result |= result << ((CHAR_BIT << 0) & (result_bit_width - 1));
|
||||
result |= result << ((CHAR_BIT << 1) & (result_bit_width - 1));
|
||||
result |= result << ((CHAR_BIT << 2) & (result_bit_width - 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns whether `c` is in the a-z/A-Z range (w.r.t. `ToUpper`).
|
||||
// Implemented by:
|
||||
// 1. Pushing the a-z/A-Z range to [SCHAR_MIN, SCHAR_MIN + 26).
|
||||
@@ -189,47 +177,10 @@ constexpr bool AsciiInAZRange(unsigned char c) {
|
||||
return static_cast<signed char>(u) < threshold;
|
||||
}
|
||||
|
||||
// Force-inline so the compiler won't merge the short and long implementations.
|
||||
template <bool ToUpper>
|
||||
static constexpr char* PartialAsciiStrCaseFold(absl::Nonnull<char*> p,
|
||||
absl::Nonnull<char*> end) {
|
||||
using vec_t = size_t;
|
||||
const size_t n = static_cast<size_t>(end - p);
|
||||
|
||||
// SWAR algorithm: http://0x80.pl/notesen/2016-01-06-swar-swap-case.html
|
||||
constexpr char ch_a = ToUpper ? 'a' : 'A', ch_z = ToUpper ? 'z' : 'Z';
|
||||
char* const swar_end = p + (n / sizeof(vec_t)) * sizeof(vec_t);
|
||||
while (p < swar_end) {
|
||||
vec_t v = vec_t();
|
||||
|
||||
// memcpy the vector, but constexpr
|
||||
for (size_t i = 0; i < sizeof(vec_t); ++i) {
|
||||
v |= static_cast<vec_t>(static_cast<unsigned char>(p[i]))
|
||||
<< (i * CHAR_BIT);
|
||||
}
|
||||
|
||||
constexpr unsigned int msb = 1u << (CHAR_BIT - 1);
|
||||
const vec_t v_msb = v & BroadcastByte<vec_t>(msb);
|
||||
const vec_t v_nonascii_mask = (v_msb << 1) - (v_msb >> (CHAR_BIT - 1));
|
||||
const vec_t v_nonascii = v & v_nonascii_mask;
|
||||
const vec_t v_ascii = v & ~v_nonascii_mask;
|
||||
const vec_t a = v_ascii + BroadcastByte<vec_t>(msb - ch_a - 0),
|
||||
z = v_ascii + BroadcastByte<vec_t>(msb - ch_z - 1);
|
||||
v = v_nonascii | (v_ascii ^ ((a ^ z) & BroadcastByte<vec_t>(msb)) >> 2);
|
||||
|
||||
// memcpy the vector, but constexpr
|
||||
for (size_t i = 0; i < sizeof(vec_t); ++i) {
|
||||
p[i] = static_cast<char>(v >> (i * CHAR_BIT));
|
||||
}
|
||||
|
||||
p += sizeof(v);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
template <bool ToUpper>
|
||||
static constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p,
|
||||
absl::Nonnull<char*> end) {
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline constexpr void AsciiStrCaseFoldImpl(
|
||||
absl::Nonnull<char*> p, size_t size) {
|
||||
// The upper- and lowercase versions of ASCII characters differ by only 1 bit.
|
||||
// When we need to flip the case, we can xor with this bit to achieve the
|
||||
// desired result. Note that the choice of 'a' and 'A' here is arbitrary. We
|
||||
@@ -237,20 +188,32 @@ static constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p,
|
||||
// have the same single bit difference.
|
||||
constexpr unsigned char kAsciiCaseBitFlip = 'a' ^ 'A';
|
||||
|
||||
using vec_t = size_t;
|
||||
// TODO(b/316380338): When FDO becomes able to vectorize these,
|
||||
// revert this manual optimization and just leave the naive loop.
|
||||
if (static_cast<size_t>(end - p) >= sizeof(vec_t)) {
|
||||
p = ascii_internal::PartialAsciiStrCaseFold<ToUpper>(p, end);
|
||||
}
|
||||
while (p < end) {
|
||||
unsigned char v = static_cast<unsigned char>(*p);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
unsigned char v = static_cast<unsigned char>(p[i]);
|
||||
v ^= AsciiInAZRange<ToUpper>(v) ? kAsciiCaseBitFlip : 0;
|
||||
*p = static_cast<char>(v);
|
||||
++p;
|
||||
p[i] = static_cast<char>(v);
|
||||
}
|
||||
}
|
||||
|
||||
// The string size threshold for starting using the long string version.
|
||||
constexpr size_t kCaseFoldThreshold = 16;
|
||||
|
||||
// No-inline so the compiler won't merge the short and long implementations.
|
||||
template <bool ToUpper>
|
||||
ABSL_ATTRIBUTE_NOINLINE constexpr void AsciiStrCaseFoldLong(
|
||||
absl::Nonnull<char*> p, size_t size) {
|
||||
ABSL_ASSUME(size >= kCaseFoldThreshold);
|
||||
AsciiStrCaseFoldImpl<ToUpper>(p, size);
|
||||
}
|
||||
|
||||
// Splitting to short and long strings to allow vectorization decisions
|
||||
// to be made separately in the long and short cases.
|
||||
template <bool ToUpper>
|
||||
constexpr void AsciiStrCaseFold(absl::Nonnull<char*> p, size_t size) {
|
||||
size < kCaseFoldThreshold ? AsciiStrCaseFoldImpl<ToUpper>(p, size)
|
||||
: AsciiStrCaseFoldLong<ToUpper>(p, size);
|
||||
}
|
||||
|
||||
static constexpr size_t ValidateAsciiCasefold() {
|
||||
constexpr size_t num_chars = 1 + CHAR_MAX - CHAR_MIN;
|
||||
size_t incorrect_index = 0;
|
||||
@@ -259,8 +222,8 @@ static constexpr size_t ValidateAsciiCasefold() {
|
||||
for (unsigned int i = 0; i < num_chars; ++i) {
|
||||
uppered[i] = lowered[i] = static_cast<char>(i);
|
||||
}
|
||||
AsciiStrCaseFold<false>(&lowered[0], &lowered[num_chars]);
|
||||
AsciiStrCaseFold<true>(&uppered[0], &uppered[num_chars]);
|
||||
AsciiStrCaseFold<false>(&lowered[0], num_chars);
|
||||
AsciiStrCaseFold<true>(&uppered[0], num_chars);
|
||||
for (size_t i = 0; i < num_chars; ++i) {
|
||||
const char ch = static_cast<char>(i),
|
||||
ch_upper = ('a' <= ch && ch <= 'z' ? 'A' + (ch - 'a') : ch),
|
||||
@@ -278,13 +241,11 @@ static_assert(ValidateAsciiCasefold() == 0, "error in case conversion");
|
||||
} // namespace ascii_internal
|
||||
|
||||
void AsciiStrToLower(absl::Nonnull<std::string*> s) {
|
||||
char* p = &(*s)[0]; // Guaranteed to be valid for empty strings
|
||||
return ascii_internal::AsciiStrCaseFold<false>(p, p + s->size());
|
||||
return ascii_internal::AsciiStrCaseFold<false>(&(*s)[0], s->size());
|
||||
}
|
||||
|
||||
void AsciiStrToUpper(absl::Nonnull<std::string*> s) {
|
||||
char* p = &(*s)[0]; // Guaranteed to be valid for empty strings
|
||||
return ascii_internal::AsciiStrCaseFold<true>(p, p + s->size());
|
||||
return ascii_internal::AsciiStrCaseFold<true>(&(*s)[0], s->size());
|
||||
}
|
||||
|
||||
void RemoveExtraAsciiWhitespace(absl::Nonnull<std::string*> str) {
|
||||
|
||||
35
Pods/abseil/absl/strings/cord.cc
generated
35
Pods/abseil/absl/strings/cord.cc
generated
@@ -75,7 +75,7 @@ using ::absl::cord_internal::kMinFlatLength;
|
||||
using ::absl::cord_internal::kInlinedVectorSize;
|
||||
using ::absl::cord_internal::kMaxBytesToCopy;
|
||||
|
||||
static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data,
|
||||
static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
|
||||
absl::Nonnull<std::ostream*> os, int indent = 0);
|
||||
static bool VerifyNode(absl::Nonnull<CordRep*> root,
|
||||
absl::Nonnull<CordRep*> start_node);
|
||||
@@ -425,8 +425,8 @@ Cord& Cord::operator=(absl::string_view src) {
|
||||
// we keep it here to make diffs easier.
|
||||
void Cord::InlineRep::AppendArray(absl::string_view src,
|
||||
MethodIdentifier method) {
|
||||
MaybeRemoveEmptyCrcNode();
|
||||
if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined.
|
||||
MaybeRemoveEmptyCrcNode();
|
||||
|
||||
size_t appended = 0;
|
||||
CordRep* rep = tree();
|
||||
@@ -1062,6 +1062,15 @@ void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
|
||||
}
|
||||
}
|
||||
|
||||
void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst) {
|
||||
const size_t cur_dst_size = dst->size();
|
||||
const size_t new_dst_size = cur_dst_size + src.size();
|
||||
absl::strings_internal::STLStringResizeUninitializedAmortized(dst,
|
||||
new_dst_size);
|
||||
char* append_ptr = &(*dst)[cur_dst_size];
|
||||
src.CopyToArrayImpl(append_ptr);
|
||||
}
|
||||
|
||||
void Cord::CopyToArraySlowPath(absl::Nonnull<char*> dst) const {
|
||||
assert(contents_.is_tree());
|
||||
absl::string_view fragment;
|
||||
@@ -1448,14 +1457,13 @@ absl::string_view Cord::FlattenSlowPath() {
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data,
|
||||
static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
|
||||
absl::Nonnull<std::ostream*> os, int indent) {
|
||||
CordRep* rep = nonnull_rep;
|
||||
const int kIndentStep = 1;
|
||||
absl::InlinedVector<CordRep*, kInlinedVectorSize> stack;
|
||||
absl::InlinedVector<int, kInlinedVectorSize> indents;
|
||||
for (;;) {
|
||||
*os << std::setw(3) << rep->refcount.Get();
|
||||
*os << " " << std::setw(7) << rep->length;
|
||||
*os << std::setw(3) << (rep == nullptr ? 0 : rep->refcount.Get());
|
||||
*os << " " << std::setw(7) << (rep == nullptr ? 0 : rep->length);
|
||||
*os << " [";
|
||||
if (include_data) *os << static_cast<void*>(rep);
|
||||
*os << "]";
|
||||
@@ -1477,26 +1485,23 @@ static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data,
|
||||
if (rep->IsExternal()) {
|
||||
*os << "EXTERNAL [";
|
||||
if (include_data)
|
||||
*os << absl::CEscape(std::string(rep->external()->base, rep->length));
|
||||
*os << absl::CEscape(
|
||||
absl::string_view(rep->external()->base, rep->length));
|
||||
*os << "]\n";
|
||||
} else if (rep->IsFlat()) {
|
||||
*os << "FLAT cap=" << rep->flat()->Capacity() << " [";
|
||||
if (include_data)
|
||||
*os << absl::CEscape(std::string(rep->flat()->Data(), rep->length));
|
||||
*os << absl::CEscape(
|
||||
absl::string_view(rep->flat()->Data(), rep->length));
|
||||
*os << "]\n";
|
||||
} else {
|
||||
CordRepBtree::Dump(rep, /*label=*/"", include_data, *os);
|
||||
}
|
||||
}
|
||||
if (leaf) {
|
||||
if (stack.empty()) break;
|
||||
rep = stack.back();
|
||||
stack.pop_back();
|
||||
indent = indents.back();
|
||||
indents.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ABSL_INTERNAL_CHECK(indents.empty(), "");
|
||||
}
|
||||
|
||||
static std::string ReportError(absl::Nonnull<CordRep*> root,
|
||||
|
||||
75
Pods/abseil/absl/strings/cord.h
generated
75
Pods/abseil/absl/strings/cord.h
generated
@@ -75,6 +75,7 @@
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
#include "absl/crc/internal/crc_cord_state.h"
|
||||
@@ -95,6 +96,7 @@
|
||||
#include "absl/strings/internal/resize_uninitialized.h"
|
||||
#include "absl/strings/internal/string_constant.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/compare.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
@@ -104,6 +106,7 @@ class CordTestPeer;
|
||||
template <typename Releaser>
|
||||
Cord MakeCordFromExternal(absl::string_view, Releaser&&);
|
||||
void CopyCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
|
||||
void AppendCordToString(const Cord& src, absl::Nonnull<std::string*> dst);
|
||||
|
||||
// Cord memory accounting modes
|
||||
enum class CordMemoryAccounting {
|
||||
@@ -420,6 +423,18 @@ class Cord {
|
||||
friend void CopyCordToString(const Cord& src,
|
||||
absl::Nonnull<std::string*> dst);
|
||||
|
||||
// AppendCordToString()
|
||||
//
|
||||
// Appends the contents of a `src` Cord to a `*dst` string.
|
||||
//
|
||||
// This function optimizes the case of appending to a non-empty destination
|
||||
// string. If `*dst` already has capacity to store the contents of the cord,
|
||||
// this function does not invalidate pointers previously returned by
|
||||
// `dst->data()`. If `*dst` is a new object, prefer to simply use the
|
||||
// conversion operator to `std::string`.
|
||||
friend void AppendCordToString(const Cord& src,
|
||||
absl::Nonnull<std::string*> dst);
|
||||
|
||||
class CharIterator;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -757,7 +772,7 @@ class Cord {
|
||||
|
||||
// Cord::Find()
|
||||
//
|
||||
// Returns an iterator to the first occurrance of the substring `needle`.
|
||||
// Returns an iterator to the first occurrence of the substring `needle`.
|
||||
//
|
||||
// If the substring `needle` does not occur, `Cord::char_end()` is returned.
|
||||
CharIterator Find(absl::string_view needle) const;
|
||||
@@ -835,6 +850,38 @@ class Cord {
|
||||
friend bool operator==(const Cord& lhs, const Cord& rhs);
|
||||
friend bool operator==(const Cord& lhs, absl::string_view rhs);
|
||||
|
||||
#ifdef __cpp_impl_three_way_comparison
|
||||
|
||||
// Cords support comparison with other Cords and string_views via operator<
|
||||
// and others; here we provide a wrapper for the C++20 three-way comparison
|
||||
// <=> operator.
|
||||
|
||||
static inline std::strong_ordering ConvertCompareResultToStrongOrdering(
|
||||
int c) {
|
||||
if (c == 0) {
|
||||
return std::strong_ordering::equal;
|
||||
} else if (c < 0) {
|
||||
return std::strong_ordering::less;
|
||||
} else {
|
||||
return std::strong_ordering::greater;
|
||||
}
|
||||
}
|
||||
|
||||
friend inline std::strong_ordering operator<=>(const Cord& x, const Cord& y) {
|
||||
return ConvertCompareResultToStrongOrdering(x.Compare(y));
|
||||
}
|
||||
|
||||
friend inline std::strong_ordering operator<=>(const Cord& lhs,
|
||||
absl::string_view rhs) {
|
||||
return ConvertCompareResultToStrongOrdering(lhs.Compare(rhs));
|
||||
}
|
||||
|
||||
friend inline std::strong_ordering operator<=>(absl::string_view lhs,
|
||||
const Cord& rhs) {
|
||||
return ConvertCompareResultToStrongOrdering(-rhs.Compare(lhs));
|
||||
}
|
||||
#endif
|
||||
|
||||
friend absl::Nullable<const CordzInfo*> GetCordzInfoForTesting(
|
||||
const Cord& cord);
|
||||
|
||||
@@ -1065,6 +1112,8 @@ class Cord {
|
||||
const;
|
||||
|
||||
CharIterator FindImpl(CharIterator it, absl::string_view needle) const;
|
||||
|
||||
void CopyToArrayImpl(absl::Nonnull<char*> dst) const;
|
||||
};
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
@@ -1103,8 +1152,8 @@ absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data,
|
||||
// Overload for function reference types that dispatches using a function
|
||||
// pointer because there are no `alignof()` or `sizeof()` a function reference.
|
||||
// NOLINTNEXTLINE - suppress clang-tidy raw pointer return.
|
||||
inline absl::Nonnull<CordRep*> NewExternalRep(absl::string_view data,
|
||||
void (&releaser)(absl::string_view)) {
|
||||
inline absl::Nonnull<CordRep*> NewExternalRep(
|
||||
absl::string_view data, void (&releaser)(absl::string_view)) {
|
||||
return NewExternalRep(data, &releaser);
|
||||
}
|
||||
|
||||
@@ -1120,7 +1169,7 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
|
||||
} else {
|
||||
using ReleaserType = absl::decay_t<Releaser>;
|
||||
cord_internal::InvokeReleaser(
|
||||
cord_internal::Rank0{}, ReleaserType(std::forward<Releaser>(releaser)),
|
||||
cord_internal::Rank1{}, ReleaserType(std::forward<Releaser>(releaser)),
|
||||
data);
|
||||
}
|
||||
return cord;
|
||||
@@ -1170,7 +1219,8 @@ inline void Cord::InlineRep::Swap(absl::Nonnull<Cord::InlineRep*> rhs) {
|
||||
if (rhs == this) {
|
||||
return;
|
||||
}
|
||||
std::swap(data_, rhs->data_);
|
||||
using std::swap;
|
||||
swap(data_, rhs->data_);
|
||||
}
|
||||
|
||||
inline absl::Nullable<const char*> Cord::InlineRep::data() const {
|
||||
@@ -1352,7 +1402,8 @@ inline size_t Cord::EstimatedMemoryUsage(
|
||||
return result;
|
||||
}
|
||||
|
||||
inline absl::optional<absl::string_view> Cord::TryFlat() const {
|
||||
inline absl::optional<absl::string_view> Cord::TryFlat() const
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
absl::cord_internal::CordRep* rep = contents_.tree();
|
||||
if (rep == nullptr) {
|
||||
return absl::string_view(contents_.data(), contents_.size());
|
||||
@@ -1364,7 +1415,7 @@ inline absl::optional<absl::string_view> Cord::TryFlat() const {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
inline absl::string_view Cord::Flatten() {
|
||||
inline absl::string_view Cord::Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
absl::cord_internal::CordRep* rep = contents_.tree();
|
||||
if (rep == nullptr) {
|
||||
return absl::string_view(contents_.data(), contents_.size());
|
||||
@@ -1387,6 +1438,7 @@ inline void Cord::Prepend(absl::string_view src) {
|
||||
|
||||
inline void Cord::Append(CordBuffer buffer) {
|
||||
if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return;
|
||||
contents_.MaybeRemoveEmptyCrcNode();
|
||||
absl::string_view short_value;
|
||||
if (CordRep* rep = buffer.ConsumeValue(short_value)) {
|
||||
contents_.AppendTree(rep, CordzUpdateTracker::kAppendCordBuffer);
|
||||
@@ -1397,6 +1449,7 @@ inline void Cord::Append(CordBuffer buffer) {
|
||||
|
||||
inline void Cord::Prepend(CordBuffer buffer) {
|
||||
if (ABSL_PREDICT_FALSE(buffer.length() == 0)) return;
|
||||
contents_.MaybeRemoveEmptyCrcNode();
|
||||
absl::string_view short_value;
|
||||
if (CordRep* rep = buffer.ConsumeValue(short_value)) {
|
||||
contents_.PrependTree(rep, CordzUpdateTracker::kPrependCordBuffer);
|
||||
@@ -1445,6 +1498,14 @@ inline bool Cord::StartsWith(absl::string_view rhs) const {
|
||||
return EqualsImpl(rhs, rhs_size);
|
||||
}
|
||||
|
||||
inline void Cord::CopyToArrayImpl(absl::Nonnull<char*> dst) const {
|
||||
if (!contents_.is_tree()) {
|
||||
if (!empty()) contents_.CopyToArray(dst);
|
||||
} else {
|
||||
CopyToArraySlowPath(dst);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Cord::ChunkIterator::InitTree(
|
||||
absl::Nonnull<cord_internal::CordRep*> tree) {
|
||||
tree = cord_internal::SkipCrcNode(tree);
|
||||
|
||||
117
Pods/abseil/absl/strings/escaping.cc
generated
117
Pods/abseil/absl/strings/escaping.cc
generated
@@ -21,10 +21,12 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/unaligned_access.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/charset.h"
|
||||
#include "absl/strings/internal/escaping.h"
|
||||
@@ -54,7 +56,8 @@ inline unsigned int hex_digit_to_int(char c) {
|
||||
return x & 0xf;
|
||||
}
|
||||
|
||||
inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) {
|
||||
inline bool IsSurrogate(char32_t c, absl::string_view src,
|
||||
absl::Nullable<std::string*> error) {
|
||||
if (c >= 0xD800 && c <= 0xDFFF) {
|
||||
if (error) {
|
||||
*error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\",
|
||||
@@ -83,7 +86,9 @@ inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) {
|
||||
// UnescapeCEscapeSequences().
|
||||
// ----------------------------------------------------------------------
|
||||
bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
|
||||
char* dest, ptrdiff_t* dest_len, std::string* error) {
|
||||
absl::Nonnull<char*> dest,
|
||||
absl::Nonnull<ptrdiff_t*> dest_len,
|
||||
absl::Nullable<std::string*> error) {
|
||||
char* d = dest;
|
||||
const char* p = source.data();
|
||||
const char* end = p + source.size();
|
||||
@@ -290,7 +295,8 @@ bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
|
||||
// may be the same.
|
||||
// ----------------------------------------------------------------------
|
||||
bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped,
|
||||
std::string* dest, std::string* error) {
|
||||
absl::Nonnull<std::string*> dest,
|
||||
absl::Nullable<std::string*> error) {
|
||||
strings_internal::STLStringResizeUninitialized(dest, source.size());
|
||||
|
||||
ptrdiff_t dest_size;
|
||||
@@ -362,7 +368,7 @@ std::string CEscapeInternal(absl::string_view src, bool use_hex,
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
constexpr unsigned char c_escaped_len[256] = {
|
||||
constexpr unsigned char kCEscapedLen[256] = {
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
|
||||
@@ -387,12 +393,28 @@ constexpr unsigned char c_escaped_len[256] = {
|
||||
// that UTF-8 bytes are not handled specially.
|
||||
inline size_t CEscapedLength(absl::string_view src) {
|
||||
size_t escaped_len = 0;
|
||||
for (char c : src)
|
||||
escaped_len += c_escaped_len[static_cast<unsigned char>(c)];
|
||||
// The maximum value of kCEscapedLen[x] is 4, so we can escape any string of
|
||||
// length size_t_max/4 without checking for overflow.
|
||||
size_t unchecked_limit =
|
||||
std::min<size_t>(src.size(), std::numeric_limits<size_t>::max() / 4);
|
||||
size_t i = 0;
|
||||
while (i < unchecked_limit) {
|
||||
// Common case: No need to check for overflow.
|
||||
escaped_len += kCEscapedLen[static_cast<unsigned char>(src[i++])];
|
||||
}
|
||||
while (i < src.size()) {
|
||||
// Beyond unchecked_limit we need to check for overflow before adding.
|
||||
size_t char_len = kCEscapedLen[static_cast<unsigned char>(src[i++])];
|
||||
ABSL_INTERNAL_CHECK(
|
||||
escaped_len <= std::numeric_limits<size_t>::max() - char_len,
|
||||
"escaped_len overflow");
|
||||
escaped_len += char_len;
|
||||
}
|
||||
return escaped_len;
|
||||
}
|
||||
|
||||
void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
|
||||
void CEscapeAndAppendInternal(absl::string_view src,
|
||||
absl::Nonnull<std::string*> dest) {
|
||||
size_t escaped_len = CEscapedLength(src);
|
||||
if (escaped_len == src.size()) {
|
||||
dest->append(src.data(), src.size());
|
||||
@@ -400,12 +422,15 @@ void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
|
||||
}
|
||||
|
||||
size_t cur_dest_len = dest->size();
|
||||
ABSL_INTERNAL_CHECK(
|
||||
cur_dest_len <= std::numeric_limits<size_t>::max() - escaped_len,
|
||||
"std::string size overflow");
|
||||
strings_internal::STLStringResizeUninitialized(dest,
|
||||
cur_dest_len + escaped_len);
|
||||
char* append_ptr = &(*dest)[cur_dest_len];
|
||||
|
||||
for (char c : src) {
|
||||
size_t char_len = c_escaped_len[static_cast<unsigned char>(c)];
|
||||
size_t char_len = kCEscapedLen[static_cast<unsigned char>(c)];
|
||||
if (char_len == 1) {
|
||||
*append_ptr++ = c;
|
||||
} else if (char_len == 2) {
|
||||
@@ -446,9 +471,10 @@ void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
|
||||
|
||||
// Reverses the mapping in Base64EscapeInternal; see that method's
|
||||
// documentation for details of the mapping.
|
||||
bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
|
||||
size_t szdest, const signed char* unbase64,
|
||||
size_t* len) {
|
||||
bool Base64UnescapeInternal(absl::Nullable<const char*> src_param, size_t szsrc,
|
||||
absl::Nullable<char*> dest, size_t szdest,
|
||||
absl::Nonnull<const signed char*> unbase64,
|
||||
absl::Nonnull<size_t*> len) {
|
||||
static const char kPad64Equals = '=';
|
||||
static const char kPad64Dot = '.';
|
||||
|
||||
@@ -784,8 +810,9 @@ constexpr signed char kUnWebSafeBase64[] = {
|
||||
/* clang-format on */
|
||||
|
||||
template <typename String>
|
||||
bool Base64UnescapeInternal(const char* src, size_t slen, String* dest,
|
||||
const signed char* unbase64) {
|
||||
bool Base64UnescapeInternal(absl::Nullable<const char*> src, size_t slen,
|
||||
absl::Nonnull<String*> dest,
|
||||
absl::Nonnull<const signed char*> unbase64) {
|
||||
// Determine the size of the output string. Base64 encodes every 3 bytes into
|
||||
// 4 characters. Any leftover chars are added directly for good measure.
|
||||
const size_t dest_len = 3 * (slen / 4) + (slen % 4);
|
||||
@@ -829,13 +856,32 @@ constexpr char kHexValueLenient[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
constexpr signed char kHexValueStrict[256] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // '0'..'9'
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 'A'..'F'
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 'a'..'f'
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
// This is a templated function so that T can be either a char*
|
||||
// or a string. This works because we use the [] operator to access
|
||||
// individual characters at a time.
|
||||
template <typename T>
|
||||
void HexStringToBytesInternal(const char* from, T to, size_t num) {
|
||||
void HexStringToBytesInternal(absl::Nullable<const char*> from, T to,
|
||||
size_t num) {
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
to[i] = static_cast<char>(kHexValueLenient[from[i * 2] & 0xFF] << 4) +
|
||||
(kHexValueLenient[from[i * 2 + 1] & 0xFF]);
|
||||
@@ -845,7 +891,8 @@ void HexStringToBytesInternal(const char* from, T to, size_t num) {
|
||||
// This is a templated function so that T can be either a char* or a
|
||||
// std::string.
|
||||
template <typename T>
|
||||
void BytesToHexStringInternal(const unsigned char* src, T dest, size_t num) {
|
||||
void BytesToHexStringInternal(absl::Nullable<const unsigned char*> src, T dest,
|
||||
size_t num) {
|
||||
auto dest_ptr = &dest[0];
|
||||
for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
|
||||
const char* hex_p = &numbers_internal::kHexTable[*src_ptr * 2];
|
||||
@@ -860,8 +907,8 @@ void BytesToHexStringInternal(const unsigned char* src, T dest, size_t num) {
|
||||
//
|
||||
// See CUnescapeInternal() for implementation details.
|
||||
// ----------------------------------------------------------------------
|
||||
bool CUnescape(absl::string_view source, std::string* dest,
|
||||
std::string* error) {
|
||||
bool CUnescape(absl::string_view source, absl::Nonnull<std::string*> dest,
|
||||
absl::Nullable<std::string*> error) {
|
||||
return CUnescapeInternal(source, kUnescapeNulls, dest, error);
|
||||
}
|
||||
|
||||
@@ -883,21 +930,23 @@ std::string Utf8SafeCHexEscape(absl::string_view src) {
|
||||
return CEscapeInternal(src, true, true);
|
||||
}
|
||||
|
||||
bool Base64Unescape(absl::string_view src, std::string* dest) {
|
||||
bool Base64Unescape(absl::string_view src, absl::Nonnull<std::string*> dest) {
|
||||
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
|
||||
}
|
||||
|
||||
bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) {
|
||||
bool WebSafeBase64Unescape(absl::string_view src,
|
||||
absl::Nonnull<std::string*> dest) {
|
||||
return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
|
||||
}
|
||||
|
||||
void Base64Escape(absl::string_view src, std::string* dest) {
|
||||
void Base64Escape(absl::string_view src, absl::Nonnull<std::string*> dest) {
|
||||
strings_internal::Base64EscapeInternal(
|
||||
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
|
||||
true, strings_internal::kBase64Chars);
|
||||
}
|
||||
|
||||
void WebSafeBase64Escape(absl::string_view src, std::string* dest) {
|
||||
void WebSafeBase64Escape(absl::string_view src,
|
||||
absl::Nonnull<std::string*> dest) {
|
||||
strings_internal::Base64EscapeInternal(
|
||||
reinterpret_cast<const unsigned char*>(src.data()), src.size(), dest,
|
||||
false, strings_internal::kWebSafeBase64Chars);
|
||||
@@ -919,6 +968,32 @@ std::string WebSafeBase64Escape(absl::string_view src) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
bool HexStringToBytes(absl::string_view hex,
|
||||
absl::Nonnull<std::string*> bytes) {
|
||||
std::string output;
|
||||
|
||||
size_t num_bytes = hex.size() / 2;
|
||||
if (hex.size() != num_bytes * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::strings_internal::STLStringResizeUninitialized(&output, num_bytes);
|
||||
auto hex_p = hex.cbegin();
|
||||
for (std::string::iterator bin_p = output.begin(); bin_p != output.end();
|
||||
++bin_p) {
|
||||
int h1 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
|
||||
int h2 = absl::kHexValueStrict[static_cast<size_t>(*hex_p++)];
|
||||
if (h1 == -1 || h2 == -1) {
|
||||
output.resize(static_cast<size_t>(bin_p - output.begin()));
|
||||
return false;
|
||||
}
|
||||
*bin_p = static_cast<char>((h1 << 4) + h2);
|
||||
}
|
||||
|
||||
*bytes = std::move(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string HexStringToBytes(absl::string_view from) {
|
||||
std::string result;
|
||||
const auto num = from.size() / 2;
|
||||
|
||||
33
Pods/abseil/absl/strings/escaping.h
generated
33
Pods/abseil/absl/strings/escaping.h
generated
@@ -27,7 +27,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/str_join.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
@@ -65,14 +67,16 @@ ABSL_NAMESPACE_BEGIN
|
||||
//
|
||||
// std::string s = "foo\\rbar\\nbaz\\t";
|
||||
// std::string unescaped_s;
|
||||
// if (!absl::CUnescape(s, &unescaped_s) {
|
||||
// if (!absl::CUnescape(s, &unescaped_s)) {
|
||||
// ...
|
||||
// }
|
||||
// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t");
|
||||
bool CUnescape(absl::string_view source, std::string* dest, std::string* error);
|
||||
bool CUnescape(absl::string_view source, absl::Nonnull<std::string*> dest,
|
||||
absl::Nullable<std::string*> error);
|
||||
|
||||
// Overload of `CUnescape()` with no error reporting.
|
||||
inline bool CUnescape(absl::string_view source, std::string* dest) {
|
||||
inline bool CUnescape(absl::string_view source,
|
||||
absl::Nonnull<std::string*> dest) {
|
||||
return CUnescape(source, dest, nullptr);
|
||||
}
|
||||
|
||||
@@ -122,7 +126,7 @@ std::string Utf8SafeCHexEscape(absl::string_view src);
|
||||
// Encodes a `src` string into a base64-encoded 'dest' string with padding
|
||||
// characters. This function conforms with RFC 4648 section 4 (base64) and RFC
|
||||
// 2045.
|
||||
void Base64Escape(absl::string_view src, std::string* dest);
|
||||
void Base64Escape(absl::string_view src, absl::Nonnull<std::string*> dest);
|
||||
std::string Base64Escape(absl::string_view src);
|
||||
|
||||
// WebSafeBase64Escape()
|
||||
@@ -130,7 +134,8 @@ std::string Base64Escape(absl::string_view src);
|
||||
// Encodes a `src` string into a base64 string, like Base64Escape() does, but
|
||||
// outputs '-' instead of '+' and '_' instead of '/', and does not pad 'dest'.
|
||||
// This function conforms with RFC 4648 section 5 (base64url).
|
||||
void WebSafeBase64Escape(absl::string_view src, std::string* dest);
|
||||
void WebSafeBase64Escape(absl::string_view src,
|
||||
absl::Nonnull<std::string*> dest);
|
||||
std::string WebSafeBase64Escape(absl::string_view src);
|
||||
|
||||
// Base64Unescape()
|
||||
@@ -140,7 +145,7 @@ std::string WebSafeBase64Escape(absl::string_view src);
|
||||
// `src` contains invalid characters, `dest` is cleared and returns `false`.
|
||||
// If padding is included (note that `Base64Escape()` does produce it), it must
|
||||
// be correct. In the padding, '=' and '.' are treated identically.
|
||||
bool Base64Unescape(absl::string_view src, std::string* dest);
|
||||
bool Base64Unescape(absl::string_view src, absl::Nonnull<std::string*> dest);
|
||||
|
||||
// WebSafeBase64Unescape()
|
||||
//
|
||||
@@ -149,12 +154,24 @@ bool Base64Unescape(absl::string_view src, std::string* dest);
|
||||
// invalid characters, `dest` is cleared and returns `false`. If padding is
|
||||
// included (note that `WebSafeBase64Escape()` does not produce it), it must be
|
||||
// correct. In the padding, '=' and '.' are treated identically.
|
||||
bool WebSafeBase64Unescape(absl::string_view src, std::string* dest);
|
||||
bool WebSafeBase64Unescape(absl::string_view src,
|
||||
absl::Nonnull<std::string*> dest);
|
||||
|
||||
// HexStringToBytes()
|
||||
//
|
||||
// Converts the hexadecimal encoded data in `hex` into raw bytes in the `bytes`
|
||||
// output string. If `hex` does not consist of valid hexadecimal data, this
|
||||
// function returns false and leaves `bytes` in an unspecified state. Returns
|
||||
// true on success.
|
||||
ABSL_MUST_USE_RESULT bool HexStringToBytes(absl::string_view hex,
|
||||
absl::Nonnull<std::string*> bytes);
|
||||
|
||||
// HexStringToBytes()
|
||||
//
|
||||
// Converts an ASCII hex string into bytes, returning binary data of length
|
||||
// `from.size()/2`.
|
||||
// `from.size()/2`. The input must be valid hexadecimal data, otherwise the
|
||||
// return value is unspecified.
|
||||
ABSL_DEPRECATED("Use the HexStringToBytes() that returns a bool")
|
||||
std::string HexStringToBytes(absl::string_view from);
|
||||
|
||||
// BytesToHexString()
|
||||
|
||||
1
Pods/abseil/absl/strings/has_absl_stringify.h
generated
1
Pods/abseil/absl/strings/has_absl_stringify.h
generated
@@ -18,6 +18,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace absl {
|
||||
|
||||
10
Pods/abseil/absl/strings/internal/charconv_bigint.h
generated
10
Pods/abseil/absl/strings/internal/charconv_bigint.h
generated
@@ -109,7 +109,17 @@ class BigUnsigned {
|
||||
size_ = (std::min)(size_ + word_shift, max_words);
|
||||
count %= 32;
|
||||
if (count == 0) {
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=warray-bounds
|
||||
// shows a lot of bogus -Warray-bounds warnings under GCC.
|
||||
// This is not the only one in Abseil.
|
||||
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(14, 0)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_);
|
||||
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(14, 0)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
} else {
|
||||
for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) {
|
||||
words_[i] = (words_[i - word_shift] << count) |
|
||||
|
||||
38
Pods/abseil/absl/strings/internal/cord_internal.h
generated
38
Pods/abseil/absl/strings/internal/cord_internal.h
generated
@@ -85,7 +85,7 @@ enum Constants {
|
||||
};
|
||||
|
||||
// Emits a fatal error "Unexpected node type: xyz" and aborts the program.
|
||||
ABSL_ATTRIBUTE_NORETURN void LogFatalNodeType(CordRep* rep);
|
||||
[[noreturn]] void LogFatalNodeType(CordRep* rep);
|
||||
|
||||
// Fast implementation of memmove for up to 15 bytes. This implementation is
|
||||
// safe for overlapping regions. If nullify_tail is true, the destination is
|
||||
@@ -259,7 +259,7 @@ struct CordRep {
|
||||
// on the specific layout of these fields. Notably: the non-trivial field
|
||||
// `refcount` being preceded by `length`, and being tailed by POD data
|
||||
// members only.
|
||||
// # LINT.IfChange
|
||||
// LINT.IfChange
|
||||
size_t length;
|
||||
RefcountAndFlags refcount;
|
||||
// If tag < FLAT, it represents CordRepKind and indicates the type of node.
|
||||
@@ -275,7 +275,7 @@ struct CordRep {
|
||||
// allocate room for these in the derived class, as not all compilers reuse
|
||||
// padding space from the base class (clang and gcc do, MSVC does not, etc)
|
||||
uint8_t storage[3];
|
||||
// # LINT.ThenChange(cord_rep_btree.h:copy_raw)
|
||||
// LINT.ThenChange(cord_rep_btree.h:copy_raw)
|
||||
|
||||
// Returns true if this instance's tag matches the requested type.
|
||||
constexpr bool IsSubstring() const { return tag == SUBSTRING; }
|
||||
@@ -352,18 +352,19 @@ struct CordRepExternal : public CordRep {
|
||||
static void Delete(CordRep* rep);
|
||||
};
|
||||
|
||||
struct Rank1 {};
|
||||
struct Rank0 : Rank1 {};
|
||||
// Use go/ranked-overloads for dispatching.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
|
||||
template <typename Releaser, typename = ::absl::base_internal::invoke_result_t<
|
||||
Releaser, absl::string_view>>
|
||||
void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view data) {
|
||||
void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view data) {
|
||||
::absl::base_internal::invoke(std::forward<Releaser>(releaser), data);
|
||||
}
|
||||
|
||||
template <typename Releaser,
|
||||
typename = ::absl::base_internal::invoke_result_t<Releaser>>
|
||||
void InvokeReleaser(Rank1, Releaser&& releaser, absl::string_view) {
|
||||
void InvokeReleaser(Rank0, Releaser&& releaser, absl::string_view) {
|
||||
::absl::base_internal::invoke(std::forward<Releaser>(releaser));
|
||||
}
|
||||
|
||||
@@ -381,7 +382,7 @@ struct CordRepExternalImpl
|
||||
}
|
||||
|
||||
~CordRepExternalImpl() {
|
||||
InvokeReleaser(Rank0{}, std::move(this->template get<0>()),
|
||||
InvokeReleaser(Rank1{}, std::move(this->template get<0>()),
|
||||
absl::string_view(base, length));
|
||||
}
|
||||
|
||||
@@ -398,7 +399,6 @@ inline CordRepSubstring* CordRepSubstring::Create(CordRep* child, size_t pos,
|
||||
assert(pos < child->length);
|
||||
assert(n <= child->length - pos);
|
||||
|
||||
// TODO(b/217376272): Harden internal logic.
|
||||
// Move to strategical places inside the Cord logic and make this an assert.
|
||||
if (ABSL_PREDICT_FALSE(!(child->IsExternal() || child->IsFlat()))) {
|
||||
LogFatalNodeType(child);
|
||||
@@ -520,6 +520,7 @@ class InlineData {
|
||||
|
||||
constexpr InlineData(const InlineData& rhs) noexcept;
|
||||
InlineData& operator=(const InlineData& rhs) noexcept;
|
||||
friend void swap(InlineData& lhs, InlineData& rhs) noexcept;
|
||||
|
||||
friend bool operator==(const InlineData& lhs, const InlineData& rhs) {
|
||||
#ifdef ABSL_INTERNAL_CORD_HAVE_SANITIZER
|
||||
@@ -770,6 +771,12 @@ class InlineData {
|
||||
char data[kMaxInline + 1];
|
||||
AsTree as_tree;
|
||||
};
|
||||
|
||||
// TODO(b/145829486): see swap(InlineData, InlineData) for more info.
|
||||
inline void SwapValue(Rep rhs, Rep& refrhs) {
|
||||
memcpy(&refrhs, this, sizeof(*this));
|
||||
memcpy(this, &rhs, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
// Private implementation of `Compare()`
|
||||
@@ -884,6 +891,19 @@ inline void CordRep::Unref(CordRep* rep) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void swap(InlineData& lhs, InlineData& rhs) noexcept {
|
||||
lhs.unpoison();
|
||||
rhs.unpoison();
|
||||
// TODO(b/145829486): `std::swap(lhs.rep_, rhs.rep_)` results in bad codegen
|
||||
// on clang, spilling the temporary swap value on the stack. Since `Rep` is
|
||||
// trivial, we can make clang DTRT by calling a hand-rolled `SwapValue` where
|
||||
// we pass `rhs` both by value (register allocated) and by reference. The IR
|
||||
// then folds and inlines correctly into an optimized swap without spill.
|
||||
lhs.rep_.SwapValue(rhs.rep_, rhs.rep_);
|
||||
rhs.poison();
|
||||
lhs.poison();
|
||||
}
|
||||
|
||||
} // namespace cord_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
|
||||
@@ -684,14 +684,14 @@ inline CordRepBtree* CordRepBtree::CopyRaw(size_t new_length) const {
|
||||
// except `refcount` is trivially copyable, and the compiler does not
|
||||
// efficiently coalesce member-wise copy of these members.
|
||||
// See https://gcc.godbolt.org/z/qY8zsca6z
|
||||
// # LINT.IfChange(copy_raw)
|
||||
// LINT.IfChange(copy_raw)
|
||||
tree->length = new_length;
|
||||
uint8_t* dst = &tree->tag;
|
||||
const uint8_t* src = &tag;
|
||||
const ptrdiff_t offset = src - reinterpret_cast<const uint8_t*>(this);
|
||||
memcpy(dst, src, sizeof(CordRepBtree) - static_cast<size_t>(offset));
|
||||
return tree;
|
||||
// # LINT.ThenChange()
|
||||
// LINT.ThenChange()
|
||||
}
|
||||
|
||||
inline CordRepBtree* CordRepBtree::Copy() const {
|
||||
|
||||
32
Pods/abseil/absl/strings/internal/cordz_functions.cc
generated
32
Pods/abseil/absl/strings/internal/cordz_functions.cc
generated
@@ -40,13 +40,15 @@ std::atomic<int> g_cordz_mean_interval(50000);
|
||||
// Special negative 'not initialized' per thread value for cordz_next_sample.
|
||||
static constexpr int64_t kInitCordzNextSample = -1;
|
||||
|
||||
ABSL_CONST_INIT thread_local int64_t cordz_next_sample = kInitCordzNextSample;
|
||||
ABSL_CONST_INIT thread_local SamplingState cordz_next_sample = {
|
||||
kInitCordzNextSample, 1};
|
||||
|
||||
// kIntervalIfDisabled is the number of profile-eligible events need to occur
|
||||
// before the code will confirm that cordz is still disabled.
|
||||
constexpr int64_t kIntervalIfDisabled = 1 << 16;
|
||||
|
||||
ABSL_ATTRIBUTE_NOINLINE bool cordz_should_profile_slow() {
|
||||
ABSL_ATTRIBUTE_NOINLINE int64_t
|
||||
cordz_should_profile_slow(SamplingState& state) {
|
||||
|
||||
thread_local absl::profiling_internal::ExponentialBiased
|
||||
exponential_biased_generator;
|
||||
@@ -55,30 +57,34 @@ ABSL_ATTRIBUTE_NOINLINE bool cordz_should_profile_slow() {
|
||||
// Check if we disabled profiling. If so, set the next sample to a "large"
|
||||
// number to minimize the overhead of the should_profile codepath.
|
||||
if (mean_interval <= 0) {
|
||||
cordz_next_sample = kIntervalIfDisabled;
|
||||
return false;
|
||||
state = {kIntervalIfDisabled, kIntervalIfDisabled};
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if we're always sampling.
|
||||
if (mean_interval == 1) {
|
||||
cordz_next_sample = 1;
|
||||
return true;
|
||||
state = {1, 1};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cordz_next_sample <= 0) {
|
||||
if (cordz_next_sample.next_sample <= 0) {
|
||||
// If first check on current thread, check cordz_should_profile()
|
||||
// again using the created (initial) stride in cordz_next_sample.
|
||||
const bool initialized = cordz_next_sample != kInitCordzNextSample;
|
||||
cordz_next_sample = exponential_biased_generator.GetStride(mean_interval);
|
||||
return initialized || cordz_should_profile();
|
||||
const bool initialized =
|
||||
cordz_next_sample.next_sample != kInitCordzNextSample;
|
||||
auto old_stride = state.sample_stride;
|
||||
auto stride = exponential_biased_generator.GetStride(mean_interval);
|
||||
state = {stride, stride};
|
||||
bool should_sample = initialized || cordz_should_profile() > 0;
|
||||
return should_sample ? old_stride : 0;
|
||||
}
|
||||
|
||||
--cordz_next_sample;
|
||||
return false;
|
||||
--state.next_sample;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cordz_set_next_sample_for_testing(int64_t next_sample) {
|
||||
cordz_next_sample = next_sample;
|
||||
cordz_next_sample = {next_sample, next_sample};
|
||||
}
|
||||
|
||||
#endif // ABSL_INTERNAL_CORDZ_ENABLED
|
||||
|
||||
32
Pods/abseil/absl/strings/internal/cordz_functions.h
generated
32
Pods/abseil/absl/strings/internal/cordz_functions.h
generated
@@ -41,23 +41,33 @@ void set_cordz_mean_interval(int32_t mean_interval);
|
||||
|
||||
#ifdef ABSL_INTERNAL_CORDZ_ENABLED
|
||||
|
||||
struct SamplingState {
|
||||
int64_t next_sample;
|
||||
int64_t sample_stride;
|
||||
};
|
||||
|
||||
// cordz_next_sample is the number of events until the next sample event. If
|
||||
// the value is 1 or less, the code will check on the next event if cordz is
|
||||
// enabled, and if so, will sample the Cord. cordz is only enabled when we can
|
||||
// use thread locals.
|
||||
ABSL_CONST_INIT extern thread_local int64_t cordz_next_sample;
|
||||
ABSL_CONST_INIT extern thread_local SamplingState cordz_next_sample;
|
||||
|
||||
// Determines if the next sample should be profiled. If it is, the value pointed
|
||||
// at by next_sample will be set with the interval until the next sample.
|
||||
bool cordz_should_profile_slow();
|
||||
// Determines if the next sample should be profiled.
|
||||
// Returns:
|
||||
// 0: Do not sample
|
||||
// >0: Sample with the stride of the last sampling period
|
||||
int64_t cordz_should_profile_slow(SamplingState& state);
|
||||
|
||||
// Returns true if the next cord should be sampled.
|
||||
inline bool cordz_should_profile() {
|
||||
if (ABSL_PREDICT_TRUE(cordz_next_sample > 1)) {
|
||||
cordz_next_sample--;
|
||||
return false;
|
||||
// Determines if the next sample should be profiled.
|
||||
// Returns:
|
||||
// 0: Do not sample
|
||||
// >0: Sample with the stride of the last sampling period
|
||||
inline int64_t cordz_should_profile() {
|
||||
if (ABSL_PREDICT_TRUE(cordz_next_sample.next_sample > 1)) {
|
||||
cordz_next_sample.next_sample--;
|
||||
return 0;
|
||||
}
|
||||
return cordz_should_profile_slow();
|
||||
return cordz_should_profile_slow(cordz_next_sample);
|
||||
}
|
||||
|
||||
// Sets the interval until the next sample (for testing only)
|
||||
@@ -65,7 +75,7 @@ void cordz_set_next_sample_for_testing(int64_t next_sample);
|
||||
|
||||
#else // ABSL_INTERNAL_CORDZ_ENABLED
|
||||
|
||||
inline bool cordz_should_profile() { return false; }
|
||||
inline int64_t cordz_should_profile() { return 0; }
|
||||
inline void cordz_set_next_sample_for_testing(int64_t) {}
|
||||
|
||||
#endif // ABSL_INTERNAL_CORDZ_ENABLED
|
||||
|
||||
48
Pods/abseil/absl/strings/internal/cordz_handle.cc
generated
48
Pods/abseil/absl/strings/internal/cordz_handle.cc
generated
@@ -16,6 +16,7 @@
|
||||
#include <atomic>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h" // For ABSL_RAW_CHECK
|
||||
#include "absl/base/no_destructor.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace absl {
|
||||
@@ -43,33 +44,32 @@ struct Queue {
|
||||
}
|
||||
};
|
||||
|
||||
static Queue* GlobalQueue() {
|
||||
static Queue* global_queue = new Queue;
|
||||
return global_queue;
|
||||
static Queue& GlobalQueue() {
|
||||
static absl::NoDestructor<Queue> global_queue;
|
||||
return *global_queue;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
CordzHandle::CordzHandle(bool is_snapshot) : is_snapshot_(is_snapshot) {
|
||||
Queue* global_queue = GlobalQueue();
|
||||
Queue& global_queue = GlobalQueue();
|
||||
if (is_snapshot) {
|
||||
MutexLock lock(&global_queue->mutex);
|
||||
CordzHandle* dq_tail =
|
||||
global_queue->dq_tail.load(std::memory_order_acquire);
|
||||
MutexLock lock(&global_queue.mutex);
|
||||
CordzHandle* dq_tail = global_queue.dq_tail.load(std::memory_order_acquire);
|
||||
if (dq_tail != nullptr) {
|
||||
dq_prev_ = dq_tail;
|
||||
dq_tail->dq_next_ = this;
|
||||
}
|
||||
global_queue->dq_tail.store(this, std::memory_order_release);
|
||||
global_queue.dq_tail.store(this, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
|
||||
CordzHandle::~CordzHandle() {
|
||||
Queue* global_queue = GlobalQueue();
|
||||
Queue& global_queue = GlobalQueue();
|
||||
if (is_snapshot_) {
|
||||
std::vector<CordzHandle*> to_delete;
|
||||
{
|
||||
MutexLock lock(&global_queue->mutex);
|
||||
MutexLock lock(&global_queue.mutex);
|
||||
CordzHandle* next = dq_next_;
|
||||
if (dq_prev_ == nullptr) {
|
||||
// We were head of the queue, delete every CordzHandle until we reach
|
||||
@@ -85,7 +85,7 @@ CordzHandle::~CordzHandle() {
|
||||
if (next) {
|
||||
next->dq_prev_ = dq_prev_;
|
||||
} else {
|
||||
global_queue->dq_tail.store(dq_prev_, std::memory_order_release);
|
||||
global_queue.dq_tail.store(dq_prev_, std::memory_order_release);
|
||||
}
|
||||
}
|
||||
for (CordzHandle* handle : to_delete) {
|
||||
@@ -95,20 +95,20 @@ CordzHandle::~CordzHandle() {
|
||||
}
|
||||
|
||||
bool CordzHandle::SafeToDelete() const {
|
||||
return is_snapshot_ || GlobalQueue()->IsEmpty();
|
||||
return is_snapshot_ || GlobalQueue().IsEmpty();
|
||||
}
|
||||
|
||||
void CordzHandle::Delete(CordzHandle* handle) {
|
||||
assert(handle);
|
||||
if (handle) {
|
||||
Queue* const queue = GlobalQueue();
|
||||
Queue& queue = GlobalQueue();
|
||||
if (!handle->SafeToDelete()) {
|
||||
MutexLock lock(&queue->mutex);
|
||||
CordzHandle* dq_tail = queue->dq_tail.load(std::memory_order_acquire);
|
||||
MutexLock lock(&queue.mutex);
|
||||
CordzHandle* dq_tail = queue.dq_tail.load(std::memory_order_acquire);
|
||||
if (dq_tail != nullptr) {
|
||||
handle->dq_prev_ = dq_tail;
|
||||
dq_tail->dq_next_ = handle;
|
||||
queue->dq_tail.store(handle, std::memory_order_release);
|
||||
queue.dq_tail.store(handle, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -118,9 +118,9 @@ void CordzHandle::Delete(CordzHandle* handle) {
|
||||
|
||||
std::vector<const CordzHandle*> CordzHandle::DiagnosticsGetDeleteQueue() {
|
||||
std::vector<const CordzHandle*> handles;
|
||||
Queue* global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue->mutex);
|
||||
CordzHandle* dq_tail = global_queue->dq_tail.load(std::memory_order_acquire);
|
||||
Queue& global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue.mutex);
|
||||
CordzHandle* dq_tail = global_queue.dq_tail.load(std::memory_order_acquire);
|
||||
for (const CordzHandle* p = dq_tail; p; p = p->dq_prev_) {
|
||||
handles.push_back(p);
|
||||
}
|
||||
@@ -133,9 +133,9 @@ bool CordzHandle::DiagnosticsHandleIsSafeToInspect(
|
||||
if (handle == nullptr) return true;
|
||||
if (handle->is_snapshot_) return false;
|
||||
bool snapshot_found = false;
|
||||
Queue* global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue->mutex);
|
||||
for (const CordzHandle* p = global_queue->dq_tail; p; p = p->dq_prev_) {
|
||||
Queue& global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue.mutex);
|
||||
for (const CordzHandle* p = global_queue.dq_tail; p; p = p->dq_prev_) {
|
||||
if (p == handle) return !snapshot_found;
|
||||
if (p == this) snapshot_found = true;
|
||||
}
|
||||
@@ -150,8 +150,8 @@ CordzHandle::DiagnosticsGetSafeToInspectDeletedHandles() {
|
||||
return handles;
|
||||
}
|
||||
|
||||
Queue* global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue->mutex);
|
||||
Queue& global_queue = GlobalQueue();
|
||||
MutexLock lock(&global_queue.mutex);
|
||||
for (const CordzHandle* p = dq_next_; p != nullptr; p = p->dq_next_) {
|
||||
if (!p->is_snapshot()) {
|
||||
handles.push_back(p);
|
||||
|
||||
19
Pods/abseil/absl/strings/internal/cordz_info.cc
generated
19
Pods/abseil/absl/strings/internal/cordz_info.cc
generated
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "absl/strings/internal/cordz_info.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
#include "absl/container/inlined_vector.h"
|
||||
@@ -247,10 +249,12 @@ CordzInfo* CordzInfo::Next(const CordzSnapshot& snapshot) const {
|
||||
return next;
|
||||
}
|
||||
|
||||
void CordzInfo::TrackCord(InlineData& cord, MethodIdentifier method) {
|
||||
void CordzInfo::TrackCord(InlineData& cord, MethodIdentifier method,
|
||||
int64_t sampling_stride) {
|
||||
assert(cord.is_tree());
|
||||
assert(!cord.is_profiled());
|
||||
CordzInfo* cordz_info = new CordzInfo(cord.as_tree(), nullptr, method);
|
||||
CordzInfo* cordz_info =
|
||||
new CordzInfo(cord.as_tree(), nullptr, method, sampling_stride);
|
||||
cord.set_cordz_info(cordz_info);
|
||||
cordz_info->Track();
|
||||
}
|
||||
@@ -266,7 +270,8 @@ void CordzInfo::TrackCord(InlineData& cord, const InlineData& src,
|
||||
if (cordz_info != nullptr) cordz_info->Untrack();
|
||||
|
||||
// Start new cord sample
|
||||
cordz_info = new CordzInfo(cord.as_tree(), src.cordz_info(), method);
|
||||
cordz_info = new CordzInfo(cord.as_tree(), src.cordz_info(), method,
|
||||
src.cordz_info()->sampling_stride());
|
||||
cord.set_cordz_info(cordz_info);
|
||||
cordz_info->Track();
|
||||
}
|
||||
@@ -298,9 +303,8 @@ size_t CordzInfo::FillParentStack(const CordzInfo* src, void** stack) {
|
||||
return src->stack_depth_;
|
||||
}
|
||||
|
||||
CordzInfo::CordzInfo(CordRep* rep,
|
||||
const CordzInfo* src,
|
||||
MethodIdentifier method)
|
||||
CordzInfo::CordzInfo(CordRep* rep, const CordzInfo* src,
|
||||
MethodIdentifier method, int64_t sampling_stride)
|
||||
: rep_(rep),
|
||||
stack_depth_(
|
||||
static_cast<size_t>(absl::GetStackTrace(stack_,
|
||||
@@ -309,7 +313,8 @@ CordzInfo::CordzInfo(CordRep* rep,
|
||||
parent_stack_depth_(FillParentStack(src, parent_stack_)),
|
||||
method_(method),
|
||||
parent_method_(GetParentMethod(src)),
|
||||
create_time_(absl::Now()) {
|
||||
create_time_(absl::Now()),
|
||||
sampling_stride_(sampling_stride) {
|
||||
update_tracker_.LossyAdd(method);
|
||||
if (src) {
|
||||
// Copy parent counters.
|
||||
|
||||
13
Pods/abseil/absl/strings/internal/cordz_info.h
generated
13
Pods/abseil/absl/strings/internal/cordz_info.h
generated
@@ -60,7 +60,8 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
|
||||
// and/or deleted. `method` identifies the Cord public API method initiating
|
||||
// the cord to be sampled.
|
||||
// Requires `cord` to hold a tree, and `cord.cordz_info()` to be null.
|
||||
static void TrackCord(InlineData& cord, MethodIdentifier method);
|
||||
static void TrackCord(InlineData& cord, MethodIdentifier method,
|
||||
int64_t sampling_stride);
|
||||
|
||||
// Identical to TrackCord(), except that this function fills the
|
||||
// `parent_stack` and `parent_method` properties of the returned CordzInfo
|
||||
@@ -181,6 +182,8 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
|
||||
// or RemovePrefix.
|
||||
CordzStatistics GetCordzStatistics() const;
|
||||
|
||||
int64_t sampling_stride() const { return sampling_stride_; }
|
||||
|
||||
private:
|
||||
using SpinLock = absl::base_internal::SpinLock;
|
||||
using SpinLockHolder = ::absl::base_internal::SpinLockHolder;
|
||||
@@ -199,7 +202,7 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
|
||||
static constexpr size_t kMaxStackDepth = 64;
|
||||
|
||||
explicit CordzInfo(CordRep* rep, const CordzInfo* src,
|
||||
MethodIdentifier method);
|
||||
MethodIdentifier method, int64_t weight);
|
||||
~CordzInfo() override;
|
||||
|
||||
// Sets `rep_` without holding a lock.
|
||||
@@ -250,12 +253,14 @@ class ABSL_LOCKABLE CordzInfo : public CordzHandle {
|
||||
const MethodIdentifier parent_method_;
|
||||
CordzUpdateTracker update_tracker_;
|
||||
const absl::Time create_time_;
|
||||
const int64_t sampling_stride_;
|
||||
};
|
||||
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CordzInfo::MaybeTrackCord(
|
||||
InlineData& cord, MethodIdentifier method) {
|
||||
if (ABSL_PREDICT_FALSE(cordz_should_profile())) {
|
||||
TrackCord(cord, method);
|
||||
auto stride = cordz_should_profile();
|
||||
if (ABSL_PREDICT_FALSE(stride > 0)) {
|
||||
TrackCord(cord, method, stride);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
Pods/abseil/absl/strings/internal/escaping.cc
generated
7
Pods/abseil/absl/strings/internal/escaping.cc
generated
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "absl/strings/internal/escaping.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "absl/base/internal/endian.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
@@ -31,12 +33,14 @@ ABSL_CONST_INIT const char kBase64Chars[] =
|
||||
ABSL_CONST_INIT const char kWebSafeBase64Chars[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
|
||||
size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
|
||||
// Base64 encodes three bytes of input at a time. If the input is not
|
||||
// divisible by three, we pad as appropriate.
|
||||
//
|
||||
// Base64 encodes each three bytes of input into four bytes of output.
|
||||
constexpr size_t kMaxSize = (std::numeric_limits<size_t>::max() - 1) / 4 * 3;
|
||||
ABSL_INTERNAL_CHECK(input_len <= kMaxSize,
|
||||
"CalculateBase64EscapedLenInternal() overflow");
|
||||
size_t len = (input_len / 3) * 4;
|
||||
|
||||
// Since all base 64 input is an integral number of octets, only the following
|
||||
@@ -66,7 +70,6 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
|
||||
}
|
||||
}
|
||||
|
||||
assert(len >= input_len); // make sure we didn't overflow
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2024 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_HAS_ABSL_STRINGIFY_H_
|
||||
#define ABSL_STRINGS_INTERNAL_HAS_ABSL_STRINGIFY_H_
|
||||
|
||||
#include "absl/strings/has_absl_stringify.h"
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace strings_internal {
|
||||
|
||||
// This exists to fix a circular dependency problem with the GoogleTest release.
|
||||
// GoogleTest referenced this internal file and this internal trait. Since
|
||||
// simultaneous releases are not possible since once release must reference
|
||||
// another, we will temporarily add this back.
|
||||
// https://github.com/google/googletest/blob/v1.14.x/googletest/include/gtest/gtest-printers.h#L119
|
||||
//
|
||||
// This file can be deleted after the next Abseil and GoogleTest release.
|
||||
//
|
||||
// https://github.com/google/googletest/pull/4368#issuecomment-1717699895
|
||||
// https://github.com/google/googletest/pull/4368#issuecomment-1717699895
|
||||
using ::absl::HasAbslStringify;
|
||||
|
||||
} // namespace strings_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_STRINGS_INTERNAL_HAS_ABSL_STRINGIFY_H_
|
||||
@@ -31,16 +31,23 @@
|
||||
#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
|
||||
#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/strings/internal/ostringstream.h"
|
||||
#include "absl/strings/internal/resize_uninitialized.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
@@ -230,14 +237,19 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
|
||||
if (start != end) {
|
||||
// Sums size
|
||||
auto&& start_value = *start;
|
||||
size_t result_size = start_value.size();
|
||||
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
|
||||
// in memory strings to overflow a uint64_t.
|
||||
uint64_t result_size = start_value.size();
|
||||
for (Iterator it = start; ++it != end;) {
|
||||
result_size += s.size();
|
||||
result_size += (*it).size();
|
||||
}
|
||||
|
||||
if (result_size > 0) {
|
||||
STLStringResizeUninitialized(&result, result_size);
|
||||
constexpr uint64_t kMaxSize =
|
||||
uint64_t{(std::numeric_limits<size_t>::max)()};
|
||||
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
|
||||
STLStringResizeUninitialized(&result, static_cast<size_t>(result_size));
|
||||
|
||||
// Joins strings
|
||||
char* result_buf = &*result.begin();
|
||||
@@ -310,6 +322,15 @@ std::string JoinRange(const Range& range, absl::string_view separator) {
|
||||
return JoinRange(begin(range), end(range), separator);
|
||||
}
|
||||
|
||||
template <typename Tuple, std::size_t... I>
|
||||
std::string JoinTuple(const Tuple& value, absl::string_view separator,
|
||||
std::index_sequence<I...>) {
|
||||
return JoinRange(
|
||||
std::initializer_list<absl::string_view>{
|
||||
static_cast<const AlphaNum&>(std::get<I>(value)).Piece()...},
|
||||
separator);
|
||||
}
|
||||
|
||||
} // namespace strings_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
@@ -402,7 +403,10 @@ class Splitter {
|
||||
ar[index].size = it->size();
|
||||
++it;
|
||||
} while (++index != ar.size() && !it.at_end());
|
||||
v.insert(v.end(), ar.begin(), ar.begin() + index);
|
||||
// We static_cast index to a signed type to work around overzealous
|
||||
// compiler warnings about signedness.
|
||||
v.insert(v.end(), ar.begin(),
|
||||
ar.begin() + static_cast<ptrdiff_t>(index));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
444
Pods/abseil/absl/strings/numbers.cc
generated
444
Pods/abseil/absl/strings/numbers.cc
generated
@@ -20,9 +20,7 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cfloat> // for DBL_DIG and FLT_DIG
|
||||
#include <climits>
|
||||
#include <cmath> // for HUGE_VAL
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -30,7 +28,6 @@
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <system_error> // NOLINT(build/c++11)
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
@@ -159,71 +156,28 @@ constexpr uint32_t kTwoZeroBytes = 0x0101 * '0';
|
||||
constexpr uint64_t kFourZeroBytes = 0x01010101 * '0';
|
||||
constexpr uint64_t kEightZeroBytes = 0x0101010101010101ull * '0';
|
||||
|
||||
template <typename T>
|
||||
constexpr T Pow(T base, uint32_t n) {
|
||||
// Exponentiation by squaring
|
||||
return static_cast<T>((n > 1 ? Pow(base * base, n >> 1) : static_cast<T>(1)) *
|
||||
((n & 1) ? base : static_cast<T>(1)));
|
||||
}
|
||||
|
||||
// Given n, calculates C where the following holds for all 0 <= x < Pow(100, n):
|
||||
// x / Pow(10, n) == x * C / Pow(2, n * 10)
|
||||
// In other words, it allows us to divide by a power of 10 via a single
|
||||
// multiplication and bit shifts, assuming the input will be smaller than the
|
||||
// square of that power of 10.
|
||||
template <typename T>
|
||||
constexpr T ComputePowerOf100DivisionCoefficient(uint32_t n) {
|
||||
if (n > 4) {
|
||||
// This doesn't work for large powers of 100, due to overflow
|
||||
abort();
|
||||
}
|
||||
T denom = 16 - 1;
|
||||
T num = (denom + 1) - 10;
|
||||
T gcd = 3; // Greatest common divisor of numerator and denominator
|
||||
denom = Pow(denom / gcd, n);
|
||||
num = Pow(num / gcd, 9 * n);
|
||||
T quotient = num / denom;
|
||||
if (num % denom >= denom / 2) {
|
||||
// Round up, since the remainder is more than half the denominator
|
||||
++quotient;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
// * kDivisionBy10Mul / kDivisionBy10Div is a division by 10 for values from 0
|
||||
// to 99. It's also a division of a structure [k takes 2 bytes][m takes 2
|
||||
// bytes], then * kDivisionBy10Mul / kDivisionBy10Div will be [k / 10][m / 10].
|
||||
// It allows parallel division.
|
||||
constexpr uint64_t kDivisionBy10Mul =
|
||||
ComputePowerOf100DivisionCoefficient<uint64_t>(1);
|
||||
static_assert(kDivisionBy10Mul == 103,
|
||||
"division coefficient for 10 is incorrect");
|
||||
// * 103 / 1024 is a division by 10 for values from 0 to 99. It's also a
|
||||
// division of a structure [k takes 2 bytes][m takes 2 bytes], then * 103 / 1024
|
||||
// will be [k / 10][m / 10]. It allows parallel division.
|
||||
constexpr uint64_t kDivisionBy10Mul = 103u;
|
||||
constexpr uint64_t kDivisionBy10Div = 1 << 10;
|
||||
|
||||
// * kDivisionBy100Mul / kDivisionBy100Div is a division by 100 for values from
|
||||
// 0 to 9999.
|
||||
constexpr uint64_t kDivisionBy100Mul =
|
||||
ComputePowerOf100DivisionCoefficient<uint64_t>(2);
|
||||
static_assert(kDivisionBy100Mul == 10486,
|
||||
"division coefficient for 100 is incorrect");
|
||||
// * 10486 / 1048576 is a division by 100 for values from 0 to 9999.
|
||||
constexpr uint64_t kDivisionBy100Mul = 10486u;
|
||||
constexpr uint64_t kDivisionBy100Div = 1 << 20;
|
||||
|
||||
static_assert(ComputePowerOf100DivisionCoefficient<uint64_t>(3) == 1073742,
|
||||
"division coefficient for 1000 is incorrect");
|
||||
|
||||
// Same as `PrepareEightDigits`, but produces 2 digits for integers < 100.
|
||||
inline uint32_t PrepareTwoDigitsImpl(uint32_t i, bool reversed) {
|
||||
assert(i < 100);
|
||||
uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div;
|
||||
uint32_t mod10 = i - 10u * div10;
|
||||
return (div10 << (reversed ? 8 : 0)) + (mod10 << (reversed ? 0 : 8));
|
||||
}
|
||||
inline uint32_t PrepareTwoDigits(uint32_t i) {
|
||||
return PrepareTwoDigitsImpl(i, false);
|
||||
// Encode functions write the ASCII output of input `n` to `out_str`.
|
||||
inline char* EncodeHundred(uint32_t n, absl::Nonnull<char*> out_str) {
|
||||
int num_digits = static_cast<int>(n - 10) >> 8;
|
||||
uint32_t div10 = (n * kDivisionBy10Mul) / kDivisionBy10Div;
|
||||
uint32_t mod10 = n - 10u * div10;
|
||||
uint32_t base = kTwoZeroBytes + div10 + (mod10 << 8);
|
||||
base >>= num_digits & 8;
|
||||
little_endian::Store16(out_str, static_cast<uint16_t>(base));
|
||||
return out_str + 2 + num_digits;
|
||||
}
|
||||
|
||||
// Same as `PrepareEightDigits`, but produces 4 digits for integers < 10000.
|
||||
inline uint32_t PrepareFourDigitsImpl(uint32_t n, bool reversed) {
|
||||
inline char* EncodeTenThousand(uint32_t n, absl::Nonnull<char*> out_str) {
|
||||
// We split lower 2 digits and upper 2 digits of n into 2 byte consecutive
|
||||
// blocks. 123 -> [\0\1][\0\23]. We divide by 10 both blocks
|
||||
// (it's 1 division + zeroing upper bits), and compute modulo 10 as well "in
|
||||
@@ -231,19 +185,22 @@ inline uint32_t PrepareFourDigitsImpl(uint32_t n, bool reversed) {
|
||||
// strip trailing zeros, add ASCII '0000' and return.
|
||||
uint32_t div100 = (n * kDivisionBy100Mul) / kDivisionBy100Div;
|
||||
uint32_t mod100 = n - 100ull * div100;
|
||||
uint32_t hundreds =
|
||||
(mod100 << (reversed ? 0 : 16)) + (div100 << (reversed ? 16 : 0));
|
||||
uint32_t hundreds = (mod100 << 16) + div100;
|
||||
uint32_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div;
|
||||
tens &= (0xFull << 16) | 0xFull;
|
||||
tens = (tens << (reversed ? 8 : 0)) +
|
||||
static_cast<uint32_t>((hundreds - 10ull * tens) << (reversed ? 0 : 8));
|
||||
return tens;
|
||||
}
|
||||
inline uint32_t PrepareFourDigits(uint32_t n) {
|
||||
return PrepareFourDigitsImpl(n, false);
|
||||
}
|
||||
inline uint32_t PrepareFourDigitsReversed(uint32_t n) {
|
||||
return PrepareFourDigitsImpl(n, true);
|
||||
tens += (hundreds - 10ull * tens) << 8;
|
||||
ABSL_ASSUME(tens != 0);
|
||||
// The result can contain trailing zero bits, we need to strip them to a first
|
||||
// significant byte in a final representation. For example, for n = 123, we
|
||||
// have tens to have representation \0\1\2\3. We do `& -8` to round
|
||||
// to a multiple to 8 to strip zero bytes, not all zero bits.
|
||||
// countr_zero to help.
|
||||
// 0 minus 8 to make MSVC happy.
|
||||
uint32_t zeroes = static_cast<uint32_t>(absl::countr_zero(tens)) & (0 - 8u);
|
||||
tens += kFourZeroBytes;
|
||||
tens >>= zeroes;
|
||||
little_endian::Store32(out_str, tens);
|
||||
return out_str + sizeof(tens) - zeroes / 8;
|
||||
}
|
||||
|
||||
// Helper function to produce an ASCII representation of `i`.
|
||||
@@ -259,309 +216,126 @@ inline uint32_t PrepareFourDigitsReversed(uint32_t n) {
|
||||
// // Note two leading zeros:
|
||||
// EXPECT_EQ(absl::string_view(ascii, 8), "00102030");
|
||||
//
|
||||
// If `Reversed` is set to true, the result becomes reversed to "03020100".
|
||||
//
|
||||
// Pre-condition: `i` must be less than 100000000.
|
||||
inline uint64_t PrepareEightDigitsImpl(uint32_t i, bool reversed) {
|
||||
inline uint64_t PrepareEightDigits(uint32_t i) {
|
||||
ABSL_ASSUME(i < 10000'0000);
|
||||
// Prepare 2 blocks of 4 digits "in parallel".
|
||||
uint32_t hi = i / 10000;
|
||||
uint32_t lo = i % 10000;
|
||||
uint64_t merged = (uint64_t{hi} << (reversed ? 32 : 0)) |
|
||||
(uint64_t{lo} << (reversed ? 0 : 32));
|
||||
uint64_t merged = hi | (uint64_t{lo} << 32);
|
||||
uint64_t div100 = ((merged * kDivisionBy100Mul) / kDivisionBy100Div) &
|
||||
((0x7Full << 32) | 0x7Full);
|
||||
uint64_t mod100 = merged - 100ull * div100;
|
||||
uint64_t hundreds =
|
||||
(mod100 << (reversed ? 0 : 16)) + (div100 << (reversed ? 16 : 0));
|
||||
uint64_t hundreds = (mod100 << 16) + div100;
|
||||
uint64_t tens = (hundreds * kDivisionBy10Mul) / kDivisionBy10Div;
|
||||
tens &= (0xFull << 48) | (0xFull << 32) | (0xFull << 16) | 0xFull;
|
||||
tens = (tens << (reversed ? 8 : 0)) +
|
||||
((hundreds - 10ull * tens) << (reversed ? 0 : 8));
|
||||
tens += (hundreds - 10ull * tens) << 8;
|
||||
return tens;
|
||||
}
|
||||
inline uint64_t PrepareEightDigits(uint32_t i) {
|
||||
return PrepareEightDigitsImpl(i, false);
|
||||
}
|
||||
inline uint64_t PrepareEightDigitsReversed(uint32_t i) {
|
||||
return PrepareEightDigitsImpl(i, true);
|
||||
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE absl::Nonnull<char*> EncodeFullU32(
|
||||
uint32_t n, absl::Nonnull<char*> out_str) {
|
||||
if (n < 10) {
|
||||
*out_str = static_cast<char>('0' + n);
|
||||
return out_str + 1;
|
||||
}
|
||||
if (n < 100'000'000) {
|
||||
uint64_t bottom = PrepareEightDigits(n);
|
||||
ABSL_ASSUME(bottom != 0);
|
||||
// 0 minus 8 to make MSVC happy.
|
||||
uint32_t zeroes =
|
||||
static_cast<uint32_t>(absl::countr_zero(bottom)) & (0 - 8u);
|
||||
little_endian::Store64(out_str, (bottom + kEightZeroBytes) >> zeroes);
|
||||
return out_str + sizeof(bottom) - zeroes / 8;
|
||||
}
|
||||
uint32_t div08 = n / 100'000'000;
|
||||
uint32_t mod08 = n % 100'000'000;
|
||||
uint64_t bottom = PrepareEightDigits(mod08) + kEightZeroBytes;
|
||||
out_str = EncodeHundred(div08, out_str);
|
||||
little_endian::Store64(out_str, bottom);
|
||||
return out_str + sizeof(bottom);
|
||||
}
|
||||
|
||||
template <typename T, typename BackwardIt>
|
||||
class FastUIntToStringConverter {
|
||||
static_assert(
|
||||
std::is_same<T, decltype(+std::declval<T>())>::value,
|
||||
"to avoid code bloat, only instantiate this for int and larger types");
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"this class is only for unsigned types");
|
||||
|
||||
public:
|
||||
// Outputs the given number backward (like with std::copy_backward),
|
||||
// starting from the end of the string.
|
||||
// The number of digits in the number must have been already measured and
|
||||
// passed *exactly*, otherwise the behavior is undefined.
|
||||
// (This is an optimization, as calculating the number of digits again would
|
||||
// slow down the hot path.)
|
||||
// Returns an iterator to the start of the suffix that was appended.
|
||||
static BackwardIt FastIntToBufferBackward(T v, BackwardIt end) {
|
||||
// THIS IS A HOT FUNCTION with a very deliberate structure to exploit branch
|
||||
// prediction and shorten the critical path for smaller numbers.
|
||||
// Do not move around the if/else blocks or attempt to simplify it
|
||||
// without benchmarking any changes.
|
||||
|
||||
if (v < 10) {
|
||||
goto AT_LEAST_1 /* NOTE: mandatory for the 0 case */;
|
||||
}
|
||||
if (v < 1000) {
|
||||
goto AT_LEAST_10;
|
||||
}
|
||||
if (v < 10000000) {
|
||||
goto AT_LEAST_1000;
|
||||
}
|
||||
|
||||
if (v >= 100000000 / 10) {
|
||||
if (v >= 10000000000000000 / 10) {
|
||||
DoFastIntToBufferBackward<8>(v, end);
|
||||
}
|
||||
DoFastIntToBufferBackward<8>(v, end);
|
||||
}
|
||||
|
||||
if (v >= 10000 / 10) {
|
||||
AT_LEAST_1000:
|
||||
DoFastIntToBufferBackward<4>(v, end);
|
||||
}
|
||||
|
||||
if (v >= 100 / 10) {
|
||||
AT_LEAST_10:
|
||||
DoFastIntToBufferBackward<2>(v, end);
|
||||
}
|
||||
|
||||
if (v >= 10 / 10) {
|
||||
AT_LEAST_1:
|
||||
end = DoFastIntToBufferBackward(v, end, std::integral_constant<int, 1>());
|
||||
}
|
||||
return end;
|
||||
inline ABSL_ATTRIBUTE_ALWAYS_INLINE char* EncodeFullU64(uint64_t i,
|
||||
char* buffer) {
|
||||
if (i <= std::numeric_limits<uint32_t>::max()) {
|
||||
return EncodeFullU32(static_cast<uint32_t>(i), buffer);
|
||||
}
|
||||
|
||||
private:
|
||||
// Only assume pointers are contiguous for now. String and vector iterators
|
||||
// could be special-cased as well, but there's no need for them here.
|
||||
// With C++20 we can probably switch to std::contiguous_iterator_tag.
|
||||
static constexpr bool kIsContiguousIterator =
|
||||
std::is_pointer<BackwardIt>::value;
|
||||
|
||||
template <int Exponent>
|
||||
static void DoFastIntToBufferBackward(T& v, BackwardIt& end) {
|
||||
constexpr T kModulus = Pow<T>(10, Exponent);
|
||||
T remainder = static_cast<T>(v % kModulus);
|
||||
v = static_cast<T>(v / kModulus);
|
||||
end = DoFastIntToBufferBackward(remainder, end,
|
||||
std::integral_constant<int, Exponent>());
|
||||
uint32_t mod08;
|
||||
if (i < 1'0000'0000'0000'0000ull) {
|
||||
uint32_t div08 = static_cast<uint32_t>(i / 100'000'000ull);
|
||||
mod08 = static_cast<uint32_t>(i % 100'000'000ull);
|
||||
buffer = EncodeFullU32(div08, buffer);
|
||||
} else {
|
||||
uint64_t div08 = i / 100'000'000ull;
|
||||
mod08 = static_cast<uint32_t>(i % 100'000'000ull);
|
||||
uint32_t div016 = static_cast<uint32_t>(div08 / 100'000'000ull);
|
||||
uint32_t div08mod08 = static_cast<uint32_t>(div08 % 100'000'000ull);
|
||||
uint64_t mid_result = PrepareEightDigits(div08mod08) + kEightZeroBytes;
|
||||
buffer = EncodeTenThousand(div016, buffer);
|
||||
little_endian::Store64(buffer, mid_result);
|
||||
buffer += sizeof(mid_result);
|
||||
}
|
||||
|
||||
static BackwardIt DoFastIntToBufferBackward(const T&, BackwardIt end,
|
||||
std::integral_constant<int, 0>) {
|
||||
return end;
|
||||
}
|
||||
|
||||
static BackwardIt DoFastIntToBufferBackward(T v, BackwardIt end,
|
||||
std::integral_constant<int, 1>) {
|
||||
*--end = static_cast<char>('0' + v);
|
||||
return DoFastIntToBufferBackward(v, end, std::integral_constant<int, 0>());
|
||||
}
|
||||
|
||||
static BackwardIt DoFastIntToBufferBackward(T v, BackwardIt end,
|
||||
std::integral_constant<int, 4>) {
|
||||
if (kIsContiguousIterator) {
|
||||
const uint32_t digits =
|
||||
PrepareFourDigits(static_cast<uint32_t>(v)) + kFourZeroBytes;
|
||||
end -= sizeof(digits);
|
||||
little_endian::Store32(&*end, digits);
|
||||
} else {
|
||||
uint32_t digits =
|
||||
PrepareFourDigitsReversed(static_cast<uint32_t>(v)) + kFourZeroBytes;
|
||||
for (size_t i = 0; i < sizeof(digits); ++i) {
|
||||
*--end = static_cast<char>(digits);
|
||||
digits >>= CHAR_BIT;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
static BackwardIt DoFastIntToBufferBackward(T v, BackwardIt end,
|
||||
std::integral_constant<int, 8>) {
|
||||
if (kIsContiguousIterator) {
|
||||
const uint64_t digits =
|
||||
PrepareEightDigits(static_cast<uint32_t>(v)) + kEightZeroBytes;
|
||||
end -= sizeof(digits);
|
||||
little_endian::Store64(&*end, digits);
|
||||
} else {
|
||||
uint64_t digits = PrepareEightDigitsReversed(static_cast<uint32_t>(v)) +
|
||||
kEightZeroBytes;
|
||||
for (size_t i = 0; i < sizeof(digits); ++i) {
|
||||
*--end = static_cast<char>(digits);
|
||||
digits >>= CHAR_BIT;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template <int Digits>
|
||||
static BackwardIt DoFastIntToBufferBackward(
|
||||
T v, BackwardIt end, std::integral_constant<int, Digits>) {
|
||||
constexpr int kLogModulus = Digits - Digits / 2;
|
||||
constexpr T kModulus = Pow(static_cast<T>(10), kLogModulus);
|
||||
bool is_safe_to_use_division_trick = Digits <= 8;
|
||||
T quotient, remainder;
|
||||
if (is_safe_to_use_division_trick) {
|
||||
constexpr uint64_t kCoefficient =
|
||||
ComputePowerOf100DivisionCoefficient<uint64_t>(kLogModulus);
|
||||
quotient = (v * kCoefficient) >> (10 * kLogModulus);
|
||||
remainder = v - quotient * kModulus;
|
||||
} else {
|
||||
quotient = v / kModulus;
|
||||
remainder = v % kModulus;
|
||||
}
|
||||
end = DoFastIntToBufferBackward(remainder, end,
|
||||
std::integral_constant<int, kLogModulus>());
|
||||
return DoFastIntToBufferBackward(
|
||||
quotient, end, std::integral_constant<int, Digits - kLogModulus>());
|
||||
}
|
||||
};
|
||||
|
||||
// Returns an iterator to the start of the suffix that was appended
|
||||
template <typename T, typename BackwardIt>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, BackwardIt>
|
||||
DoFastIntToBufferBackward(T v, BackwardIt end, uint32_t digits) {
|
||||
using PromotedT = std::decay_t<decltype(+v)>;
|
||||
using Converter = FastUIntToStringConverter<PromotedT, BackwardIt>;
|
||||
(void)digits;
|
||||
return Converter().FastIntToBufferBackward(v, end);
|
||||
}
|
||||
|
||||
template <typename T, typename BackwardIt>
|
||||
std::enable_if_t<std::is_signed<T>::value, BackwardIt>
|
||||
DoFastIntToBufferBackward(T v, BackwardIt end, uint32_t digits) {
|
||||
if (absl::numbers_internal::IsNegative(v)) {
|
||||
// Store the minus sign *before* we produce the number itself, not after.
|
||||
// This gets us a tail call.
|
||||
end[-static_cast<ptrdiff_t>(digits) - 1] = '-';
|
||||
}
|
||||
return DoFastIntToBufferBackward(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(v), end, digits);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<std::is_integral<T>::value, int>
|
||||
GetNumDigitsOrNegativeIfNegativeImpl(T v) {
|
||||
const auto /* either bool or std::false_type */ is_negative =
|
||||
absl::numbers_internal::IsNegative(v);
|
||||
const int digits = static_cast<int>(absl::numbers_internal::Base10Digits(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(v)));
|
||||
return is_negative ? ~digits : digits;
|
||||
uint64_t mod_result = PrepareEightDigits(mod08) + kEightZeroBytes;
|
||||
little_endian::Store64(buffer, mod_result);
|
||||
return buffer + sizeof(mod_result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void numbers_internal::PutTwoDigits(uint32_t i, absl::Nonnull<char*> buf) {
|
||||
little_endian::Store16(
|
||||
buf, static_cast<uint16_t>(PrepareTwoDigits(i) + kTwoZeroBytes));
|
||||
assert(i < 100);
|
||||
uint32_t base = kTwoZeroBytes;
|
||||
uint32_t div10 = (i * kDivisionBy10Mul) / kDivisionBy10Div;
|
||||
uint32_t mod10 = i - 10u * div10;
|
||||
base += div10 + (mod10 << 8);
|
||||
little_endian::Store16(buf, static_cast<uint16_t>(base));
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
|
||||
uint32_t i, absl::Nonnull<char*> buffer) {
|
||||
const uint32_t digits = absl::numbers_internal::Base10Digits(i);
|
||||
buffer += digits;
|
||||
*buffer = '\0'; // We're going backward, so store this first
|
||||
FastIntToBufferBackward(i, buffer, digits);
|
||||
return buffer;
|
||||
uint32_t n, absl::Nonnull<char*> out_str) {
|
||||
out_str = EncodeFullU32(n, out_str);
|
||||
*out_str = '\0';
|
||||
return out_str;
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
|
||||
int32_t i, absl::Nonnull<char*> buffer) {
|
||||
buffer += static_cast<int>(i < 0);
|
||||
uint32_t digits = absl::numbers_internal::Base10Digits(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(i));
|
||||
buffer += digits;
|
||||
*buffer = '\0'; // We're going backward, so store this first
|
||||
FastIntToBufferBackward(i, buffer, digits);
|
||||
uint32_t u = static_cast<uint32_t>(i);
|
||||
if (i < 0) {
|
||||
*buffer++ = '-';
|
||||
// We need to do the negation in modular (i.e., "unsigned")
|
||||
// arithmetic; MSVC++ apparently warns for plain "-u", so
|
||||
// we write the equivalent expression "0 - u" instead.
|
||||
u = 0 - u;
|
||||
}
|
||||
buffer = EncodeFullU32(u, buffer);
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
|
||||
uint64_t i, absl::Nonnull<char*> buffer) {
|
||||
uint32_t digits = absl::numbers_internal::Base10Digits(i);
|
||||
buffer += digits;
|
||||
*buffer = '\0'; // We're going backward, so store this first
|
||||
FastIntToBufferBackward(i, buffer, digits);
|
||||
buffer = EncodeFullU64(i, buffer);
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBuffer(
|
||||
int64_t i, absl::Nonnull<char*> buffer) {
|
||||
buffer += static_cast<int>(i < 0);
|
||||
uint32_t digits = absl::numbers_internal::Base10Digits(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(i));
|
||||
buffer += digits;
|
||||
*buffer = '\0'; // We're going backward, so store this first
|
||||
FastIntToBufferBackward(i, buffer, digits);
|
||||
uint64_t u = static_cast<uint64_t>(i);
|
||||
if (i < 0) {
|
||||
*buffer++ = '-';
|
||||
// We need to do the negation in modular (i.e., "unsigned")
|
||||
// arithmetic; MSVC++ apparently warns for plain "-u", so
|
||||
// we write the equivalent expression "0 - u" instead.
|
||||
u = 0 - u;
|
||||
}
|
||||
buffer = EncodeFullU64(u, buffer);
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBufferBackward(
|
||||
uint32_t i, absl::Nonnull<char*> buffer_end, uint32_t exact_digit_count) {
|
||||
return DoFastIntToBufferBackward(i, buffer_end, exact_digit_count);
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBufferBackward(
|
||||
int32_t i, absl::Nonnull<char*> buffer_end, uint32_t exact_digit_count) {
|
||||
return DoFastIntToBufferBackward(i, buffer_end, exact_digit_count);
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBufferBackward(
|
||||
uint64_t i, absl::Nonnull<char*> buffer_end, uint32_t exact_digit_count) {
|
||||
return DoFastIntToBufferBackward(i, buffer_end, exact_digit_count);
|
||||
}
|
||||
|
||||
absl::Nonnull<char*> numbers_internal::FastIntToBufferBackward(
|
||||
int64_t i, absl::Nonnull<char*> buffer_end, uint32_t exact_digit_count) {
|
||||
return DoFastIntToBufferBackward(i, buffer_end, exact_digit_count);
|
||||
}
|
||||
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(signed char v) {
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(unsigned char v) {
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(short v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned short v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(int v) {
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(unsigned int v) {
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(long v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned long v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(long long v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
int numbers_internal::GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned long long v) { // NOLINT
|
||||
return GetNumDigitsOrNegativeIfNegativeImpl(v);
|
||||
}
|
||||
|
||||
// Given a 128-bit number expressed as a pair of uint64_t, high half first,
|
||||
// return that number multiplied by the given 32-bit value. If the result is
|
||||
// too large to fit in a 128-bit number, divide it by 2 until it fits.
|
||||
|
||||
163
Pods/abseil/absl/strings/numbers.h
generated
163
Pods/abseil/absl/strings/numbers.h
generated
@@ -32,7 +32,6 @@
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
@@ -40,12 +39,10 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/endian.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/numeric/bits.h"
|
||||
#include "absl/numeric/int128.h"
|
||||
@@ -161,96 +158,6 @@ bool safe_strtou128_base(absl::string_view text,
|
||||
static const int kFastToBufferSize = 32;
|
||||
static const int kSixDigitsToBufferSize = 16;
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<!std::is_unsigned<T>::value, bool> IsNegative(const T& v) {
|
||||
return v < T();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, std::false_type> IsNegative(
|
||||
const T&) {
|
||||
// The integer is unsigned, so return a compile-time constant.
|
||||
// This can help the optimizer avoid having to prove bool to be false later.
|
||||
return std::false_type();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<std::is_unsigned<std::decay_t<T>>::value, T&&>
|
||||
UnsignedAbsoluteValue(T&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) {
|
||||
// The value is unsigned; just return the original.
|
||||
return std::forward<T>(v);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION
|
||||
std::enable_if_t<!std::is_unsigned<T>::value, std::make_unsigned_t<T>>
|
||||
UnsignedAbsoluteValue(T v) {
|
||||
using U = std::make_unsigned_t<T>;
|
||||
return IsNegative(v) ? U() - static_cast<U>(v) : static_cast<U>(v);
|
||||
}
|
||||
|
||||
// Returns the number of base-10 digits in the given number.
|
||||
// Note that this strictly counts digits. It does not count the sign.
|
||||
// The `initial_digits` parameter is the starting point, which is normally equal
|
||||
// to 1 because the number of digits in 0 is 1 (a special case).
|
||||
// However, callers may e.g. wish to change it to 2 to account for the sign.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned<T>::value, uint32_t> Base10Digits(
|
||||
T v, const uint32_t initial_digits = 1) {
|
||||
uint32_t r = initial_digits;
|
||||
// If code size becomes an issue, the 'if' stage can be removed for a minor
|
||||
// performance loss.
|
||||
for (;;) {
|
||||
if (ABSL_PREDICT_TRUE(v < 10 * 10)) {
|
||||
r += (v >= 10);
|
||||
break;
|
||||
}
|
||||
if (ABSL_PREDICT_TRUE(v < 1000 * 10)) {
|
||||
r += (v >= 1000) + 2;
|
||||
break;
|
||||
}
|
||||
if (ABSL_PREDICT_TRUE(v < 100000 * 10)) {
|
||||
r += (v >= 100000) + 4;
|
||||
break;
|
||||
}
|
||||
r += 6;
|
||||
v = static_cast<T>(v / 1000000);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_signed<T>::value, uint32_t> Base10Digits(
|
||||
T v, uint32_t r = 1) {
|
||||
// Branchlessly add 1 to account for a minus sign.
|
||||
r += static_cast<uint32_t>(IsNegative(v));
|
||||
return Base10Digits(UnsignedAbsoluteValue(v), r);
|
||||
}
|
||||
|
||||
// These functions return the number of base-10 digits, but multiplied by -1 if
|
||||
// the input itself is negative. This is handy and efficient for later usage,
|
||||
// since the bitwise complement of the result becomes equal to the number of
|
||||
// characters required.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
signed char v);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned char v);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
short v); // NOLINT
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned short v); // NOLINT
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(int v);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned int v);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
long v); // NOLINT
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned long v); // NOLINT
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
long long v); // NOLINT
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
unsigned long long v); // NOLINT
|
||||
|
||||
// Helper function for fast formatting of floating-point values.
|
||||
// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six
|
||||
// significant digits are returned, trailing zeros are removed, and numbers
|
||||
@@ -259,18 +166,24 @@ ABSL_ATTRIBUTE_CONST_FUNCTION int GetNumDigitsOrNegativeIfNegative(
|
||||
// Required buffer size is `kSixDigitsToBufferSize`.
|
||||
size_t SixDigitsToBuffer(double d, absl::Nonnull<char*> buffer);
|
||||
|
||||
// All of these functions take an output buffer
|
||||
// WARNING: These functions may write more characters than necessary, because
|
||||
// they are intended for speed. All functions take an output buffer
|
||||
// as an argument and return a pointer to the last byte they wrote, which is the
|
||||
// terminating '\0'. At most `kFastToBufferSize` bytes are written.
|
||||
absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer);
|
||||
absl::Nonnull<char*> FastIntToBuffer(uint32_t i, absl::Nonnull<char*> buffer);
|
||||
absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer);
|
||||
absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer);
|
||||
absl::Nonnull<char*> FastIntToBuffer(int32_t i, absl::Nonnull<char*> buffer)
|
||||
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
|
||||
absl::Nonnull<char*> FastIntToBuffer(uint32_t n, absl::Nonnull<char*> out_str)
|
||||
ABSL_INTERNAL_NEED_MIN_SIZE(out_str, kFastToBufferSize);
|
||||
absl::Nonnull<char*> FastIntToBuffer(int64_t i, absl::Nonnull<char*> buffer)
|
||||
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
|
||||
absl::Nonnull<char*> FastIntToBuffer(uint64_t i, absl::Nonnull<char*> buffer)
|
||||
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize);
|
||||
|
||||
// For enums and integer types that are not an exact match for the types above,
|
||||
// use templates to call the appropriate one of the four overloads above.
|
||||
template <typename int_type>
|
||||
absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) {
|
||||
absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer)
|
||||
ABSL_INTERNAL_NEED_MIN_SIZE(buffer, kFastToBufferSize) {
|
||||
static_assert(sizeof(i) <= 64 / 8,
|
||||
"FastIntToBuffer works only with 64-bit-or-less integers.");
|
||||
// TODO(jorg): This signed-ness check is used because it works correctly
|
||||
@@ -294,58 +207,6 @@ absl::Nonnull<char*> FastIntToBuffer(int_type i, absl::Nonnull<char*> buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
// These functions do NOT add any null-terminator.
|
||||
// They return a pointer to the beginning of the written string.
|
||||
// The digit counts provided must *exactly* match the number of base-10 digits
|
||||
// in the number, or the behavior is undefined.
|
||||
// (i.e. do NOT count the minus sign, or over- or under-count the digits.)
|
||||
absl::Nonnull<char*> FastIntToBufferBackward(int32_t i,
|
||||
absl::Nonnull<char*> buffer_end,
|
||||
uint32_t exact_digit_count);
|
||||
absl::Nonnull<char*> FastIntToBufferBackward(uint32_t i,
|
||||
absl::Nonnull<char*> buffer_end,
|
||||
uint32_t exact_digit_count);
|
||||
absl::Nonnull<char*> FastIntToBufferBackward(int64_t i,
|
||||
absl::Nonnull<char*> buffer_end,
|
||||
uint32_t exact_digit_count);
|
||||
absl::Nonnull<char*> FastIntToBufferBackward(uint64_t i,
|
||||
absl::Nonnull<char*> buffer_end,
|
||||
uint32_t exact_digit_count);
|
||||
|
||||
// For enums and integer types that are not an exact match for the types above,
|
||||
// use templates to call the appropriate one of the four overloads above.
|
||||
template <typename int_type>
|
||||
absl::Nonnull<char*> FastIntToBufferBackward(int_type i,
|
||||
absl::Nonnull<char*> buffer_end,
|
||||
uint32_t exact_digit_count) {
|
||||
static_assert(
|
||||
sizeof(i) <= 64 / 8,
|
||||
"FastIntToBufferBackward works only with 64-bit-or-less integers.");
|
||||
// This signed-ness check is used because it works correctly
|
||||
// with enums, and it also serves to check that int_type is not a pointer.
|
||||
// If one day something like std::is_signed<enum E> works, switch to it.
|
||||
// These conditions are constexpr bools to suppress MSVC warning C4127.
|
||||
constexpr bool kIsSigned = static_cast<int_type>(1) - 2 < 0;
|
||||
constexpr bool kUse64Bit = sizeof(i) > 32 / 8;
|
||||
if (kIsSigned) {
|
||||
if (kUse64Bit) {
|
||||
return FastIntToBufferBackward(static_cast<int64_t>(i), buffer_end,
|
||||
exact_digit_count);
|
||||
} else {
|
||||
return FastIntToBufferBackward(static_cast<int32_t>(i), buffer_end,
|
||||
exact_digit_count);
|
||||
}
|
||||
} else {
|
||||
if (kUse64Bit) {
|
||||
return FastIntToBufferBackward(static_cast<uint64_t>(i), buffer_end,
|
||||
exact_digit_count);
|
||||
} else {
|
||||
return FastIntToBufferBackward(static_cast<uint32_t>(i), buffer_end,
|
||||
exact_digit_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation of SimpleAtoi, generalized to support arbitrary base (used
|
||||
// with base different from 10 elsewhere in Abseil implementation).
|
||||
template <typename int_type>
|
||||
|
||||
191
Pods/abseil/absl/strings/str_cat.cc
generated
191
Pods/abseil/absl/strings/str_cat.cc
generated
@@ -20,19 +20,18 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/strings/internal/resize_uninitialized.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StrCat()
|
||||
// This merges the given strings or integers, with no delimiter. This
|
||||
@@ -43,7 +42,8 @@ ABSL_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
// Append is merely a version of memcpy that returns the address of the byte
|
||||
// after the area just overwritten.
|
||||
absl::Nonnull<char*> Append(absl::Nonnull<char*> out, const AlphaNum& x) {
|
||||
inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out,
|
||||
const AlphaNum& x) {
|
||||
// memcpy is allowed to overwrite arbitrary memory, so doing this after the
|
||||
// call would force an extra fetch of x.size().
|
||||
char* after = out + x.size();
|
||||
@@ -53,12 +53,23 @@ absl::Nonnull<char*> Append(absl::Nonnull<char*> out, const AlphaNum& x) {
|
||||
return after;
|
||||
}
|
||||
|
||||
inline void STLStringAppendUninitializedAmortized(std::string* dest,
|
||||
size_t to_append) {
|
||||
strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
|
||||
to_append);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
|
||||
std::string result;
|
||||
absl::strings_internal::STLStringResizeUninitialized(&result,
|
||||
a.size() + b.size());
|
||||
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
|
||||
// in memory strings to overflow a uint64_t.
|
||||
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
|
||||
const uint64_t result_size =
|
||||
static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
|
||||
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
|
||||
absl::strings_internal::STLStringResizeUninitialized(
|
||||
&result, static_cast<size_t>(result_size));
|
||||
char* const begin = &result[0];
|
||||
char* out = begin;
|
||||
out = Append(out, a);
|
||||
@@ -69,8 +80,15 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
|
||||
|
||||
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
|
||||
std::string result;
|
||||
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
|
||||
// in memory strings to overflow a uint64_t.
|
||||
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
|
||||
const uint64_t result_size = static_cast<uint64_t>(a.size()) +
|
||||
static_cast<uint64_t>(b.size()) +
|
||||
static_cast<uint64_t>(c.size());
|
||||
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
|
||||
strings_internal::STLStringResizeUninitialized(
|
||||
&result, a.size() + b.size() + c.size());
|
||||
&result, static_cast<size_t>(result_size));
|
||||
char* const begin = &result[0];
|
||||
char* out = begin;
|
||||
out = Append(out, a);
|
||||
@@ -83,8 +101,16 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
|
||||
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
|
||||
const AlphaNum& d) {
|
||||
std::string result;
|
||||
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
|
||||
// in memory strings to overflow a uint64_t.
|
||||
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
|
||||
const uint64_t result_size = static_cast<uint64_t>(a.size()) +
|
||||
static_cast<uint64_t>(b.size()) +
|
||||
static_cast<uint64_t>(c.size()) +
|
||||
static_cast<uint64_t>(d.size());
|
||||
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
|
||||
strings_internal::STLStringResizeUninitialized(
|
||||
&result, a.size() + b.size() + c.size() + d.size());
|
||||
&result, static_cast<size_t>(result_size));
|
||||
char* const begin = &result[0];
|
||||
char* out = begin;
|
||||
out = Append(out, a);
|
||||
@@ -98,135 +124,18 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
|
||||
namespace strings_internal {
|
||||
|
||||
// Do not call directly - these are not part of the public API.
|
||||
void STLStringAppendUninitializedAmortized(std::string* dest,
|
||||
size_t to_append) {
|
||||
strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
|
||||
to_append);
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
std::enable_if_t<std::is_integral<Integer>::value, std::string> IntegerToString(
|
||||
Integer i) {
|
||||
std::string str;
|
||||
const auto /* either bool or std::false_type */ is_negative =
|
||||
absl::numbers_internal::IsNegative(i);
|
||||
const uint32_t digits = absl::numbers_internal::Base10Digits(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(i));
|
||||
absl::strings_internal::STLStringResizeUninitialized(
|
||||
&str, digits + static_cast<uint32_t>(is_negative));
|
||||
absl::numbers_internal::FastIntToBufferBackward(i, &str[str.size()], digits);
|
||||
return str;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string IntegerToString(long i) { // NOLINT
|
||||
if (sizeof(i) <= sizeof(int)) {
|
||||
return IntegerToString(static_cast<int>(i));
|
||||
} else {
|
||||
return IntegerToString(static_cast<long long>(i)); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string IntegerToString(unsigned long i) { // NOLINT
|
||||
if (sizeof(i) <= sizeof(unsigned int)) {
|
||||
return IntegerToString(static_cast<unsigned int>(i));
|
||||
} else {
|
||||
return IntegerToString(static_cast<unsigned long long>(i)); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
std::enable_if_t<std::is_floating_point<Float>::value, std::string>
|
||||
FloatToString(Float f) {
|
||||
std::string result;
|
||||
strings_internal::STLStringResizeUninitialized(
|
||||
&result, numbers_internal::kSixDigitsToBufferSize);
|
||||
char* start = &result[0];
|
||||
result.erase(numbers_internal::SixDigitsToBuffer(f, start));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string SingleArgStrCat(int x) { return IntegerToString(x); }
|
||||
std::string SingleArgStrCat(unsigned int x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
std::string SingleArgStrCat(long x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
std::string SingleArgStrCat(unsigned long x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
std::string SingleArgStrCat(long long x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
std::string SingleArgStrCat(unsigned long long x) { return IntegerToString(x); }
|
||||
std::string SingleArgStrCat(float x) { return FloatToString(x); }
|
||||
std::string SingleArgStrCat(double x) { return FloatToString(x); }
|
||||
|
||||
template <class Integer>
|
||||
std::enable_if_t<std::is_integral<Integer>::value, void> AppendIntegerToString(
|
||||
std::string& str, Integer i) {
|
||||
const auto /* either bool or std::false_type */ is_negative =
|
||||
absl::numbers_internal::IsNegative(i);
|
||||
const uint32_t digits = absl::numbers_internal::Base10Digits(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(i));
|
||||
absl::strings_internal::STLStringAppendUninitializedAmortized(
|
||||
&str, digits + static_cast<uint32_t>(is_negative));
|
||||
absl::numbers_internal::FastIntToBufferBackward(i, &str[str.size()], digits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void AppendIntegerToString(std::string& str, long i) { // NOLINT
|
||||
if (sizeof(i) <= sizeof(int)) {
|
||||
return AppendIntegerToString(str, static_cast<int>(i));
|
||||
} else {
|
||||
return AppendIntegerToString(str, static_cast<long long>(i)); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void AppendIntegerToString(std::string& str,
|
||||
unsigned long i) { // NOLINT
|
||||
if (sizeof(i) <= sizeof(unsigned int)) {
|
||||
return AppendIntegerToString(str, static_cast<unsigned int>(i));
|
||||
} else {
|
||||
return AppendIntegerToString(str,
|
||||
static_cast<unsigned long long>(i)); // NOLINT
|
||||
}
|
||||
}
|
||||
|
||||
// `SingleArgStrAppend` overloads are defined here for the same reasons as with
|
||||
// `SingleArgStrCat` above.
|
||||
void SingleArgStrAppend(std::string& str, int x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
void SingleArgStrAppend(std::string& str, unsigned int x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void SingleArgStrAppend(std::string& str, long x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void SingleArgStrAppend(std::string& str, unsigned long x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void SingleArgStrAppend(std::string& str, long long x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
void SingleArgStrAppend(std::string& str, unsigned long long x) {
|
||||
return AppendIntegerToString(str, x);
|
||||
}
|
||||
|
||||
std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
|
||||
std::string result;
|
||||
size_t total_size = 0;
|
||||
for (absl::string_view piece : pieces) total_size += piece.size();
|
||||
strings_internal::STLStringResizeUninitialized(&result, total_size);
|
||||
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
|
||||
// in memory strings to overflow a uint64_t.
|
||||
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
|
||||
uint64_t total_size = 0;
|
||||
for (absl::string_view piece : pieces) {
|
||||
total_size += piece.size();
|
||||
}
|
||||
ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
|
||||
strings_internal::STLStringResizeUninitialized(
|
||||
&result, static_cast<size_t>(total_size));
|
||||
|
||||
char* const begin = &result[0];
|
||||
char* out = begin;
|
||||
@@ -258,7 +167,7 @@ void AppendPieces(absl::Nonnull<std::string*> dest,
|
||||
ASSERT_NO_OVERLAP(*dest, piece);
|
||||
to_append += piece.size();
|
||||
}
|
||||
strings_internal::STLStringAppendUninitializedAmortized(dest, to_append);
|
||||
STLStringAppendUninitializedAmortized(dest, to_append);
|
||||
|
||||
char* const begin = &(*dest)[0];
|
||||
char* out = begin + old_size;
|
||||
@@ -277,7 +186,7 @@ void AppendPieces(absl::Nonnull<std::string*> dest,
|
||||
void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
|
||||
ASSERT_NO_OVERLAP(*dest, a);
|
||||
std::string::size_type old_size = dest->size();
|
||||
strings_internal::STLStringAppendUninitializedAmortized(dest, a.size());
|
||||
STLStringAppendUninitializedAmortized(dest, a.size());
|
||||
char* const begin = &(*dest)[0];
|
||||
char* out = begin + old_size;
|
||||
out = Append(out, a);
|
||||
@@ -289,8 +198,7 @@ void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
|
||||
ASSERT_NO_OVERLAP(*dest, a);
|
||||
ASSERT_NO_OVERLAP(*dest, b);
|
||||
std::string::size_type old_size = dest->size();
|
||||
strings_internal::STLStringAppendUninitializedAmortized(dest,
|
||||
a.size() + b.size());
|
||||
STLStringAppendUninitializedAmortized(dest, a.size() + b.size());
|
||||
char* const begin = &(*dest)[0];
|
||||
char* out = begin + old_size;
|
||||
out = Append(out, a);
|
||||
@@ -304,8 +212,7 @@ void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
|
||||
ASSERT_NO_OVERLAP(*dest, b);
|
||||
ASSERT_NO_OVERLAP(*dest, c);
|
||||
std::string::size_type old_size = dest->size();
|
||||
strings_internal::STLStringAppendUninitializedAmortized(
|
||||
dest, a.size() + b.size() + c.size());
|
||||
STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size());
|
||||
char* const begin = &(*dest)[0];
|
||||
char* out = begin + old_size;
|
||||
out = Append(out, a);
|
||||
@@ -321,7 +228,7 @@ void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
|
||||
ASSERT_NO_OVERLAP(*dest, c);
|
||||
ASSERT_NO_OVERLAP(*dest, d);
|
||||
std::string::size_type old_size = dest->size();
|
||||
strings_internal::STLStringAppendUninitializedAmortized(
|
||||
STLStringAppendUninitializedAmortized(
|
||||
dest, a.size() + b.size() + c.size() + d.size());
|
||||
char* const begin = &(*dest)[0];
|
||||
char* out = begin + old_size;
|
||||
|
||||
151
Pods/abseil/absl/strings/str_cat.h
generated
151
Pods/abseil/absl/strings/str_cat.h
generated
@@ -93,6 +93,8 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -312,6 +314,10 @@ class AlphaNum {
|
||||
// No bool ctor -- bools convert to an integral type.
|
||||
// A bool ctor would also convert incoming pointers (bletch).
|
||||
|
||||
// Prevent brace initialization
|
||||
template <typename T>
|
||||
AlphaNum(std::initializer_list<T>) = delete; // NOLINT(runtime/explicit)
|
||||
|
||||
AlphaNum(int x) // NOLINT(runtime/explicit)
|
||||
: piece_(digits_, static_cast<size_t>(
|
||||
numbers_internal::FastIntToBuffer(x, digits_) -
|
||||
@@ -448,36 +454,77 @@ std::string CatPieces(std::initializer_list<absl::string_view> pieces);
|
||||
void AppendPieces(absl::Nonnull<std::string*> dest,
|
||||
std::initializer_list<absl::string_view> pieces);
|
||||
|
||||
void STLStringAppendUninitializedAmortized(std::string* dest, size_t to_append);
|
||||
template <typename Integer>
|
||||
std::string IntegerToString(Integer i) {
|
||||
// Any integer (signed/unsigned) up to 64 bits can be formatted into a buffer
|
||||
// with 22 bytes (including NULL at the end).
|
||||
constexpr size_t kMaxDigits10 = 22;
|
||||
std::string result;
|
||||
strings_internal::STLStringResizeUninitialized(&result, kMaxDigits10);
|
||||
char* start = &result[0];
|
||||
// note: this can be optimized to not write last zero.
|
||||
char* end = numbers_internal::FastIntToBuffer(i, start);
|
||||
auto size = static_cast<size_t>(end - start);
|
||||
assert((size < result.size()) &&
|
||||
"StrCat(Integer) does not fit into kMaxDigits10");
|
||||
result.erase(size);
|
||||
return result;
|
||||
}
|
||||
template <typename Float>
|
||||
std::string FloatToString(Float f) {
|
||||
std::string result;
|
||||
strings_internal::STLStringResizeUninitialized(
|
||||
&result, numbers_internal::kSixDigitsToBufferSize);
|
||||
char* start = &result[0];
|
||||
result.erase(numbers_internal::SixDigitsToBuffer(f, start));
|
||||
return result;
|
||||
}
|
||||
|
||||
// `SingleArgStrCat` overloads take built-in `int`, `long` and `long long` types
|
||||
// (signed / unsigned) to avoid ambiguity on the call side. If we used int32_t
|
||||
// and int64_t, then at least one of the three (`int` / `long` / `long long`)
|
||||
// would have been ambiguous when passed to `SingleArgStrCat`.
|
||||
std::string SingleArgStrCat(int x);
|
||||
std::string SingleArgStrCat(unsigned int x);
|
||||
std::string SingleArgStrCat(long x); // NOLINT
|
||||
std::string SingleArgStrCat(unsigned long x); // NOLINT
|
||||
std::string SingleArgStrCat(long long x); // NOLINT
|
||||
std::string SingleArgStrCat(unsigned long long x); // NOLINT
|
||||
std::string SingleArgStrCat(float x);
|
||||
std::string SingleArgStrCat(double x);
|
||||
inline std::string SingleArgStrCat(int x) { return IntegerToString(x); }
|
||||
inline std::string SingleArgStrCat(unsigned int x) {
|
||||
return IntegerToString(x);
|
||||
}
|
||||
// NOLINTNEXTLINE
|
||||
inline std::string SingleArgStrCat(long x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
inline std::string SingleArgStrCat(unsigned long x) {
|
||||
return IntegerToString(x);
|
||||
}
|
||||
// NOLINTNEXTLINE
|
||||
inline std::string SingleArgStrCat(long long x) { return IntegerToString(x); }
|
||||
// NOLINTNEXTLINE
|
||||
inline std::string SingleArgStrCat(unsigned long long x) {
|
||||
return IntegerToString(x);
|
||||
}
|
||||
inline std::string SingleArgStrCat(float x) { return FloatToString(x); }
|
||||
inline std::string SingleArgStrCat(double x) { return FloatToString(x); }
|
||||
|
||||
// `SingleArgStrAppend` overloads are defined here for the same reasons as with
|
||||
// `SingleArgStrCat` above.
|
||||
void SingleArgStrAppend(std::string& str, int x);
|
||||
void SingleArgStrAppend(std::string& str, unsigned int x);
|
||||
void SingleArgStrAppend(std::string& str, long x); // NOLINT
|
||||
void SingleArgStrAppend(std::string& str, unsigned long x); // NOLINT
|
||||
void SingleArgStrAppend(std::string& str, long long x); // NOLINT
|
||||
void SingleArgStrAppend(std::string& str, unsigned long long x); // NOLINT
|
||||
// As of September 2023, the SingleArgStrCat() optimization is only enabled for
|
||||
// libc++. The reasons for this are:
|
||||
// 1) The SSO size for libc++ is 23, while libstdc++ and MSSTL have an SSO size
|
||||
// of 15. Since IntegerToString unconditionally resizes the string to 22 bytes,
|
||||
// this causes both libstdc++ and MSSTL to allocate.
|
||||
// 2) strings_internal::STLStringResizeUninitialized() only has an
|
||||
// implementation that avoids initialization when using libc++. This isn't as
|
||||
// relevant as (1), and the cost should be benchmarked if (1) ever changes on
|
||||
// libstc++ or MSSTL.
|
||||
#ifdef _LIBCPP_VERSION
|
||||
#define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE true
|
||||
#else
|
||||
#define ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE false
|
||||
#endif
|
||||
|
||||
template <typename T,
|
||||
typename = std::enable_if_t<std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, char>::value &&
|
||||
!std::is_same<T, bool>::value>>
|
||||
template <typename T, typename = std::enable_if_t<
|
||||
ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE &&
|
||||
std::is_arithmetic<T>{} && !std::is_same<T, char>{}>>
|
||||
using EnableIfFastCase = T;
|
||||
|
||||
#undef ABSL_INTERNAL_STRCAT_ENABLE_FAST_CASE
|
||||
|
||||
} // namespace strings_internal
|
||||
|
||||
ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
|
||||
@@ -553,68 +600,6 @@ inline void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
|
||||
static_cast<const AlphaNum&>(args).Piece()...});
|
||||
}
|
||||
|
||||
template <class String, class T>
|
||||
std::enable_if_t<
|
||||
std::is_integral<absl::strings_internal::EnableIfFastCase<T>>::value, void>
|
||||
StrAppend(absl::Nonnull<String*> result, T i) {
|
||||
return absl::strings_internal::SingleArgStrAppend(*result, i);
|
||||
}
|
||||
|
||||
// This overload is only selected if all the parameters are numbers that can be
|
||||
// handled quickly.
|
||||
// Later we can look into how we can extend this to more general argument
|
||||
// mixtures without bloating codegen too much, or copying unnecessarily.
|
||||
template <typename String, typename... T>
|
||||
std::enable_if_t<
|
||||
(sizeof...(T) > 1),
|
||||
std::common_type_t<std::conditional_t<
|
||||
true, void, absl::strings_internal::EnableIfFastCase<T>>...>>
|
||||
StrAppend(absl::Nonnull<String*> str, T... args) {
|
||||
// Do not add unnecessary variables, logic, or even "free" lambdas here.
|
||||
// They can add overhead for the compiler and/or at run time.
|
||||
// Furthermore, assume this function will be inlined.
|
||||
// This function is carefully tailored to be able to be largely optimized away
|
||||
// so that it becomes near-equivalent to the caller handling each argument
|
||||
// individually while minimizing register pressure, so that the compiler
|
||||
// can inline it with minimal overhead.
|
||||
|
||||
// First, calculate the total length, so we can perform just a single resize.
|
||||
// Save all the lengths for later.
|
||||
size_t total_length = 0;
|
||||
const ptrdiff_t lengths[] = {
|
||||
absl::numbers_internal::GetNumDigitsOrNegativeIfNegative(args)...};
|
||||
for (const ptrdiff_t possibly_negative_length : lengths) {
|
||||
// Lengths are negative for negative numbers. Keep them for later use, but
|
||||
// take their absolute values for calculating total lengths;
|
||||
total_length += possibly_negative_length < 0
|
||||
? static_cast<size_t>(-possibly_negative_length)
|
||||
: static_cast<size_t>(possibly_negative_length);
|
||||
}
|
||||
|
||||
// Now reserve space for all the arguments.
|
||||
const size_t old_size = str->size();
|
||||
absl::strings_internal::STLStringAppendUninitializedAmortized(str,
|
||||
total_length);
|
||||
|
||||
// Finally, output each argument one-by-one, from left to right.
|
||||
size_t i = 0; // The current argument we're processing
|
||||
ptrdiff_t n; // The length of the current argument
|
||||
typename String::pointer pos = &(*str)[old_size];
|
||||
using SomeTrivialEmptyType = std::false_type;
|
||||
// Ugly code due to the lack of C++14 fold expression makes us.
|
||||
const SomeTrivialEmptyType dummy1;
|
||||
for (const SomeTrivialEmptyType& dummy2 :
|
||||
{(/* Comma expressions are poor man's C++17 fold expression for C++14 */
|
||||
(void)(n = lengths[i]),
|
||||
(void)(n < 0 ? (void)(*pos++ = '-'), (n = ~n) : 0),
|
||||
(void)absl::numbers_internal::FastIntToBufferBackward(
|
||||
absl::numbers_internal::UnsignedAbsoluteValue(std::move(args)),
|
||||
pos += n, static_cast<uint32_t>(n)),
|
||||
(void)++i, dummy1)...}) {
|
||||
(void)dummy2; // Remove & migrate to fold expressions in C++17
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for the future StrCat default floating-point format, %.6g
|
||||
// This is fast.
|
||||
inline strings_internal::AlphaNumBuffer<
|
||||
|
||||
2
Pods/abseil/absl/strings/str_format.h
generated
2
Pods/abseil/absl/strings/str_format.h
generated
@@ -181,7 +181,7 @@ class FormatCountCapture {
|
||||
// For a `FormatSpec` to be valid at compile-time, it must be provided as
|
||||
// either:
|
||||
//
|
||||
// * A `constexpr` literal or `absl::string_view`, which is how it most often
|
||||
// * A `constexpr` literal or `absl::string_view`, which is how it is most often
|
||||
// used.
|
||||
// * A `ParsedFormat` instantiation, which ensures the format string is
|
||||
// valid before use. (See below.)
|
||||
|
||||
24
Pods/abseil/absl/strings/str_join.h
generated
24
Pods/abseil/absl/strings/str_join.h
generated
@@ -247,12 +247,20 @@ std::string StrJoin(const Range& range, absl::string_view separator,
|
||||
return strings_internal::JoinRange(range, separator, fmt);
|
||||
}
|
||||
|
||||
template <typename T, typename Formatter>
|
||||
template <typename T, typename Formatter,
|
||||
typename = typename std::enable_if<
|
||||
!std::is_convertible<T, absl::string_view>::value>::type>
|
||||
std::string StrJoin(std::initializer_list<T> il, absl::string_view separator,
|
||||
Formatter&& fmt) {
|
||||
return strings_internal::JoinRange(il, separator, fmt);
|
||||
}
|
||||
|
||||
template <typename Formatter>
|
||||
inline std::string StrJoin(std::initializer_list<absl::string_view> il,
|
||||
absl::string_view separator, Formatter&& fmt) {
|
||||
return strings_internal::JoinRange(il, separator, fmt);
|
||||
}
|
||||
|
||||
template <typename... T, typename Formatter>
|
||||
std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator,
|
||||
Formatter&& fmt) {
|
||||
@@ -269,16 +277,22 @@ std::string StrJoin(const Range& range, absl::string_view separator) {
|
||||
return strings_internal::JoinRange(range, separator);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string StrJoin(std::initializer_list<T> il,
|
||||
absl::string_view separator) {
|
||||
template <typename T, typename = typename std::enable_if<!std::is_convertible<
|
||||
T, absl::string_view>::value>::type>
|
||||
std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) {
|
||||
return strings_internal::JoinRange(il, separator);
|
||||
}
|
||||
|
||||
inline std::string StrJoin(std::initializer_list<absl::string_view> il,
|
||||
absl::string_view separator) {
|
||||
return strings_internal::JoinRange(il, separator);
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
std::string StrJoin(const std::tuple<T...>& value,
|
||||
absl::string_view separator) {
|
||||
return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter());
|
||||
return strings_internal::JoinTuple(value, separator,
|
||||
std::index_sequence_for<T...>{});
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
|
||||
4
Pods/abseil/absl/strings/str_split.h
generated
4
Pods/abseil/absl/strings/str_split.h
generated
@@ -456,7 +456,7 @@ using EnableSplitIfString =
|
||||
// // Stores results in a std::set<std::string>, which also performs
|
||||
// // de-duplication and orders the elements in ascending order.
|
||||
// std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ',');
|
||||
// // v[0] == "a", v[1] == "b", v[2] = "c"
|
||||
// // a[0] == "a", a[1] == "b", a[2] == "c"
|
||||
//
|
||||
// // `StrSplit()` can be used within a range-based for loop, in which case
|
||||
// // each element will be of type `absl::string_view`.
|
||||
@@ -544,7 +544,7 @@ StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d,
|
||||
typename strings_internal::SelectDelimiter<Delimiter>::type;
|
||||
return strings_internal::Splitter<DelimiterType, Predicate,
|
||||
absl::string_view>(
|
||||
text.value(), DelimiterType(d), std::move(p));
|
||||
text.value(), DelimiterType(std::move(d)), std::move(p));
|
||||
}
|
||||
|
||||
template <typename Delimiter, typename Predicate, typename StringType,
|
||||
|
||||
5
Pods/abseil/absl/strings/string_view.h
generated
5
Pods/abseil/absl/strings/string_view.h
generated
@@ -159,7 +159,7 @@ ABSL_NAMESPACE_BEGIN
|
||||
//
|
||||
// absl::string_view() == absl::string_view("", 0)
|
||||
// absl::string_view(nullptr, 0) == absl::string_view("abcdef"+6, 0)
|
||||
class string_view {
|
||||
class ABSL_INTERNAL_ATTRIBUTE_VIEW string_view {
|
||||
public:
|
||||
using traits_type = std::char_traits<char>;
|
||||
using value_type = char;
|
||||
@@ -173,6 +173,7 @@ class string_view {
|
||||
using reverse_iterator = const_reverse_iterator;
|
||||
using size_type = size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using absl_internal_is_view = std::true_type;
|
||||
|
||||
static constexpr size_type npos = static_cast<size_type>(-1);
|
||||
|
||||
@@ -670,7 +671,7 @@ class string_view {
|
||||
}
|
||||
|
||||
static constexpr size_type StrlenInternal(absl::Nonnull<const char*> str) {
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1910 && !defined(__clang__)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// MSVC 2017+ can evaluate this at compile-time.
|
||||
const char* begin = str;
|
||||
while (*str != '\0') ++str;
|
||||
|
||||
4
Pods/abseil/absl/strings/substitute.cc
generated
4
Pods/abseil/absl/strings/substitute.cc
generated
@@ -18,6 +18,7 @@
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
@@ -84,6 +85,9 @@ void SubstituteAndAppendArray(
|
||||
|
||||
// Build the string.
|
||||
size_t original_size = output->size();
|
||||
ABSL_INTERNAL_CHECK(
|
||||
size <= std::numeric_limits<size_t>::max() - original_size,
|
||||
"size_t overflow");
|
||||
strings_internal::STLStringResizeUninitializedAmortized(output,
|
||||
original_size + size);
|
||||
char* target = &(*output)[original_size];
|
||||
|
||||
Reference in New Issue
Block a user