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