Coverage Report

Created: 2025-11-15 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/strings/str_cat.cc
Line
Count
Source
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/append_and_overwrite.h"
30
#include "absl/strings/resize_and_overwrite.h"
31
#include "absl/strings/string_view.h"
32
33
namespace absl {
34
ABSL_NAMESPACE_BEGIN
35
36
// ----------------------------------------------------------------------
37
// StrCat()
38
//    This merges the given strings or integers, with no delimiter. This
39
//    is designed to be the fastest possible way to construct a string out
40
//    of a mix of raw C strings, string_views, strings, and integer values.
41
// ----------------------------------------------------------------------
42
43
namespace {
44
// Append is merely a version of memcpy that returns the address of the byte
45
// after the area just overwritten.
46
0
inline char* absl_nonnull Append(char* absl_nonnull out, 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
0
  char* after = out + x.size();
50
0
  if (x.size() != 0) {
51
0
    memcpy(out, x.data(), x.size());
52
0
  }
53
0
  return after;
54
0
}
55
56
}  // namespace
57
58
0
std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
59
0
  std::string result;
60
  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
61
  // in memory strings to overflow a uint64_t.
62
0
  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
63
0
  const uint64_t result_size =
64
0
      static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
65
0
  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
66
0
  absl::StringResizeAndOverwrite(result, static_cast<size_t>(result_size),
67
0
                                 [&a, &b](char* const begin, size_t buf_size) {
68
0
                                   char* out = begin;
69
0
                                   out = Append(out, a);
70
0
                                   out = Append(out, b);
71
0
                                   assert(out == begin + buf_size);
72
0
                                   return buf_size;
73
0
                                 });
74
0
  return result;
75
0
}
76
77
0
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
78
0
  std::string result;
79
  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
80
  // in memory strings to overflow a uint64_t.
81
0
  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
82
0
  const uint64_t result_size = static_cast<uint64_t>(a.size()) +
83
0
                               static_cast<uint64_t>(b.size()) +
84
0
                               static_cast<uint64_t>(c.size());
85
0
  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
86
0
  absl::StringResizeAndOverwrite(
87
0
      result, static_cast<size_t>(result_size),
88
0
      [&a, &b, &c](char* const begin, size_t buf_size) {
89
0
        char* out = begin;
90
0
        out = Append(out, a);
91
0
        out = Append(out, b);
92
0
        out = Append(out, c);
93
0
        assert(out == begin + buf_size);
94
0
        return buf_size;
95
0
      });
96
0
  return result;
97
0
}
98
99
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
100
0
                   const AlphaNum& d) {
101
0
  std::string result;
102
  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
103
  // in memory strings to overflow a uint64_t.
104
0
  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
105
0
  const uint64_t result_size =
106
0
      static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size()) +
107
0
      static_cast<uint64_t>(c.size()) + static_cast<uint64_t>(d.size());
108
0
  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
109
0
  absl::StringResizeAndOverwrite(
110
0
      result, static_cast<size_t>(result_size),
111
0
      [&a, &b, &c, &d](char* const begin, size_t buf_size) {
112
0
        char* out = begin;
113
0
        out = Append(out, a);
114
0
        out = Append(out, b);
115
0
        out = Append(out, c);
116
0
        out = Append(out, d);
117
0
        assert(out == begin + buf_size);
118
0
        return buf_size;
119
0
      });
120
0
  return result;
121
0
}
122
123
namespace strings_internal {
124
125
// Do not call directly - these are not part of the public API.
126
0
std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
127
0
  std::string result;
128
  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
129
  // in memory strings to overflow a uint64_t.
130
0
  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
131
0
  uint64_t total_size = 0;
132
0
  for (absl::string_view piece : pieces) {
133
0
    total_size += piece.size();
134
0
  }
135
0
  ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
136
0
  absl::StringResizeAndOverwrite(result, static_cast<size_t>(total_size),
137
0
                                 [&pieces](char* const begin, size_t buf_size) {
138
0
                                   char* out = begin;
139
0
                                   for (absl::string_view piece : pieces) {
140
0
                                     const size_t this_size = piece.size();
141
0
                                     if (this_size != 0) {
142
0
                                       memcpy(out, piece.data(), this_size);
143
0
                                       out += this_size;
144
0
                                     }
145
0
                                   }
146
0
                                   assert(out == begin + buf_size);
147
0
                                   return buf_size;
148
0
                                 });
149
0
  return result;
150
0
}
151
152
// It's possible to call StrAppend with an absl::string_view that is itself a
153
// fragment of the string we're appending to.  However the results of this are
154
// random. Therefore, check for this in debug mode.  Use unsigned math so we
155
// only have to do one comparison. Note, there's an exception case: appending an
156
// empty string is always allowed.
157
#define ASSERT_NO_OVERLAP(dest, src) \
158
0
  assert(((src).size() == 0) ||      \
159
0
         (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size())))
