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 "src/sksl/SkSLString.h" |
9 | |
10 | #include "src/sksl/SkSLUtil.h" |
11 | #include <algorithm> |
12 | #include <errno.h> |
13 | #include <limits.h> |
14 | #include <locale> |
15 | #include <sstream> |
16 | #include <string> |
17 | |
18 | namespace SkSL { |
19 | |
20 | String String::printf(const char* fmt, ...) { |
21 | va_list args; |
22 | va_start(args, fmt); |
23 | String result; |
24 | result.vappendf(fmt, args); |
25 | va_end(args); |
26 | return result; |
27 | } |
28 | |
29 | void String::appendf(const char* fmt, ...) { |
30 | va_list args; |
31 | va_start(args, fmt); |
32 | this->vappendf(fmt, args); |
33 | va_end(args); |
34 | } |
35 | |
36 | void String::reset() { |
37 | this->clear(); |
38 | } |
39 | |
40 | int String::findLastOf(const char c) const { |
41 | // Rely on find_last_of and remap the output |
42 | size_t index = this->find_last_of(c); |
43 | return (index == std::string::npos ? -1 : index); |
44 | } |
45 | |
46 | void String::vappendf(const char* fmt, va_list args) { |
47 | #ifdef SKSL_BUILD_FOR_WIN |
48 | #define VSNPRINTF _vsnprintf |
49 | #else |
50 | #define VSNPRINTF vsnprintf |
51 | #endif |
52 | #define BUFFER_SIZE 256 |
53 | char buffer[BUFFER_SIZE]; |
54 | va_list reuse; |
55 | va_copy(reuse, args); |
56 | size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args); |
57 | if (BUFFER_SIZE >= size) { |
58 | this->append(buffer, size); |
59 | } else { |
60 | auto newBuffer = std::unique_ptr<char[]>(new char[size + 1]); |
61 | VSNPRINTF(newBuffer.get(), size + 1, fmt, reuse); |
62 | this->append(newBuffer.get(), size); |
63 | } |
64 | va_end(reuse); |
65 | } |
66 | |
67 | |
68 | bool String::startsWith(const char* s) const { |
69 | return !strncmp(c_str(), s, strlen(s)); |
70 | } |
71 | |
72 | bool String::endsWith(const char* s) const { |
73 | size_t len = strlen(s); |
74 | if (size() < len) { |
75 | return false; |
76 | } |
77 | return !strncmp(c_str() + size() - len, s, len); |
78 | } |
79 | |
80 | int String::find(const String& substring, int fromPos) const { |
81 | return find(substring.c_str(), fromPos); |
82 | } |
83 | |
84 | int String::find(const char* substring, int fromPos) const { |
85 | SkASSERT(fromPos >= 0); |
86 | size_t found = INHERITED::find(substring, (size_t) fromPos); |
87 | return found == std::string::npos ? -1 : found; |
88 | } |
89 | |
90 | String String::operator+(const char* s) const { |
91 | String result(*this); |
92 | result.append(s); |
93 | return result; |
94 | } |
95 | |
96 | String String::operator+(const String& s) const { |
97 | String result(*this); |
98 | result.append(s); |
99 | return result; |
100 | } |
101 | |
102 | String String::operator+(StringFragment s) const { |
103 | String result(*this); |
104 | result.append(s.fChars, s.fLength); |
105 | return result; |
106 | } |
107 | |
108 | String& String::operator+=(char c) { |
109 | INHERITED::operator+=(c); |
110 | return *this; |
111 | } |
112 | |
113 | String& String::operator+=(const char* s) { |
114 | INHERITED::operator+=(s); |
115 | return *this; |
116 | } |
117 | |
118 | String& String::operator+=(const String& s) { |
119 | INHERITED::operator+=(s); |
120 | return *this; |
121 | } |
122 | |
123 | String& String::operator+=(StringFragment s) { |
124 | this->append(s.fChars, s.fLength); |
125 | return *this; |
126 | } |
127 | |
128 | bool String::operator==(const String& s) const { |
129 | return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size()); |
130 | } |
131 | |
132 | bool String::operator!=(const String& s) const { |
133 | return !(*this == s); |
134 | } |
135 | |
136 | bool String::operator==(const char* s) const { |
137 | return this->size() == strlen(s) && !memcmp(c_str(), s, this->size()); |
138 | } |
139 | |
140 | bool String::operator!=(const char* s) const { |
141 | return !(*this == s); |
142 | } |
143 | |
144 | String operator+(const char* s1, const String& s2) { |
145 | String result(s1); |
146 | result.append(s2); |
147 | return result; |
148 | } |
149 | |
150 | bool operator==(const char* s1, const String& s2) { |
151 | return s2 == s1; |
152 | } |
153 | |
154 | bool operator!=(const char* s1, const String& s2) { |
155 | return s2 != s1; |
156 | } |
157 | |
158 | bool StringFragment::operator==(StringFragment s) const { |
159 | if (fLength != s.fLength) { |
160 | return false; |
161 | } |
162 | return !memcmp(fChars, s.fChars, fLength); |
163 | } |
164 | |
165 | bool StringFragment::operator!=(StringFragment s) const { |
166 | if (fLength != s.fLength) { |
167 | return true; |
168 | } |
169 | return memcmp(fChars, s.fChars, fLength); |
170 | } |
171 | |
172 | bool StringFragment::operator==(const char* s) const { |
173 | for (size_t i = 0; i < fLength; ++i) { |
174 | if (fChars[i] != s[i]) { |
175 | return false; |
176 | } |
177 | } |
178 | return 0 == s[fLength]; |
179 | } |
180 | |
181 | bool StringFragment::operator!=(const char* s) const { |
182 | for (size_t i = 0; i < fLength; ++i) { |
183 | if (fChars[i] != s[i]) { |
184 | return true; |
185 | } |
186 | } |
187 | return 0 != s[fLength]; |
188 | } |
189 | |
190 | bool StringFragment::operator<(StringFragment other) const { |
191 | int comparison = strncmp(fChars, other.fChars, std::min(fLength, other.fLength)); |
192 | if (comparison) { |
193 | return comparison < 0; |
194 | } |
195 | return fLength < other.fLength; |
196 | } |
197 | |
198 | bool operator==(const char* s1, StringFragment s2) { |
199 | return s2 == s1; |
200 | } |
201 | |
202 | bool operator!=(const char* s1, StringFragment s2) { |
203 | return s2 != s1; |
204 | } |
205 | |
206 | String to_string(int32_t value) { |
207 | return SkSL::String::printf("%d" , value); |
208 | } |
209 | |
210 | String to_string(uint32_t value) { |
211 | return SkSL::String::printf("%u" , value); |
212 | } |
213 | |
214 | String to_string(int64_t value) { |
215 | std::stringstream buffer; |
216 | buffer << value; |
217 | return String(buffer.str().c_str()); |
218 | } |
219 | |
220 | String to_string(uint64_t value) { |
221 | std::stringstream buffer; |
222 | buffer << value; |
223 | return String(buffer.str().c_str()); |
224 | } |
225 | |
226 | String to_string(double value) { |
227 | std::stringstream buffer; |
228 | buffer.imbue(std::locale::classic()); |
229 | buffer.precision(17); |
230 | buffer << value; |
231 | bool needsDotZero = true; |
232 | const std::string str = buffer.str(); |
233 | for (int i = str.size() - 1; i >= 0; --i) { |
234 | char c = str[i]; |
235 | if (c == '.' || c == 'e') { |
236 | needsDotZero = false; |
237 | break; |
238 | } |
239 | } |
240 | if (needsDotZero) { |
241 | buffer << ".0" ; |
242 | } |
243 | return String(buffer.str().c_str()); |
244 | } |
245 | |
246 | SKSL_INT stoi(const String& s) { |
247 | char* p; |
248 | SkDEBUGCODE(errno = 0;) |
249 | long result = strtoul(s.c_str(), &p, 0); |
250 | SkASSERT(*p == 0); |
251 | SkASSERT(!errno); |
252 | return result; |
253 | } |
254 | |
255 | SKSL_FLOAT stod(const String& s) { |
256 | double result; |
257 | std::string str(s.c_str(), s.size()); |
258 | std::stringstream buffer(str); |
259 | buffer.imbue(std::locale::classic()); |
260 | buffer >> result; |
261 | SkASSERT(!buffer.fail()); |
262 | return result; |
263 | } |
264 | |
265 | long stol(const String& s) { |
266 | char* p; |
267 | SkDEBUGCODE(errno = 0;) |
268 | long result = strtoul(s.c_str(), &p, 0); |
269 | SkASSERT(*p == 0); |
270 | SkASSERT(!errno); |
271 | return result; |
272 | } |
273 | |
274 | } // namespace |
275 | |