1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkSLString.h"
9
10 #include "SkSLUtil.h"
11 #include <errno.h>
12 #include <limits.h>
13 #include <locale>
14 #include <sstream>
15 #include <string>
16
17 namespace SkSL {
18
printf(const char * fmt,...)19 String String::printf(const char* fmt, ...) {
20 va_list args;
21 va_start(args, fmt);
22 String result;
23 result.vappendf(fmt, args);
24 return result;
25 }
26
27 #ifdef SKSL_USE_STD_STRING
appendf(const char * fmt,...)28 void String::appendf(const char* fmt, ...) {
29 va_list args;
30 va_start(args, fmt);
31 this->vappendf(fmt, args);
32 }
33 #endif
34
vappendf(const char * fmt,va_list args)35 void String::vappendf(const char* fmt, va_list args) {
36 #ifdef SKSL_BUILD_FOR_WIN
37 #define VSNPRINTF _vsnprintf
38 #else
39 #define VSNPRINTF vsnprintf
40 #endif
41 #define BUFFER_SIZE 256
42 char buffer[BUFFER_SIZE];
43 va_list reuse;
44 va_copy(reuse, args);
45 size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args);
46 if (BUFFER_SIZE >= size) {
47 this->append(buffer, size);
48 } else {
49 auto newBuffer = std::unique_ptr<char[]>(new char[size + 1]);
50 VSNPRINTF(newBuffer.get(), size + 1, fmt, reuse);
51 this->append(newBuffer.get(), size);
52 }
53 }
54
55
startsWith(const char * s) const56 bool String::startsWith(const char* s) const {
57 return !strncmp(c_str(), s, strlen(s));
58 }
59
endsWith(const char * s) const60 bool String::endsWith(const char* s) const {
61 size_t len = strlen(s);
62 if (size() < len) {
63 return false;
64 }
65 return !strncmp(c_str() + size() - len, s, len);
66 }
67
operator +(const char * s) const68 String String::operator+(const char* s) const {
69 String result(*this);
70 result.append(s);
71 return result;
72 }
73
operator +(const String & s) const74 String String::operator+(const String& s) const {
75 String result(*this);
76 result.append(s);
77 return result;
78 }
79
operator +(StringFragment s) const80 String String::operator+(StringFragment s) const {
81 String result(*this);
82 result.append(s.fChars, s.fLength);
83 return result;
84 }
85
operator +=(char c)86 String& String::operator+=(char c) {
87 INHERITED::operator+=(c);
88 return *this;
89 }
90
operator +=(const char * s)91 String& String::operator+=(const char* s) {
92 INHERITED::operator+=(s);
93 return *this;
94 }
95
operator +=(const String & s)96 String& String::operator+=(const String& s) {
97 INHERITED::operator+=(s);
98 return *this;
99 }
100
operator +=(StringFragment s)101 String& String::operator+=(StringFragment s) {
102 this->append(s.fChars, s.fLength);
103 return *this;
104 }
105
operator ==(const String & s) const106 bool String::operator==(const String& s) const {
107 return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size());
108 }
109
operator !=(const String & s) const110 bool String::operator!=(const String& s) const {
111 return !(*this == s);
112 }
113
operator ==(const char * s) const114 bool String::operator==(const char* s) const {
115 return this->size() == strlen(s) && !memcmp(c_str(), s, this->size());
116 }
117
operator !=(const char * s) const118 bool String::operator!=(const char* s) const {
119 return !(*this == s);
120 }
121
operator +(const char * s1,const String & s2)122 String operator+(const char* s1, const String& s2) {
123 String result(s1);
124 result.append(s2);
125 return result;
126 }
127
operator ==(const char * s1,const String & s2)128 bool operator==(const char* s1, const String& s2) {
129 return s2 == s1;
130 }
131
operator !=(const char * s1,const String & s2)132 bool operator!=(const char* s1, const String& s2) {
133 return s2 != s1;
134 }
135
operator ==(StringFragment s) const136 bool StringFragment::operator==(StringFragment s) const {
137 if (fLength != s.fLength) {
138 return false;
139 }
140 return !memcmp(fChars, s.fChars, fLength);
141 }
142
operator !=(StringFragment s) const143 bool StringFragment::operator!=(StringFragment s) const {
144 if (fLength != s.fLength) {
145 return true;
146 }
147 return memcmp(fChars, s.fChars, fLength);
148 }
149
operator ==(const char * s) const150 bool StringFragment::operator==(const char* s) const {
151 for (size_t i = 0; i < fLength; ++i) {
152 if (fChars[i] != s[i]) {
153 return false;
154 }
155 }
156 return 0 == s[fLength];
157 }
158
operator !=(const char * s) const159 bool StringFragment::operator!=(const char* s) const {
160 for (size_t i = 0; i < fLength; ++i) {
161 if (fChars[i] != s[i]) {
162 return true;
163 }
164 }
165 return 0 != s[fLength];
166 }
167
operator <(StringFragment other) const168 bool StringFragment::operator<(StringFragment other) const {
169 int comparison = strncmp(fChars, other.fChars, std::min(fLength, other.fLength));
170 if (comparison) {
171 return comparison < 0;
172 }
173 return fLength < other.fLength;
174 }
175
operator ==(const char * s1,StringFragment s2)176 bool operator==(const char* s1, StringFragment s2) {
177 return s2 == s1;
178 }
179
operator !=(const char * s1,StringFragment s2)180 bool operator!=(const char* s1, StringFragment s2) {
181 return s2 != s1;
182 }
183
to_string(int32_t value)184 String to_string(int32_t value) {
185 return SkSL::String::printf("%d", value);
186 }
187
to_string(uint32_t value)188 String to_string(uint32_t value) {
189 return SkSL::String::printf("%u", value);
190 }
191
to_string(int64_t value)192 String to_string(int64_t value) {
193 std::stringstream buffer;
194 buffer << value;
195 return String(buffer.str().c_str());
196 }
197
to_string(uint64_t value)198 String to_string(uint64_t value) {
199 std::stringstream buffer;
200 buffer << value;
201 return String(buffer.str().c_str());
202 }
203
to_string(double value)204 String to_string(double value) {
205 #ifdef SKSL_BUILD_FOR_WIN
206 #define SNPRINTF _snprintf
207 #else
208 #define SNPRINTF snprintf
209 #endif
210 #define MAX_DOUBLE_CHARS 25
211 char buffer[MAX_DOUBLE_CHARS];
212 SKSL_DEBUGCODE(int len = )SNPRINTF(buffer, sizeof(buffer), "%.17g", value);
213 ASSERT(len < MAX_DOUBLE_CHARS);
214 String result(buffer);
215 if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
216 result += ".0";
217 }
218 return result;
219 #undef SNPRINTF
220 #undef MAX_DOUBLE_CHARS
221 }
222
stoi(const String & s)223 int stoi(const String& s) {
224 char* p;
225 SKSL_DEBUGCODE(errno = 0;)
226 long result = strtoul(s.c_str(), &p, 0);
227 ASSERT(*p == 0);
228 ASSERT(!errno);
229 return (int) result;
230 }
231
stod(const String & s)232 double stod(const String& s) {
233 double result;
234 std::string str(s.c_str(), s.size());
235 std::stringstream buffer(str);
236 buffer.imbue(std::locale::classic());
237 buffer >> result;
238 ASSERT(!buffer.fail());
239 return result;
240 }
241
stol(const String & s)242 long stol(const String& s) {
243 char* p;
244 SKSL_DEBUGCODE(errno = 0;)
245 long result = strtoul(s.c_str(), &p, 0);
246 ASSERT(*p == 0);
247 ASSERT(!errno);
248 return result;
249 }
250
251 } // namespace
252