Abseil Common Libraries (C++) (grcp 依赖) https://abseil.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
15 KiB

7 years ago
//
// 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
7 years ago
//
// 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`.
7 years ago
// 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".
//
// 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.
7 years ago
//
// -----------------------------------------------------------------------------
#ifndef ABSL_STRINGS_STR_CAT_H_
#define ABSL_STRINGS_STR_CAT_H_
#include <array>
#include <cstdint>
#include <string>
#include <type_traits>
Export of internal Abseil changes. -- 78293ba4eb4981991ae7e6edd25eb9245fcd7515 by Andy Soffer <asoffer@google.com>: internal changes PiperOrigin-RevId: 247073879 -- 7bd97e3aad0c3012b89a39392a6ad3f254e9f3c3 by Derek Mauro <dmauro@google.com>: Release commandline flags PiperOrigin-RevId: 247065920 -- 2a991849fd7b140a43b073076d194b61533fd199 by Tom Manshreck <shreck@google.com>: Add documentation for built-in usage flags PiperOrigin-RevId: 247058863 -- 14157b0de45841706bbd631284191fd94c313db9 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 247058292 -- ed67e0a80468596e30540b367727a250fa415b68 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 246828655 -- e1bc8c2aa3f90b3d56c55c5b7244e718c919265d by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 246822325 -- 907a68f287199f749cb9bdb48571b50bc34731e1 by Eric Fiselier <ericwf@google.com>: Accept vector<bool>::reference in StrCat and friends. Converting vector<bool>::reference to alphanum requires two user defined conversions, which isn't allowed. In order to accept this, we need a special constructor that is only enabled for the bool proxy types. PiperOrigin-RevId: 246626732 -- fe4295fa95cc65dee8c881ba12dd8f516e68c40d by Abseil Team <absl-team@google.com>: Clarify the proper way to define AbslHashValue, and fix confusing indentation. PiperOrigin-RevId: 246406528 -- d7174681a72d4a25c8fd2b4d9f515a0763eff87c by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 246358214 -- a7fdc19683cf1a5885e9e1af52fcdb2db1eda53b by Abseil Team <absl-team@google.com>: Fix sample template instantiation. PiperOrigin-RevId: 246354617 -- 29a23c6835f872948d09b24d890385bf195bc995 by Abseil Team <absl-team@google.com>: Fix incorrectly copy-pasted static_assert in absl::optional::value_or The static_assert for a move-constructible type previously said the type must be copy-constructible. PiperOrigin-RevId: 246313827 -- 41884d5872d4ea2c67875b00144b8c8a5859a295 by Greg Falcon <gfalcon@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 245418790 -- 7f90a7f94cdd5e21232c749efe952a750b5c43a2 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 245412658 -- 730a329cf047d54b46971fce1781edd857208c2a by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 245293234 -- cf0216be6338200cbb18167d3f3b2e98e372be77 by Greg Falcon <gfalcon@google.com>: Internal change PiperOrigin-RevId: 245288164 GitOrigin-RevId: 78293ba4eb4981991ae7e6edd25eb9245fcd7515 Change-Id: I5ea9a852c36c722bae2d6be65fb7f72473d94ab6
6 years ago
#include <vector>
7 years ago
#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
7 years ago
// 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 {
7 years ago
kNoPad = 1,
kZeroPad2,
kZeroPad3,
kZeroPad4,
kZeroPad5,
kZeroPad6,
kZeroPad7,
kZeroPad8,
kZeroPad9,
kZeroPad10,
kZeroPad11,
kZeroPad12,
kZeroPad13,
kZeroPad14,
kZeroPad15,
kZeroPad16,
kZeroPad17,
kZeroPad18,
kZeroPad19,
kZeroPad20,
7 years ago
kSpacePad2 = kZeroPad2 + 64,
kSpacePad3,
kSpacePad4,
kSpacePad5,
kSpacePad6,
kSpacePad7,
kSpacePad8,
kSpacePad9,
kSpacePad10,
kSpacePad11,
kSpacePad12,
kSpacePad13,
kSpacePad14,
kSpacePad15,
kSpacePad16,
kSpacePad17,
kSpacePad18,
kSpacePad19,
kSpacePad20,
7 years ago
};
// -----------------------------------------------------------------------------
// Hex
// -----------------------------------------------------------------------------
//
// `Hex` stores a set of hexadecimal string conversion parameters for use
// within `AlphaNum` string conversions.
7 years ago
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)
7 years ago
: 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)
7 years ago
: 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)
7 years ago
: 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)
7 years ago
: 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)) {}
7 years ago
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) {}
};
7 years ago
// -----------------------------------------------------------------------------
// 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)
7 years ago
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)
7 years ago
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)) {}
Export of internal Abseil changes. -- 78293ba4eb4981991ae7e6edd25eb9245fcd7515 by Andy Soffer <asoffer@google.com>: internal changes PiperOrigin-RevId: 247073879 -- 7bd97e3aad0c3012b89a39392a6ad3f254e9f3c3 by Derek Mauro <dmauro@google.com>: Release commandline flags PiperOrigin-RevId: 247065920 -- 2a991849fd7b140a43b073076d194b61533fd199 by Tom Manshreck <shreck@google.com>: Add documentation for built-in usage flags PiperOrigin-RevId: 247058863 -- 14157b0de45841706bbd631284191fd94c313db9 by Derek Mauro <dmauro@google.com>: Internal change PiperOrigin-RevId: 247058292 -- ed67e0a80468596e30540b367727a250fa415b68 by Abseil Team <absl-team@google.com>: Internal Change. PiperOrigin-RevId: 246828655 -- e1bc8c2aa3f90b3d56c55c5b7244e718c919265d by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 246822325 -- 907a68f287199f749cb9bdb48571b50bc34731e1 by Eric Fiselier <ericwf@google.com>: Accept vector<bool>::reference in StrCat and friends. Converting vector<bool>::reference to alphanum requires two user defined conversions, which isn't allowed. In order to accept this, we need a special constructor that is only enabled for the bool proxy types. PiperOrigin-RevId: 246626732 -- fe4295fa95cc65dee8c881ba12dd8f516e68c40d by Abseil Team <absl-team@google.com>: Clarify the proper way to define AbslHashValue, and fix confusing indentation. PiperOrigin-RevId: 246406528 -- d7174681a72d4a25c8fd2b4d9f515a0763eff87c by Gennadiy Rozental <rogeeff@google.com>: Internal change PiperOrigin-RevId: 246358214 -- a7fdc19683cf1a5885e9e1af52fcdb2db1eda53b by Abseil Team <absl-team@google.com>: Fix sample template instantiation. PiperOrigin-RevId: 246354617 -- 29a23c6835f872948d09b24d890385bf195bc995 by Abseil Team <absl-team@google.com>: Fix incorrectly copy-pasted static_assert in absl::optional::value_or The static_assert for a move-constructible type previously said the type must be copy-constructible. PiperOrigin-RevId: 246313827 -- 41884d5872d4ea2c67875b00144b8c8a5859a295 by Greg Falcon <gfalcon@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 245418790 -- 7f90a7f94cdd5e21232c749efe952a750b5c43a2 by Abseil Team <absl-team@google.com>: Internal change PiperOrigin-RevId: 245412658 -- 730a329cf047d54b46971fce1781edd857208c2a by Greg Falcon <gfalcon@google.com>: internal change PiperOrigin-RevId: 245293234 -- cf0216be6338200cbb18167d3f3b2e98e372be77 by Greg Falcon <gfalcon@google.com>: Internal change PiperOrigin-RevId: 245288164 GitOrigin-RevId: 78293ba4eb4981991ae7e6edd25eb9245fcd7515 Change-Id: I5ea9a852c36c722bae2d6be65fb7f72473d94ab6
6 years ago
// 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)
7 years ago
private:
absl::string_view piece_;
char digits_[numbers_internal::kFastToBufferSize];
};
// -----------------------------------------------------------------------------
// StrCat()
// -----------------------------------------------------------------------------
//
// Merges given strings or numbers, using no delimiter(s).
//
// `StrCat()` is designed to be the fastest possible way to construct a string
7 years ago
// 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
7 years ago
// (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);
7 years ago
ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b,
const AlphaNum& c, const AlphaNum& d);
7 years ago
// 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) {
7 years ago
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
7 years ago
// 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:
7 years ago
//
// std::string s = "foo";
7 years ago
// s += s;
//
// This output is undefined:
//
// std::string s = "foo";
7 years ago
// StrAppend(&s, s);
//
// This output is undefined as well, since `absl::string_view` does not own its
// data:
//
// std::string s = "foobar";
7 years ago
// 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_