| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #ifndef ABSL_STRINGS_STR_CAT_H_ |
| #define ABSL_STRINGS_STR_CAT_H_ |
|
|
| #include <algorithm> |
| #include <array> |
| #include <cassert> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstring> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
|
|
| #include "absl/base/attributes.h" |
| #include "absl/base/nullability.h" |
| #include "absl/base/port.h" |
| #include "absl/meta/type_traits.h" |
| #include "absl/strings/has_absl_stringify.h" |
| #include "absl/strings/internal/resize_uninitialized.h" |
| #include "absl/strings/internal/stringify_sink.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/string_view.h" |
|
|
| namespace absl { |
| ABSL_NAMESPACE_BEGIN |
|
|
| namespace strings_internal { |
| |
| |
| |
| template <size_t max_size> |
| struct AlphaNumBuffer { |
| std::array<char, max_size> data; |
| size_t size; |
| }; |
|
|
| } |
|
|
| |
| |
| |
| |
| enum PadSpec : uint8_t { |
| kNoPad = 1, |
| kZeroPad2, |
| kZeroPad3, |
| kZeroPad4, |
| kZeroPad5, |
| kZeroPad6, |
| kZeroPad7, |
| kZeroPad8, |
| kZeroPad9, |
| kZeroPad10, |
| kZeroPad11, |
| kZeroPad12, |
| kZeroPad13, |
| kZeroPad14, |
| kZeroPad15, |
| kZeroPad16, |
| kZeroPad17, |
| kZeroPad18, |
| kZeroPad19, |
| kZeroPad20, |
|
|
| kSpacePad2 = kZeroPad2 + 64, |
| kSpacePad3, |
| kSpacePad4, |
| kSpacePad5, |
| kSpacePad6, |
| kSpacePad7, |
| kSpacePad8, |
| kSpacePad9, |
| kSpacePad10, |
| kSpacePad11, |
| kSpacePad12, |
| kSpacePad13, |
| kSpacePad14, |
| kSpacePad15, |
| kSpacePad16, |
| kSpacePad17, |
| kSpacePad18, |
| kSpacePad19, |
| kSpacePad20, |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| struct Hex { |
| uint64_t value; |
| uint8_t width; |
| char fill; |
|
|
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| typename std::enable_if<sizeof(Int) == 1 && |
| !std::is_pointer<Int>::value>::type* = nullptr) |
| : Hex(spec, static_cast<uint8_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| typename std::enable_if<sizeof(Int) == 2 && |
| !std::is_pointer<Int>::value>::type* = nullptr) |
| : Hex(spec, static_cast<uint16_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| typename std::enable_if<sizeof(Int) == 4 && |
| !std::is_pointer<Int>::value>::type* = nullptr) |
| : Hex(spec, static_cast<uint32_t>(v)) {} |
| template <typename Int> |
| explicit Hex( |
| Int v, PadSpec spec = absl::kNoPad, |
| typename std::enable_if<sizeof(Int) == 8 && |
| !std::is_pointer<Int>::value>::type* = nullptr) |
| : Hex(spec, static_cast<uint64_t>(v)) {} |
| template <typename Pointee> |
| explicit Hex(absl::Nullable<Pointee*> v, PadSpec spec = absl::kNoPad) |
| : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} |
|
|
| template <typename S> |
| friend void AbslStringify(S& sink, Hex hex) { |
| static_assert( |
| numbers_internal::kFastToBufferSize >= 32, |
| "This function only works when output buffer >= 32 bytes long"); |
| char buffer[numbers_internal::kFastToBufferSize]; |
| char* const end = &buffer[numbers_internal::kFastToBufferSize]; |
| auto real_width = |
| absl::numbers_internal::FastHexToBufferZeroPad16(hex.value, end - 16); |
| if (real_width >= hex.width) { |
| sink.Append(absl::string_view(end - real_width, real_width)); |
| } else { |
| |
| |
| std::memset(end - 32, hex.fill, 16); |
| |
| std::memset(end - real_width - 16, hex.fill, 16); |
| sink.Append(absl::string_view(end - hex.width, hex.width)); |
| } |
| } |
|
|
| private: |
| Hex(PadSpec spec, uint64_t v) |
| : value(v), |
| width(spec == absl::kNoPad |
| ? 1 |
| : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 |
| : spec - absl::kZeroPad2 + 2), |
| fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| struct Dec { |
| uint64_t value; |
| uint8_t width; |
| char fill; |
| bool neg; |
|
|
| template <typename Int> |
| explicit Dec(Int v, PadSpec spec = absl::kNoPad, |
| typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) |
| : value(v >= 0 ? static_cast<uint64_t>(v) |
| : uint64_t{0} - static_cast<uint64_t>(v)), |
| width(spec == absl::kNoPad ? 1 |
| : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 |
| : spec - absl::kZeroPad2 + 2), |
| fill(spec >= absl::kSpacePad2 ? ' ' : '0'), |
| neg(v < 0) {} |
|
|
| template <typename S> |
| friend void AbslStringify(S& sink, Dec dec) { |
| assert(dec.width <= numbers_internal::kFastToBufferSize); |
| char buffer[numbers_internal::kFastToBufferSize]; |
| char* const end = &buffer[numbers_internal::kFastToBufferSize]; |
| char* const minfill = end - dec.width; |
| char* writer = end; |
| uint64_t val = dec.value; |
| while (val > 9) { |
| *--writer = '0' + (val % 10); |
| val /= 10; |
| } |
| *--writer = '0' + static_cast<char>(val); |
| if (dec.neg) *--writer = '-'; |
|
|
| ptrdiff_t fillers = writer - minfill; |
| if (fillers > 0) { |
| |
| |
| bool add_sign_again = false; |
| if (dec.neg && dec.fill == '0') { |
| ++writer; |
| add_sign_again = true; |
| } |
| writer -= fillers; |
| std::fill_n(writer, fillers, dec.fill); |
| if (add_sign_again) *--writer = '-'; |
| } |
|
|
| sink.Append(absl::string_view(writer, static_cast<size_t>(end - writer))); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| class AlphaNum { |
| public: |
| |
| |
|
|
| AlphaNum(int x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned int x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(long x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned long x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(long long x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
| AlphaNum(unsigned long long x) |
| : piece_(digits_, static_cast<size_t>( |
| numbers_internal::FastIntToBuffer(x, digits_) - |
| &digits_[0])) {} |
|
|
| AlphaNum(float f) |
| : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} |
| AlphaNum(double f) |
| : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} |
|
|
| template <size_t size> |
| AlphaNum( |
| const strings_internal::AlphaNumBuffer<size>& buf |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(&buf.data[0], buf.size) {} |
|
|
| AlphaNum(absl::Nullable<const char*> c_str |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(NullSafeStringView(c_str)) {} |
| AlphaNum(absl::string_view pc |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(pc) {} |
|
|
| template <typename T, typename = typename std::enable_if< |
| HasAbslStringify<T>::value>::type> |
| AlphaNum( |
| const T& v ABSL_ATTRIBUTE_LIFETIME_BOUND, |
| strings_internal::StringifySink&& sink ABSL_ATTRIBUTE_LIFETIME_BOUND = {}) |
| : piece_(strings_internal::ExtractStringification(sink, v)) {} |
|
|
| template <typename Allocator> |
| AlphaNum( |
| const std::basic_string<char, std::char_traits<char>, Allocator>& str |
| ABSL_ATTRIBUTE_LIFETIME_BOUND) |
| : piece_(str) {} |
|
|
| |
| AlphaNum(char c) = delete; |
|
|
| AlphaNum(const AlphaNum&) = delete; |
| AlphaNum& operator=(const AlphaNum&) = delete; |
|
|
| absl::string_view::size_type size() const { return piece_.size(); } |
| absl::Nullable<const char*> data() const { return piece_.data(); } |
| absl::string_view Piece() const { return piece_; } |
|
|
| |
| |
| template <typename T, |
| typename = typename std::enable_if< |
| std::is_enum<T>{} && std::is_convertible<T, int>{} && |
| !HasAbslStringify<T>::value>::type> |
| AlphaNum(T e) |
| : AlphaNum(+e) {} |
|
|
| |
| |
| template <typename T, |
| typename std::enable_if<std::is_enum<T>{} && |
| !std::is_convertible<T, int>{} && |
| !HasAbslStringify<T>::value, |
| char*>::type = nullptr> |
| AlphaNum(T e) |
| : AlphaNum(+static_cast<typename std::underlying_type<T>::type>(e)) {} |
|
|
| |
| |
| template < |
| typename T, |
| typename std::enable_if< |
| std::is_class<T>::value && |
| (std::is_same<T, std::vector<bool>::reference>::value || |
| std::is_same<T, std::vector<bool>::const_reference>::value)>::type* = |
| nullptr> |
| AlphaNum(T e) : AlphaNum(static_cast<bool>(e)) {} |
|
|
| private: |
| absl::string_view piece_; |
| char digits_[numbers_internal::kFastToBufferSize]; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| namespace strings_internal { |
|
|
| |
| 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); |
|
|
| |
| |
| |
| |
| std::string SingleArgStrCat(int x); |
| std::string SingleArgStrCat(unsigned int x); |
| std::string SingleArgStrCat(long x); |
| std::string SingleArgStrCat(unsigned long x); |
| std::string SingleArgStrCat(long long x); |
| std::string SingleArgStrCat(unsigned long long x); |
| std::string SingleArgStrCat(float x); |
| std::string SingleArgStrCat(double x); |
|
|
| |
| |
| void SingleArgStrAppend(std::string& str, int x); |
| void SingleArgStrAppend(std::string& str, unsigned int x); |
| void SingleArgStrAppend(std::string& str, long x); |
| void SingleArgStrAppend(std::string& str, unsigned long x); |
| void SingleArgStrAppend(std::string& str, long long x); |
| void SingleArgStrAppend(std::string& str, unsigned long long x); |
|
|
| 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>> |
| using EnableIfFastCase = T; |
|
|
| } |
|
|
| ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } |
|
|
| template <typename T> |
| ABSL_MUST_USE_RESULT inline std::string StrCat( |
| strings_internal::EnableIfFastCase<T> a) { |
| return strings_internal::SingleArgStrCat(a); |
| } |
| ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { |
| return std::string(a.data(), a.size()); |
| } |
|
|
| ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); |
| ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, |
| const AlphaNum& c); |
| ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, |
| const AlphaNum& c, const AlphaNum& d); |
|
|
| |
| template <typename... AV> |
| ABSL_MUST_USE_RESULT inline std::string StrCat( |
| const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
| const AlphaNum& e, const AV&... args) { |
| return strings_internal::CatPieces( |
| {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), |
| static_cast<const AlphaNum&>(args).Piece()...}); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| inline void StrAppend(absl::Nonnull<std::string*>) {} |
| void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a); |
| void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, |
| const AlphaNum& b); |
| void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c); |
| void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c, const AlphaNum& d); |
|
|
| |
| template <typename... AV> |
| inline void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a, |
| const AlphaNum& b, const AlphaNum& c, const AlphaNum& d, |
| const AlphaNum& e, const AV&... args) { |
| strings_internal::AppendPieces( |
| dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), |
| 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); |
| } |
|
|
| |
| |
| |
| |
| 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) { |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| size_t total_length = 0; |
| const ptrdiff_t lengths[] = { |
| absl::numbers_internal::GetNumDigitsOrNegativeIfNegative(args)...}; |
| for (const ptrdiff_t possibly_negative_length : lengths) { |
| |
| |
| total_length += possibly_negative_length < 0 |
| ? static_cast<size_t>(-possibly_negative_length) |
| : static_cast<size_t>(possibly_negative_length); |
| } |
|
|
| |
| const size_t old_size = str->size(); |
| absl::strings_internal::STLStringAppendUninitializedAmortized(str, |
| total_length); |
|
|
| |
| size_t i = 0; |
| ptrdiff_t n; |
| typename String::pointer pos = &(*str)[old_size]; |
| using SomeTrivialEmptyType = std::false_type; |
| const SomeTrivialEmptyType dummy; |
| |
| const SomeTrivialEmptyType dummies[] = { |
| ( |
| (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, dummy)...}; |
| (void)dummies; |
| } |
|
|
| |
| |
| inline strings_internal::AlphaNumBuffer< |
| numbers_internal::kSixDigitsToBufferSize> |
| SixDigits(double d) { |
| strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize> |
| result; |
| result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); |
| return result; |
| } |
|
|
| ABSL_NAMESPACE_END |
| } |
|
|
| #endif |
|
|