| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 | // 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////      http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.#include "absl/strings/str_cat.h"#include <assert.h>#include <algorithm>#include <cstdint>#include <cstring>#include "absl/strings/ascii.h"#include "absl/strings/internal/resize_uninitialized.h"namespace absl {AlphaNum::AlphaNum(Hex hex) {  char* const end = &digits_[numbers_internal::kFastToBufferSize];  char* writer = end;  uint64_t value = hex.value;  static const char hexdigits[] = "0123456789abcdef";  do {    *--writer = hexdigits[value & 0xF];    value >>= 4;  } while (value != 0);  char* beg;  if (end - writer < hex.width) {    beg = end - hex.width;    std::fill_n(beg, writer - beg, hex.fill);  } else {    beg = writer;  }  piece_ = absl::string_view(beg, end - beg);}// ----------------------------------------------------------------------// StrCat()//    This merges the given strings or integers, with no delimiter.  This//    is designed to be the fastest possible way to construct a std::string out//    of a mix of raw C strings, StringPieces, strings, and integer values.// ----------------------------------------------------------------------// Append is merely a version of memcpy that returns the address of the byte// after the area just overwritten.static char* Append(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();  memcpy(out, x.data(), x.size());  return after;}std::string StrCat(const AlphaNum& a, const AlphaNum& b) {  std::string result;  absl::strings_internal::STLStringResizeUninitialized(&result,                                                       a.size() + b.size());  char* const begin = &*result.begin();  char* out = begin;  out = Append(out, a);  out = Append(out, b);  assert(out == begin + result.size());  return result;}std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {  std::string result;  strings_internal::STLStringResizeUninitialized(      &result, a.size() + b.size() + c.size());  char* const begin = &*result.begin();  char* out = begin;  out = Append(out, a);  out = Append(out, b);  out = Append(out, c);  assert(out == begin + result.size());  return result;}std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,              const AlphaNum& d) {  std::string result;  strings_internal::STLStringResizeUninitialized(      &result, a.size() + b.size() + c.size() + d.size());  char* const begin = &*result.begin();  char* out = begin;  out = Append(out, a);  out = Append(out, b);  out = Append(out, c);  out = Append(out, d);  assert(out == begin + result.size());  return result;}namespace strings_internal {// Do not call directly - these are not part of the public API.std::string CatPieces(std::initializer_list<absl::string_view> pieces) {  std::string result;  size_t total_size = 0;  for (const absl::string_view piece : pieces) total_size += piece.size();  strings_internal::STLStringResizeUninitialized(&result, total_size);  char* const begin = &*result.begin();  char* out = begin;  for (const absl::string_view piece : pieces) {    const size_t this_size = piece.size();    memcpy(out, piece.data(), this_size);    out += this_size;  }  assert(out == begin + result.size());  return result;}// It's possible to call StrAppend with an absl::string_view that is itself a// fragment of the std::string we're appending to.  However the results of this are// random. Therefore, check for this in debug mode.  Use unsigned math so we// only have to do one comparison. Note, there's an exception case: appending an// empty std::string is always allowed.#define ASSERT_NO_OVERLAP(dest, src) \  assert(((src).size() == 0) ||      \         (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))void AppendPieces(std::string* dest,                  std::initializer_list<absl::string_view> pieces) {  size_t old_size = dest->size();  size_t total_size = old_size;  for (const absl::string_view piece : pieces) {    ASSERT_NO_OVERLAP(*dest, piece);    total_size += piece.size();  }  strings_internal::STLStringResizeUninitialized(dest, total_size);  char* const begin = &*dest->begin();  char* out = begin + old_size;  for (const absl::string_view piece : pieces) {    const size_t this_size = piece.size();    memcpy(out, piece.data(), this_size);    out += this_size;  }  assert(out == begin + dest->size());}}  // namespace strings_internalvoid StrAppend(std::string* dest, const AlphaNum& a) {  ASSERT_NO_OVERLAP(*dest, a);  dest->append(a.data(), a.size());}void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {  ASSERT_NO_OVERLAP(*dest, a);  ASSERT_NO_OVERLAP(*dest, b);  std::string::size_type old_size = dest->size();  strings_internal::STLStringResizeUninitialized(      dest, old_size + a.size() + b.size());  char* const begin = &*dest->begin();  char* out = begin + old_size;  out = Append(out, a);  out = Append(out, b);  assert(out == begin + dest->size());}void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,               const AlphaNum& c) {  ASSERT_NO_OVERLAP(*dest, a);  ASSERT_NO_OVERLAP(*dest, b);  ASSERT_NO_OVERLAP(*dest, c);  std::string::size_type old_size = dest->size();  strings_internal::STLStringResizeUninitialized(      dest, old_size + a.size() + b.size() + c.size());  char* const begin = &*dest->begin();  char* out = begin + old_size;  out = Append(out, a);  out = Append(out, b);  out = Append(out, c);  assert(out == begin + dest->size());}void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,               const AlphaNum& c, const AlphaNum& d) {  ASSERT_NO_OVERLAP(*dest, a);  ASSERT_NO_OVERLAP(*dest, b);  ASSERT_NO_OVERLAP(*dest, c);  ASSERT_NO_OVERLAP(*dest, d);  std::string::size_type old_size = dest->size();  strings_internal::STLStringResizeUninitialized(      dest, old_size + a.size() + b.size() + c.size() + d.size());  char* const begin = &*dest->begin();  char* out = begin + old_size;  out = Append(out, a);  out = Append(out, b);  out = Append(out, c);  out = Append(out, d);  assert(out == begin + dest->size());}}  // namespace absl
 |