tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

str_cat.cc (8886B)


      1 // Copyright 2017 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/strings/str_cat.h"
     16 
     17 #include <assert.h>
     18 
     19 #include <cstddef>
     20 #include <cstdint>
     21 #include <cstring>
     22 #include <initializer_list>
     23 #include <limits>
     24 #include <string>
     25 
     26 #include "absl/base/config.h"
     27 #include "absl/base/internal/raw_logging.h"
     28 #include "absl/base/nullability.h"
     29 #include "absl/strings/internal/resize_uninitialized.h"
     30 #include "absl/strings/string_view.h"
     31 
     32 namespace absl {
     33 ABSL_NAMESPACE_BEGIN
     34 
     35 // ----------------------------------------------------------------------
     36 // StrCat()
     37 //    This merges the given strings or integers, with no delimiter. This
     38 //    is designed to be the fastest possible way to construct a string out
     39 //    of a mix of raw C strings, string_views, strings, and integer values.
     40 // ----------------------------------------------------------------------
     41 
     42 namespace {
     43 // Append is merely a version of memcpy that returns the address of the byte
     44 // after the area just overwritten.
     45 inline absl::Nonnull<char*> Append(absl::Nonnull<char*> out,
     46                                   const AlphaNum& x) {
     47  // memcpy is allowed to overwrite arbitrary memory, so doing this after the
     48  // call would force an extra fetch of x.size().
     49  char* after = out + x.size();
     50  if (x.size() != 0) {
     51    memcpy(out, x.data(), x.size());
     52  }
     53  return after;
     54 }
     55 
     56 inline void STLStringAppendUninitializedAmortized(std::string* dest,
     57                                                  size_t to_append) {
     58  strings_internal::AppendUninitializedTraits<std::string>::Append(dest,
     59                                                                   to_append);
     60 }
     61 }  // namespace
     62 
     63 std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
     64  std::string result;
     65  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
     66  // in memory strings to overflow a uint64_t.
     67  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
     68  const uint64_t result_size =
     69      static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
     70  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
     71  absl::strings_internal::STLStringResizeUninitialized(
     72      &result, static_cast<size_t>(result_size));
     73  char* const begin = &result[0];
     74  char* out = begin;
     75  out = Append(out, a);
     76  out = Append(out, b);
     77  assert(out == begin + result.size());
     78  return result;
     79 }
     80 
     81 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
     82  std::string result;
     83  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
     84  // in memory strings to overflow a uint64_t.
     85  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
     86  const uint64_t result_size = static_cast<uint64_t>(a.size()) +
     87                               static_cast<uint64_t>(b.size()) +
     88                               static_cast<uint64_t>(c.size());
     89  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
     90  strings_internal::STLStringResizeUninitialized(
     91      &result, static_cast<size_t>(result_size));
     92  char* const begin = &result[0];
     93  char* out = begin;
     94  out = Append(out, a);
     95  out = Append(out, b);
     96  out = Append(out, c);
     97  assert(out == begin + result.size());
     98  return result;
     99 }
    100 
    101 std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
    102                   const AlphaNum& d) {
    103  std::string result;
    104  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
    105  // in memory strings to overflow a uint64_t.
    106  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
    107  const uint64_t result_size = static_cast<uint64_t>(a.size()) +
    108                               static_cast<uint64_t>(b.size()) +
    109                               static_cast<uint64_t>(c.size()) +
    110                               static_cast<uint64_t>(d.size());
    111  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
    112  strings_internal::STLStringResizeUninitialized(
    113      &result, static_cast<size_t>(result_size));
    114  char* const begin = &result[0];
    115  char* out = begin;
    116  out = Append(out, a);
    117  out = Append(out, b);
    118  out = Append(out, c);
    119  out = Append(out, d);
    120  assert(out == begin + result.size());
    121  return result;
    122 }
    123 
    124 namespace strings_internal {
    125 
    126 // Do not call directly - these are not part of the public API.
    127 std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
    128  std::string result;
    129  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
    130  // in memory strings to overflow a uint64_t.
    131  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
    132  uint64_t total_size = 0;
    133  for (absl::string_view piece : pieces) {
    134    total_size += piece.size();
    135  }
    136  ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
    137  strings_internal::STLStringResizeUninitialized(
    138      &result, static_cast<size_t>(total_size));
    139 
    140  char* const begin = &result[0];
    141  char* out = begin;
    142  for (absl::string_view piece : pieces) {
    143    const size_t this_size = piece.size();
    144    if (this_size != 0) {
    145      memcpy(out, piece.data(), this_size);
    146      out += this_size;
    147    }
    148  }
    149  assert(out == begin + result.size());
    150  return result;
    151 }
    152 
    153 // It's possible to call StrAppend with an absl::string_view that is itself a
    154 // fragment of the string we're appending to.  However the results of this are
    155 // random. Therefore, check for this in debug mode.  Use unsigned math so we
    156 // only have to do one comparison. Note, there's an exception case: appending an
    157 // empty string is always allowed.
    158 #define ASSERT_NO_OVERLAP(dest, src) \
    159  assert(((src).size() == 0) ||      \
    160         (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
    161 
    162 void AppendPieces(absl::Nonnull<std::string*> dest,
    163                  std::initializer_list<absl::string_view> pieces) {
    164  size_t old_size = dest->size();
    165  size_t to_append = 0;
    166  for (absl::string_view piece : pieces) {
    167    ASSERT_NO_OVERLAP(*dest, piece);
    168    to_append += piece.size();
    169  }
    170  STLStringAppendUninitializedAmortized(dest, to_append);
    171 
    172  char* const begin = &(*dest)[0];
    173  char* out = begin + old_size;
    174  for (absl::string_view piece : pieces) {
    175    const size_t this_size = piece.size();
    176    if (this_size != 0) {
    177      memcpy(out, piece.data(), this_size);
    178      out += this_size;
    179    }
    180  }
    181  assert(out == begin + dest->size());
    182 }
    183 
    184 }  // namespace strings_internal
    185 
    186 void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a) {
    187  ASSERT_NO_OVERLAP(*dest, a);
    188  std::string::size_type old_size = dest->size();
    189  STLStringAppendUninitializedAmortized(dest, a.size());
    190  char* const begin = &(*dest)[0];
    191  char* out = begin + old_size;
    192  out = Append(out, a);
    193  assert(out == begin + dest->size());
    194 }
    195 
    196 void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
    197               const AlphaNum& b) {
    198  ASSERT_NO_OVERLAP(*dest, a);
    199  ASSERT_NO_OVERLAP(*dest, b);
    200  std::string::size_type old_size = dest->size();
    201  STLStringAppendUninitializedAmortized(dest, a.size() + b.size());
    202  char* const begin = &(*dest)[0];
    203  char* out = begin + old_size;
    204  out = Append(out, a);
    205  out = Append(out, b);
    206  assert(out == begin + dest->size());
    207 }
    208 
    209 void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
    210               const AlphaNum& b, const AlphaNum& c) {
    211  ASSERT_NO_OVERLAP(*dest, a);
    212  ASSERT_NO_OVERLAP(*dest, b);
    213  ASSERT_NO_OVERLAP(*dest, c);
    214  std::string::size_type old_size = dest->size();
    215  STLStringAppendUninitializedAmortized(dest, a.size() + b.size() + c.size());
    216  char* const begin = &(*dest)[0];
    217  char* out = begin + old_size;
    218  out = Append(out, a);
    219  out = Append(out, b);
    220  out = Append(out, c);
    221  assert(out == begin + dest->size());
    222 }
    223 
    224 void StrAppend(absl::Nonnull<std::string*> dest, const AlphaNum& a,
    225               const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
    226  ASSERT_NO_OVERLAP(*dest, a);
    227  ASSERT_NO_OVERLAP(*dest, b);
    228  ASSERT_NO_OVERLAP(*dest, c);
    229  ASSERT_NO_OVERLAP(*dest, d);
    230  std::string::size_type old_size = dest->size();
    231  STLStringAppendUninitializedAmortized(
    232      dest, a.size() + b.size() + c.size() + d.size());
    233  char* const begin = &(*dest)[0];
    234  char* out = begin + old_size;
    235  out = Append(out, a);
    236  out = Append(out, b);
    237  out = Append(out, c);
    238  out = Append(out, d);
    239  assert(out == begin + dest->size());
    240 }
    241 
    242 ABSL_NAMESPACE_END
    243 }  // namespace absl