160
161
void AppendPieces(std::string* absl_nonnull dest,
162
0
                  std::initializer_list<absl::string_view> pieces) {
163
0
  size_t to_append = 0;
164
0
  for (absl::string_view piece : pieces) {
165
0
    ASSERT_NO_OVERLAP(*dest, piece);
166
0
    to_append += piece.size();
167
0
  }
168
0
  StringAppendAndOverwrite(*dest, to_append,
169
0
                           [&pieces](char* const buf, size_t buf_size) {
170
0
                             char* out = buf;
171
0
                             for (absl::string_view piece : pieces) {
172
0
                               const size_t this_size = piece.size();
173
0
                               if (this_size != 0) {
174
0
                                 memcpy(out, piece.data(), this_size);
175
0
                                 out += this_size;
176
0
                               }
177
0
                             }
178
0
                             assert(out == buf + buf_size);
179
0
                             return buf_size;
180
0
                           });
181
0
}
182
183
}  // namespace strings_internal
184
185
0
void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a) {
186
0
  ASSERT_NO_OVERLAP(*dest, a);
187
0
  strings_internal::StringAppendAndOverwrite(
188
0
      *dest, a.size(), [&a](char* const buf, size_t buf_size) {
189
0
        char* out = buf;
190
0
        out = Append(out, a);
191
0
        assert(out == buf + buf_size);
192
0
        return buf_size;
193
0
      });
194
0
}
195
196
void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
197
0
               const AlphaNum& b) {
198
0
  ASSERT_NO_OVERLAP(*dest, a);
199
0
  ASSERT_NO_OVERLAP(*dest, b);
200
0
  strings_internal::StringAppendAndOverwrite(
201
0
      *dest, a.size() + b.size(), [&a, &b](char* const buf, size_t buf_size) {
202
0
        char* out = buf;
203
0
        out = Append(out, a);
204
0
        out = Append(out, b);
205
0
        assert(out == buf + buf_size);
206
0
        return buf_size;
207
0
      });
208
0
}
209
210
void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
211
0
               const AlphaNum& b, const AlphaNum& c) {
212
0
  ASSERT_NO_OVERLAP(*dest, a);
213
0
  ASSERT_NO_OVERLAP(*dest, b);
214
0
  ASSERT_NO_OVERLAP(*dest, c);
215
0
  strings_internal::StringAppendAndOverwrite(
216
0
      *dest, a.size() + b.size() + c.size(),
217
0
      [&a, &b, &c](char* const buf, size_t buf_size) {
218
0
        char* out = buf;
219
0
        out = Append(out, a);
220
0
        out = Append(out, b);
221
0
        out = Append(out, c);
222
0
        assert(out == buf + buf_size);
223
0
        return buf_size;
224
0
      });
225
0
}
226
227
void StrAppend(std::string* absl_nonnull dest, const AlphaNum& a,
228
0
               const AlphaNum& b, const AlphaNum& c, const AlphaNum& d) {
229
0
  ASSERT_NO_OVERLAP(*dest, a);
230
0
  ASSERT_NO_OVERLAP(*dest, b);
231
0
  ASSERT_NO_OVERLAP(*dest, c);
232
0
  ASSERT_NO_OVERLAP(*dest, d);
233
0
  strings_internal::StringAppendAndOverwrite(
234
0
      *dest, a.size() + b.size() + c.size() + d.size(),
235
0
      [&a, &b, &c, &d](char* const buf, size_t buf_size) {
236
0
        char* out = buf;
237
0
        out = Append(out, a);
238
0
        out = Append(out, b);
239
0
        out = Append(out, c);
240
0
        out = Append(out, d);
241
0
        assert(out == buf + buf_size);
242
0
        return buf_size;
243
0
      });
244
0
}
245
246
ABSL_NAMESPACE_END
247
}  // namespace absl