1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_STRINGS_STRCAT_H_
6 #define BASE_STRINGS_STRCAT_H_
7 
8 #include <initializer_list>
9 
10 #include "base/base_export.h"
11 #include "base/compiler_specific.h"
12 #include "base/containers/span.h"
13 #include "base/strings/string_piece.h"
14 #include "build/build_config.h"
15 
16 #if defined(OS_WIN)
17 // Guard against conflict with Win32 API StrCat macro:
18 // check StrCat wasn't and will not be redefined.
19 #define StrCat StrCat
20 #endif
21 
22 namespace base {
23 
24 // StrCat ----------------------------------------------------------------------
25 //
26 // StrCat is a function to perform concatenation on a sequence of strings.
27 // It is preferrable to a sequence of "a + b + c" because it is both faster and
28 // generates less code.
29 //
30 //   std::string result = base::StrCat({"foo ", result, "\nfoo ", bar});
31 //
32 // To join an array of strings with a separator, see base::JoinString in
33 // base/strings/string_util.h.
34 //
35 // MORE INFO
36 //
37 // StrCat can see all arguments at once, so it can allocate one return buffer
38 // of exactly the right size and copy once, as opposed to a sequence of
39 // operator+ which generates a series of temporary strings, copying as it goes.
40 // And by using StringPiece arguments, StrCat can avoid creating temporary
41 // string objects for char* constants.
42 //
43 // ALTERNATIVES
44 //
45 // Internal Google / Abseil has a similar StrCat function. That version takes
46 // an overloaded number of arguments instead of initializer list (overflowing
47 // to initializer list for many arguments). We don't have any legacy
48 // requirements and using only initializer_list is simpler and generates
49 // roughly the same amount of code at the call sites.
50 //
51 // Abseil's StrCat also allows numbers by using an intermediate class that can
52 // be implicitly constructed from either a string or various number types. This
53 // class formats the numbers into a static buffer for increased performance,
54 // and the call sites look nice.
55 //
56 // As-written Abseil's helper class for numbers generates slightly more code
57 // than the raw StringPiece version. We can de-inline the helper class'
58 // constructors which will cause the StringPiece constructors to be de-inlined
59 // for this call and generate slightly less code. This is something we can
60 // explore more in the future.
61 
62 BASE_EXPORT std::string StrCat(span<const StringPiece> pieces)
63     WARN_UNUSED_RESULT;
64 BASE_EXPORT string16 StrCat(span<const StringPiece16> pieces)
65     WARN_UNUSED_RESULT;
66 BASE_EXPORT std::string StrCat(span<const std::string> pieces)
67     WARN_UNUSED_RESULT;
68 BASE_EXPORT string16 StrCat(span<const string16> pieces) WARN_UNUSED_RESULT;
69 
70 // Initializer list forwards to the array version.
StrCat(std::initializer_list<StringPiece> pieces)71 inline std::string StrCat(std::initializer_list<StringPiece> pieces) {
72   return StrCat(make_span(pieces));
73 }
74 
StrCat(std::initializer_list<StringPiece16> pieces)75 inline string16 StrCat(std::initializer_list<StringPiece16> pieces) {
76   return StrCat(make_span(pieces));
77 }
78 
79 // StrAppend -------------------------------------------------------------------
80 //
81 // Appends a sequence of strings to a destination. Prefer:
82 //   StrAppend(&foo, ...);
83 // over:
84 //   foo += StrCat(...);
85 // because it avoids a temporary string allocation and copy.
86 
87 BASE_EXPORT void StrAppend(std::string* dest, span<const StringPiece> pieces);
88 BASE_EXPORT void StrAppend(string16* dest, span<const StringPiece16> pieces);
89 BASE_EXPORT void StrAppend(std::string* dest, span<const std::string> pieces);
90 BASE_EXPORT void StrAppend(string16* dest, span<const string16> pieces);
91 
92 // Initializer list forwards to the array version.
StrAppend(std::string * dest,std::initializer_list<StringPiece> pieces)93 inline void StrAppend(std::string* dest,
94                       std::initializer_list<StringPiece> pieces) {
95   StrAppend(dest, make_span(pieces));
96 }
97 
StrAppend(string16 * dest,std::initializer_list<StringPiece16> pieces)98 inline void StrAppend(string16* dest,
99                       std::initializer_list<StringPiece16> pieces) {
100   StrAppend(dest, make_span(pieces));
101 }
102 
103 }  // namespace base
104 
105 #if defined(OS_WIN)
106 #include "base/strings/strcat_win.h"
107 #endif
108 
109 #endif  // BASE_STRINGS_STRCAT_H_
110