str_cat.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "absl/strings/str_cat.h"
00016 
00017 #include <assert.h>
00018 #include <algorithm>
00019 #include <cstdint>
00020 #include <cstring>
00021 
00022 #include "absl/strings/ascii.h"
00023 #include "absl/strings/internal/resize_uninitialized.h"
00024 
00025 namespace absl {
00026 
00027 AlphaNum::AlphaNum(Hex hex) {
00028   char* const end = &digits_[numbers_internal::kFastToBufferSize];
00029   char* writer = end;
00030   uint64_t value = hex.value;
00031   static const char hexdigits[] = "0123456789abcdef";
00032   do {
00033     *--writer = hexdigits[value & 0xF];
00034     value >>= 4;
00035   } while (value != 0);
00036 
00037   char* beg;
00038   if (end - writer < hex.width) {
00039     beg = end - hex.width;
00040     std::fill_n(beg, writer - beg, hex.fill);
00041   } else {
00042     beg = writer;
00043   }
00044 
00045   piece_ = absl::string_view(beg, end - beg);
00046 }
00047 
00048 AlphaNum::AlphaNum(Dec dec) {
00049   assert(dec.width <= numbers_internal::kFastToBufferSize);
00050   char* const end = &digits_[numbers_internal::kFastToBufferSize];
00051   char* const minfill = end - dec.width;
00052   char* writer = end;
00053   uint64_t value = dec.value;
00054   bool neg = dec.neg;
00055   while (value > 9) {
00056     *--writer = '0' + (value % 10);
00057     value /= 10;
00058   }
00059   *--writer = '0' + value;
00060   if (neg) *--writer = '-';
00061 
00062   ptrdiff_t fillers = writer - minfill;
00063   if (fillers > 0) {
00064     // Tricky: if the fill character is ' ', then it's <fill><+/-><digits>
00065     // But...: if the fill character is '0', then it's <+/-><fill><digits>
00066     bool add_sign_again = false;
00067     if (neg && dec.fill == '0') {  // If filling with '0',
00068       ++writer;                    // ignore the sign we just added
00069       add_sign_again = true;       // and re-add the sign later.
00070     }
00071     writer -= fillers;
00072     std::fill_n(writer, fillers, dec.fill);
00073     if (add_sign_again) *--writer = '-';
00074   }
00075 
00076   piece_ = absl::string_view(writer, end - writer);
00077 }
00078 
00079 // ----------------------------------------------------------------------
00080 // StrCat()
00081 //    This merges the given strings or integers, with no delimiter. This
00082 //    is designed to be the fastest possible way to construct a string out
00083 //    of a mix of raw C strings, string_views, strings, and integer values.
00084 // ----------------------------------------------------------------------
00085 
00086 // Append is merely a version of memcpy that returns the address of the byte
00087 // after the area just overwritten.
00088 static char* Append(char* out, const AlphaNum& x) {
00089   // memcpy is allowed to overwrite arbitrary memory, so doing this after the
00090   // call would force an extra fetch of x.size().
00091   char* after = out + x.size();
00092   if (x.size() != 0) {
00093     memcpy(out, x.data(), x.size());
00094   }
00095   return after;
00096 }
00097 
00098 std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
00099   std::string result;
00100   absl::strings_internal::STLStringResizeUninitialized(&result,
00101                                                        a.size() + b.size());
00102   char* const begin = &*result.begin();
00103   char* out = begin;
00104   out = Append(out, a);
00105   out = Append(out, b);
00106   assert(out == begin + result.size());
00107   return result;
00108 }
00109 
00110 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
00111   std::string result;
00112   strings_internal::STLStringResizeUninitialized(
00113       &result, a.size() + b.size() + c.size());
00114   char* const begin = &*result.begin();
00115   char* out = begin;
00116   out = Append(out, a);
00117   out = Append(out, b);
00118   out = Append(out, c);
00119   assert(out == begin + result.size());
00120   return result;
00121 }
00122 
00123 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
00124                    const AlphaNum& d) {
00125   std::string result;
00126   strings_internal::STLStringResizeUninitialized(
00127       &result, a.size() + b.size() + c.size() + d.size());
00128   char* const begin = &*result.begin();
00129   char* out = begin;
00130   out = Append(out, a);
00131   out = Append(out, b);
00132   out = Append(out, c);
00133   out = Append(out, d);
00134   assert(out == begin + result.size());
00135   return result;
00136 }
00137 
00138 namespace strings_internal {
00139 
00140 // Do not call directly - these are not part of the public API.
00141 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
00142   std::string result;
00143   size_t total_size = 0;
00144   for (const absl::string_view piece : pieces) total_size += piece.size();
00145   strings_internal::STLStringResizeUninitialized(&result, total_size);
00146 
00147   char* const begin = &*result.begin();
00148   char* out = begin;
00149   for (const absl::string_view piece : pieces) {
00150     const size_t this_size = piece.size();
00151     if (this_size != 0) {
00152       memcpy(out, piece.data(), this_size);
00153       out += this_size;
00154     }
00155   }
00156   assert(out == begin + result.size());
00157   return result;
00158 }
00159 
00160 // It's possible to call StrAppend with an absl::string_view that is itself a
00161 // fragment of the string we're appending to.  However the results of this are
00162 // random. Therefore, check for this in debug mode.  Use unsigned math so we
00163 // only have to do one comparison. Note, there's an exception case: appending an
00164 // empty string is always allowed.
00165 #define ASSERT_NO_OVERLAP(dest, src) \
00166   assert(((src).size() == 0) ||      \
00167          (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
00168 
00169 void AppendPieces(std::string* dest,
00170                   std::initializer_list<absl::string_view> pieces) {
00171   size_t old_size = dest->size();
00172   size_t total_size = old_size;
00173   for (const absl::string_view piece : pieces) {
00174     ASSERT_NO_OVERLAP(*dest, piece);
00175     total_size += piece.size();
00176   }
00177   strings_internal::STLStringResizeUninitialized(dest, total_size);
00178 
00179   char* const begin = &*dest->begin();
00180   char* out = begin + old_size;
00181   for (const absl::string_view piece : pieces) {
00182     const size_t this_size = piece.size();
00183     if (this_size != 0) {
00184       memcpy(out, piece.data(), this_size);
00185       out += this_size;
00186     }
00187   }
00188   assert(out == begin + dest->size());
00189 }
00190 
00191 }  // namespace strings_internal
00192 
00193 void StrAppend(std::string* dest, const AlphaNum& a) {
00194   ASSERT_NO_OVERLAP(*dest, a);
00195   dest->append(a.data(), a.size());
00196 }
00197 
00198 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) {
00199   ASSERT_NO_OVERLAP(*dest, a);
00200   ASSERT_NO_OVERLAP(*dest, b);
00201   std::string::size_type old_size = dest->size();
00202   strings_internal::STLStringResizeUninitialized(
00203       dest, old_size + a.size() + b.size());
00204   char* const begin = &*dest->begin();
00205   char* out = begin + old_size;
00206   out = Append(out, a);
00207   out = Append(out, b);
00208   assert(out == begin + dest->size());
00209 }
00210 
00211 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
00212                const AlphaNum& c) {
00213   ASSERT_NO_OVERLAP(*dest, a);
00214   ASSERT_NO_OVERLAP(*dest, b);
00215   ASSERT_NO_OVERLAP(*dest, c);
00216   std::string::size_type old_size = dest->size();
00217   strings_internal::STLStringResizeUninitialized(
00218       dest, old_size + a.size() + b.size() + c.size());
00219   char* const begin = &*dest->begin();
00220   char* out = begin + old_size;
00221   out = Append(out, a);
00222   out = Append(out, b);
00223   out = Append(out, c);
00224   assert(out == begin + dest->size());
00225 }
00226 
00227 void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b,
00228                const AlphaNum& c, const AlphaNum& d) {
00229   ASSERT_NO_OVERLAP(*dest, a);
00230   ASSERT_NO_OVERLAP(*dest, b);
00231   ASSERT_NO_OVERLAP(*dest, c);
00232   ASSERT_NO_OVERLAP(*dest, d);
00233   std::string::size_type old_size = dest->size();
00234   strings_internal::STLStringResizeUninitialized(
00235       dest, old_size + a.size() + b.size() + c.size() + d.size());
00236   char* const begin = &*dest->begin();
00237   char* out = begin + old_size;
00238   out = Append(out, a);
00239   out = Append(out, b);
00240   out = Append(out, c);
00241   out = Append(out, d);
00242   assert(out == begin + dest->size());
00243 }
00244 
00245 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15