-- 074a799119ac881b8b8ce59ef7a3166d1aa025ac by Tom Manshreck <shreck@google.com>: nit: Add return info for StrCat PiperOrigin-RevId: 278647298 -- d58a2a39ab6f50266cc695506ba2e86bdb45d795 by Mark Barolak <mbar@google.com>: Stop suppressing no-nested-anon-types warnings because there aren't actually any warnings to suppress. PiperOrigin-RevId: 278440548 -- 445051bd280b9a6f608a8c80b3d7cafcc1377a03 by Abseil Team <absl-team@google.com>: ResetThreadIdentity does not need to clear identity->waiter_state. ResetThreadIdentity is only called by NewThreadIdentity. NewThreadIdentity is only called by CreateThreadIdentity. CreateThreadIdentity calls PerThreadSem::Init, which initializes identity->waiter_state, immediately after calling NewThreadIdentity. Therefore ResetThreadIdentity does not need to clear identity->waiter_state. PiperOrigin-RevId: 278429844 -- c2079b664d92be40d5e365abcca4e9b3505a75a6 by Abseil Team <absl-team@google.com>: Delete the f->header.magic check in LowLevelAlloc::Free(). The f->header.magic check in LowLevelAlloc::Free() is redundant, because AddToFreeList() will immediately perform the same check. Also fix a typo in the comment that documents the lock requirements for Next(). The comment should say "L >= arena->mu", which is equivalent to EXCLUSIVE_LOCKS_REQUIRED(arena->mu). NOTE: LowLevelAlloc::Free() performs the f->header.magic check without holding the arena lock. This may have caused the TSAN data race warning reported in bug 143697235. PiperOrigin-RevId: 278414140 -- 5534f35ce677165700117d868f51607ed1f0d73b by Greg Falcon <gfalcon@google.com>: Add an internal (unsupported) PiecewiseCombiner class to allow hashing buffers piecewise. PiperOrigin-RevId: 278388902 GitOrigin-RevId: 074a799119ac881b8b8ce59ef7a3166d1aa025ac Change-Id: I61734850cbbb01c7585e8c736a5bb56e416512a8
		
			
				
	
	
		
			406 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			406 lines
		
	
	
	
		
			15 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //
 | |
| // Copyright 2017 The Abseil Authors.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      https://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| //
 | |
| // -----------------------------------------------------------------------------
 | |
| // File: str_cat.h
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // This package contains functions for efficiently concatenating and appending
 | |
| // strings: `StrCat()` and `StrAppend()`. Most of the work within these routines
 | |
| // is actually handled through use of a special AlphaNum type, which was
 | |
| // designed to be used as a parameter type that efficiently manages conversion
 | |
| // to strings and avoids copies in the above operations.
 | |
| //
 | |
| // Any routine accepting either a string or a number may accept `AlphaNum`.
 | |
| // The basic idea is that by accepting a `const AlphaNum &` as an argument
 | |
| // to your function, your callers will automagically convert bools, integers,
 | |
| // and floating point values to strings for you.
 | |
| //
 | |
| // NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported
 | |
| // except for the specific case of function parameters of type `AlphaNum` or
 | |
| // `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a
 | |
| // stack variable is not supported.
 | |
| //
 | |
| // Conversion from 8-bit values is not accepted because, if it were, then an
 | |
| // attempt to pass ':' instead of ":" might result in a 58 ending up in your
 | |
| // result.
 | |
| //
 | |
| // Bools convert to "0" or "1". Pointers to types other than `char *` are not
 | |
| // valid inputs. No output is generated for null `char *` pointers.
 | |
| //
 | |
| // Floating point numbers are formatted with six-digit precision, which is
 | |
| // the default for "std::cout <<" or printf "%g" (the same as "%.6g").
 | |
| //
 | |
| // You can convert to hexadecimal output rather than decimal output using the
 | |
| // `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to
 | |
| // `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using
 | |
| // a `PadSpec` enum.
 | |
| //
 | |
| // -----------------------------------------------------------------------------
 | |
| 
 | |
| #ifndef ABSL_STRINGS_STR_CAT_H_
 | |
| #define ABSL_STRINGS_STR_CAT_H_
 | |
| 
 | |
| #include <array>
 | |
| #include <cstdint>
 | |
| #include <string>
 | |
| #include <type_traits>
 | |
| #include <vector>
 | |
| 
 | |
| #include "absl/base/port.h"
 | |
