1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Author: kenton@google.com (Kenton Varda)
32// from google3/strings/substitute.h
33
34#include <google/protobuf/stubs/common.h>
35#include <google/protobuf/stubs/stringpiece.h>
36#include <google/protobuf/stubs/strutil.h>
37
38#include <string>
39
40#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
41#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
42
43#include <google/protobuf/port_def.inc>
44
45namespace google {
46namespace protobuf {
47namespace strings {
48
49// ----------------------------------------------------------------------
50// strings::Substitute()
51// strings::SubstituteAndAppend()
52// Kind of like StringPrintf, but different.
53//
54// Example:
55// string GetMessage(string first_name, string last_name, int age) {
56// return strings::Substitute("My name is $0 $1 and I am $2 years old.",
57// first_name, last_name, age);
58// }
59//
60// Differences from StringPrintf:
61// * The format string does not identify the types of arguments.
62// Instead, the magic of C++ deals with this for us. See below
63// for a list of accepted types.
64// * Substitutions in the format string are identified by a '$'
65// followed by a digit. So, you can use arguments out-of-order and
66// use the same argument multiple times.
67// * It's much faster than StringPrintf.
68//
69// Supported types:
70// * Strings (const char*, const string&)
71// * Note that this means you do not have to add .c_str() to all of
72// your strings. In fact, you shouldn't; it will be slower.
73// * int32, int64, uint32, uint64: Formatted using SimpleItoa().
74// * float, double: Formatted using SimpleFtoa() and SimpleDtoa().
75// * bool: Printed as "true" or "false".
76//
77// SubstituteAndAppend() is like Substitute() but appends the result to
78// *output. Example:
79//
80// string str;
81// strings::SubstituteAndAppend(&str,
82// "My name is $0 $1 and I am $2 years old.",
83// first_name, last_name, age);
84//
85// Substitute() is significantly faster than StringPrintf(). For very
86// large strings, it may be orders of magnitude faster.
87// ----------------------------------------------------------------------
88
89namespace internal { // Implementation details.
90
91class SubstituteArg {
92 public:
93 inline SubstituteArg(const char* value)
94 : text_(value), size_(strlen(s: text_)) {}
95 inline SubstituteArg(const std::string& value)
96 : text_(value.data()), size_(value.size()) {}
97 inline SubstituteArg(const StringPiece value)
98 : text_(value.data()), size_(value.size()) {}
99
100 // Indicates that no argument was given.
101 inline explicit SubstituteArg()
102 : text_(nullptr), size_(-1) {}
103
104 // Primitives
105 // We don't overload for signed and unsigned char because if people are
106 // explicitly declaring their chars as signed or unsigned then they are
107 // probably actually using them as 8-bit integers and would probably
108 // prefer an integer representation. But, we don't really know. So, we
109 // make the caller decide what to do.
110 inline SubstituteArg(char value)
111 : text_(scratch_), size_(1) { scratch_[0] = value; }
112 inline SubstituteArg(short value)
113 : text_(FastInt32ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
114 inline SubstituteArg(unsigned short value)
115 : text_(FastUInt32ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
116 inline SubstituteArg(int value)
117 : text_(FastInt32ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
118 inline SubstituteArg(unsigned int value)
119 : text_(FastUInt32ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
120 inline SubstituteArg(long value)
121 : text_(FastLongToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
122 inline SubstituteArg(unsigned long value)
123 : text_(FastULongToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
124 inline SubstituteArg(long long value)
125 : text_(FastInt64ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
126 inline SubstituteArg(unsigned long long value)
127 : text_(FastUInt64ToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
128 inline SubstituteArg(float value)
129 : text_(FloatToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
130 inline SubstituteArg(double value)
131 : text_(DoubleToBuffer(i: value, buffer: scratch_)), size_(strlen(s: text_)) {}
132 inline SubstituteArg(bool value)
133 : text_(value ? "true" : "false"), size_(strlen(s: text_)) {}
134
135 inline const char* data() const { return text_; }
136 inline int size() const { return size_; }
137
138 private:
139 const char* text_;
140 int size_;
141 char scratch_[kFastToBufferSize];
142};
143
144} // namespace internal
145
146PROTOBUF_EXPORT std::string Substitute(
147 const std::string& format,
148 const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
149 const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
150 const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
151 const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
152 const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
153 const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
154 const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
155 const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
156 const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
157 const internal::SubstituteArg& arg9 = internal::SubstituteArg());
158
159PROTOBUF_EXPORT void SubstituteAndAppend(
160 std::string* output, const char* format,
161 const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
162 const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
163 const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
164 const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
165 const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
166 const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
167 const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
168 const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
169 const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
170 const internal::SubstituteArg& arg9 = internal::SubstituteArg());
171
172} // namespace strings
173} // namespace protobuf
174} // namespace google
175
176#include <google/protobuf/port_undef.inc>
177
178#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
179