| #include "absl/strings/numbers.h"
 | |
| #include "absl/strings/string_view.h"
 | |
| 
 | |
| namespace absl {
 | |
| 
 | |
| namespace strings_internal {
 | |
| // AlphaNumBuffer allows a way to pass a string to StrCat without having to do
 | |
| // memory allocation.  It is simply a pair of a fixed-size character array, and
 | |
| // a size.  Please don't use outside of absl, yet.
 | |
| template <size_t max_size>
 | |
| struct AlphaNumBuffer {
 | |
|   std::array<char, max_size> data;
 | |
|   size_t size;
 | |
| };
 | |
| 
 | |
| }  // namespace strings_internal
 | |
| 
 | |
| // Enum that specifies the number of significant digits to return in a `Hex` or
 | |
| // `Dec` conversion and fill character to use. A `kZeroPad2` value, for example,
 | |
| // would produce hexadecimal strings such as "0a","0f" and a 'kSpacePad5' value
 | |
| // would produce hexadecimal strings such as "    a","    f".
 | |
| 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,
 | |
| };
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // Hex
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // `Hex` stores a set of hexadecimal string conversion parameters for use
 | |
| // within `AlphaNum` string conversions.
 | |
| 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(Pointee* v, PadSpec spec = absl::kNoPad)
 | |
|       : Hex(spec, reinterpret_cast<uintptr_t>(v)) {}
 | |
| 
 | |
|  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') {}
 | |
| };
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // Dec
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // `Dec` stores a set of decimal string conversion parameters for use
 | |
| // within `AlphaNum` string conversions.  Dec is slower than the default
 | |
| // integer conversion, so use it only if you need padding.
 | |
| 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) {}
 | |
| };
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // AlphaNum
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // The `AlphaNum` class acts as the main parameter type for `StrCat()` and
 | |
| // `StrAppend()`, providing efficient conversion of numeric, boolean, and
 | |
| // hexadecimal values (through the `Hex` type) into strings.
 | |
| 
 | |
| class AlphaNum {
 | |
|  public:
 | |
|   // No bool ctor -- bools convert to an integral type.
 | |
|   // A bool ctor would also convert incoming pointers (bletch).
 | |
| 
 | |
|   AlphaNum(int x)  // NOLINT(runtime/explicit)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
|   AlphaNum(unsigned int x)  // NOLINT(runtime/explicit)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
|   AlphaNum(long x)  // NOLINT(*)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
|   AlphaNum(unsigned long x)  // NOLINT(*)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
|   AlphaNum(long long x)  // NOLINT(*)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
|   AlphaNum(unsigned long long x)  // NOLINT(*)
 | |
|       : piece_(digits_,
 | |
|                numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {}
 | |
| 
 | |
|   AlphaNum(float f)  // NOLINT(runtime/explicit)
 | |
|       : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
 | |
|   AlphaNum(double f)  // NOLINT(runtime/explicit)
 | |
|       : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {}
 | |
| 
 | |
|   AlphaNum(Hex hex);  // NOLINT(runtime/explicit)
 | |
|   AlphaNum(Dec dec);  // NOLINT(runtime/explicit)
 | |
| 
 | |
|   template <size_t size>
 | |
|   AlphaNum(  // NOLINT(runtime/explicit)
 | |
|       const strings_internal::AlphaNumBuffer<size>& buf)
 | |
|       : piece_(&buf.data[0], buf.size) {}
 | |
| 
 | |
|   AlphaNum(const char* c_str) : piece_(c_str) {}  // NOLINT(runtime/explicit)
 | |
|   AlphaNum(absl::string_view pc) : piece_(pc) {}  // NOLINT(runtime/explicit)
 | |
| 
 | |
|   template <typename Allocator>
 | |
|   AlphaNum(  // NOLINT(runtime/explicit)
 | |
|       const std::basic_string<char, std::char_traits<char>, Allocator>& str)
 | |
|       : piece_(str) {}
 | |
| 
 | |
|   // Use std::string literals ":" instead of character literals ':'.
 | |
|   AlphaNum(char c) = delete;  // NOLINT(runtime/explicit)
 | |
| 
 | |
|   AlphaNum(const AlphaNum&) = delete;
 | |
|   AlphaNum& operator=(const AlphaNum&) = delete;
 | |
| 
 | |
|   absl::string_view::size_type size() const { return piece_.size(); }
 | |
|   const char* data() const { return piece_.data(); }
 | |
|   absl::string_view Piece() const { return piece_; }
 | |
| 
 | |
|   // Normal enums are already handled by the integer formatters.
 | |
|   // This overload matches only scoped enums.
 | |
|   template <typename T,
 | |
|             typename = typename std::enable_if<
 | |
|                 std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type>
 | |
|   AlphaNum(T e)  // NOLINT(runtime/explicit)
 | |
|       : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {}
 | |
| 
 | |
|   // vector<bool>::reference and const_reference require special help to
 | |
|   // convert to `AlphaNum` because it requires two user defined conversions.
 | |
|   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)) {}  // NOLINT(runtime/explicit)
 | |
| 
 | |
|  private:
 | |
|   absl::string_view piece_;
 | |
|   char digits_[numbers_internal::kFastToBufferSize];
 | |
| };
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // StrCat()
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // Merges given strings or numbers, using no delimiter(s), returning the merged
 | |
| // result as a string.
 | |
| //
 | |
| // `StrCat()` is designed to be the fastest possible way to construct a string
 | |
| // out of a mix of raw C strings, string_views, strings, bool values,
 | |
| // and numeric values.
 | |
| //
 | |
| // Don't use `StrCat()` for user-visible strings. The localization process
 | |
| // works poorly on strings built up out of fragments.
 | |
| //
 | |
| // For clarity and performance, don't use `StrCat()` when appending to a
 | |
| // string. Use `StrAppend()` instead. In particular, avoid using any of these
 | |
| // (anti-)patterns:
 | |
| //
 | |
| //   str.append(StrCat(...))
 | |
| //   str += StrCat(...)
 | |
| //   str = StrCat(str, ...)
 | |
| //
 | |
| // The last case is the worst, with a potential to change a loop
 | |
| // from a linear time operation with O(1) dynamic allocations into a
 | |
| // quadratic time operation with O(n) dynamic allocations.
 | |
| //
 | |
| // See `StrAppend()` below for more information.
 | |
| 
 | |
| namespace strings_internal {
 | |
| 
 | |
| // Do not call directly - this is not part of the public API.
 | |
| std::string CatPieces(std::initializer_list<absl::string_view> pieces);
 | |
| void AppendPieces(std::string* dest,
 | |
|                   std::initializer_list<absl::string_view> pieces);
 | |
| 
 | |
| }  // namespace strings_internal
 | |
| 
 | |
| ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); }
 | |
| 
 | |
| 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);
 | |
| 
 | |
| // Support 5 or more arguments
 | |
| 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()...});
 | |
| }
 | |
| 
 | |
| // -----------------------------------------------------------------------------
 | |
| // StrAppend()
 | |
| // -----------------------------------------------------------------------------
 | |
| //
 | |
| // Appends a string or set of strings to an existing string, in a similar
 | |
| // fashion to `StrCat()`.
 | |
| //
 | |
| // WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the
 | |
| // a, b, c, parameters be a reference into str. For speed, `StrAppend()` does
 | |
| // not try to check each of its input arguments to be sure that they are not
 | |
| // a subset of the string being appended to. That is, while this will work:
 | |
| //
 | |
| //   std::string s = "foo";
 | |
| //   s += s;
 | |
| //
 | |
| // This output is undefined:
 | |
| //
 | |
| //   std::string s = "foo";
 | |
| //   StrAppend(&s, s);
 | |
| //
 | |
| // This output is undefined as well, since `absl::string_view` does not own its
 | |
| // data:
 | |
| //
 | |
| //   std::string s = "foobar";
 | |
| //   absl::string_view p = s;
 | |
| //   StrAppend(&s, p);
 | |
| 
 | |
| inline void StrAppend(std::string*) {}
 | |
| void StrAppend(std::string* dest, const AlphaNum& a);
 | |
| void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b);
 | |
| void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
 | |
|                const AlphaNum& c);
 | |
| void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
 | |
|                const AlphaNum& c, const AlphaNum& d);
 | |
| 
 | |
| // Support 5 or more arguments
 | |
| template <typename... AV>
 | |
| inline void StrAppend(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()...});
 | |
| }
 | |
| 
 | |
| // Helper function for the future StrCat default floating-point format, %.6g
 | |
| // This is fast.
 | |
| 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;
 | |
| }
 | |
| 
 | |
| }  // namespace absl
 | |
| 
 | |
| #endif  // ABSL_STRINGS_STR_CAT_H_
 |