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 "include/private/SkSLString.h"
9 #include "src/sksl/SkSLUtil.h"
10 #include <algorithm>
11 #include <cinttypes>
12 #include <errno.h>
13 #include <limits.h>
14 #include <locale>
15 #include <sstream>
16 #include <string>
17
18 namespace SkSL {
19
printf(const char * fmt,...)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
appendf(const char * fmt,...)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
vappendf(const char * fmt,va_list args)36 void String::vappendf(const char* fmt, va_list args) {
37 #define BUFFER_SIZE 256
38 char buffer[BUFFER_SIZE];
39 va_list reuse;
40 va_copy(reuse, args);
41 size_t size = vsnprintf(buffer, BUFFER_SIZE, fmt, args);
42 if (BUFFER_SIZE >= size + 1) {
43 this->append(buffer, size);
44 } else {
45 auto newBuffer = std::unique_ptr<char[]>(new char[size + 1]);
46 vsnprintf(newBuffer.get(), size + 1, fmt, reuse);
47 this->append(newBuffer.get(), size);
48 }
49 va_end(reuse);
50 }
51
startsWith(const char prefix[]) const52 bool StringFragment::startsWith(const char prefix[]) const {
53 return !strncmp(fChars, prefix, strlen(prefix));
54 }
55
endsWith(const char suffix[]) const56 bool StringFragment::endsWith(const char suffix[]) const {
57 size_t suffixLength = strlen(suffix);
58 if (fLength < suffixLength) {
59 return false;
60 }
61 return !strncmp(fChars + fLength - suffixLength, suffix, suffixLength);
62 }
63
consumeSuffix(const char suffix[])64 bool String::consumeSuffix(const char suffix[]) {
65 size_t suffixLength = strlen(suffix);
66 if (this->length() < suffixLength) {
67 return false;
68 }
69 if (0 != strncmp(this->data() + this->size() - suffixLength, suffix, suffixLength)) {
70 return false;
71 }
72 this->resize(this->length() - suffixLength);
73 return true;
74 }
75
operator +(const char * s) const76 String String::operator+(const char* s) const {
77 String result(*this);
78 result.append(s);
79 return result;
80 }
81
operator +(const String & s) const82 String String::operator+(const String& s) const {
83 String result(*this);
84 result.append(s);
85 return result;
86 }
87
operator +(StringFragment s) const88 String String::operator+(StringFragment s) const {
89 String result(*this);
90 result.append(s.fChars, s.fLength);
91 return result;
92 }
93
operator +=(char c)94 String& String::operator+=(char c) {
95 INHERITED::operator+=(c);
96 return *this;
97 }
98
operator +=(const char * s)99 String& String::operator+=(const char* s) {
100 INHERITED::operator+=(s);
101 return *this;
102 }
103
operator +=(const String & s)104 String& String::operator+=(const String& s) {
105 INHERITED::operator+=(s);
106 return *this;
107 }
108
operator +=(StringFragment s)109 String& String::operator+=(StringFragment s) {
110 this->append(s.fChars, s.fLength);
111 return *this;
112 }
113
operator ==(const String & s) const114 bool String::operator==(const String& s) const {
115 return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size());
116 }
117
operator !=(const String & s) const118 bool String::operator!=(const String& s) const {
119 return !(*this == s);
120 }
121
operator ==(const char * s) const122 bool String::operator==(const char* s) const {
123 return this->size() == strlen(s) && !memcmp(c_str(), s, this->size());
124 }
125
operator !=(const char * s) const126 bool String::operator!=(const char* s) const {
127 return !(*this == s);
128 }
129
operator +(const char * s1,const String & s2)130 String operator+(const char* s1, const String& s2) {
131 String result(s1);
132 result.append(s2);
133 return result;
134 }
135
operator ==(const char * s1,const String & s2)136 bool operator==(const char* s1, const String& s2) {
137 return s2 == s1;
138 }
139
operator !=(const char * s1,const String & s2)140 bool operator!=(const char* s1, const String& s2) {
141 return s2 != s1;
142 }
143
operator ==(StringFragment s) const144 bool StringFragment::operator==(StringFragment s) const {
145 if (fLength != s.fLength) {
146 return false;
147 }
148 return !memcmp(fChars, s.fChars, fLength);
149 }
150
operator !=(StringFragment s) const151 bool StringFragment::operator!=(StringFragment s) const {
152 if (fLength != s.fLength) {
153 return true;
154 }
155 return memcmp(fChars, s.fChars, fLength);
156 }
157
operator ==(const char * s) const158 bool StringFragment::operator==(const char* s) const {
159 for (size_t i = 0; i < fLength; ++i) {
160 if (fChars[i] != s[i]) {
161 return false;
162 }
163 }
164 return 0 == s[fLength];
165 }
166
operator !=(const char * s) const167 bool StringFragment::operator!=(const char* s) const {
168 for (size_t i = 0; i < fLength; ++i) {
169 if (fChars[i] != s[i]) {
170 return true;
171 }
172 }
173 return 0 != s[fLength];
174 }
175
operator <(StringFragment other) const176 bool StringFragment::operator<(StringFragment other) const {
177 int comparison = strncmp(fChars, other.fChars, std::min(fLength, other.fLength));
178 if (comparison) {
179 return comparison < 0;
180 }
181 return fLength < other.fLength;
182 }
183
operator +(const char * other) const184 String StringFragment::operator+(const char* other) const {
185 return String(*this) + other;
186 }
187
operator +(const StringFragment & other) const188 String StringFragment::operator+(const StringFragment& other) const {
189 return String(*this) + other;
190 }
191
operator +(const String & other) const192 String StringFragment::operator+(const String& other) const {
193 return String(*this) + other;
194 }
195
operator ==(const char * s1,StringFragment s2)196 bool operator==(const char* s1, StringFragment s2) {
197 return s2 == s1;
198 }
199
operator !=(const char * s1,StringFragment s2)200 bool operator!=(const char* s1, StringFragment s2) {
201 return s2 != s1;
202 }
203
to_string(int32_t value)204 String to_string(int32_t value) {
205 return SkSL::String(std::to_string(value));
206 }
207
to_string(uint32_t value)208 String to_string(uint32_t value) {
209 return SkSL::String(std::to_string(value));
210 }
211
to_string(int64_t value)212 String to_string(int64_t value) {
213 return SkSL::String(std::to_string(value));
214 }
215
to_string(uint64_t value)216 String to_string(uint64_t value) {
217 return SkSL::String(std::to_string(value));
218 }
219
to_string(double value)220 String to_string(double value) {
221 std::stringstream buffer;
222 buffer.imbue(std::locale::classic());
223 buffer.precision(17);
224 buffer << value;
225 bool needsDotZero = true;
226 const std::string str = buffer.str();
227 for (int i = str.size() - 1; i >= 0; --i) {
228 char c = str[i];
229 if (c == '.' || c == 'e') {
230 needsDotZero = false;
231 break;
232 }
233 }
234 if (needsDotZero) {
235 buffer << ".0";
236 }
237 return String(buffer.str().c_str());
238 }
239
stod(const StringFragment & s,SKSL_FLOAT * value)240 bool stod(const StringFragment& s, SKSL_FLOAT* value) {
241 std::string str(s.data(), s.size());
242 std::stringstream buffer(str);
243 buffer.imbue(std::locale::classic());
244 buffer >> *value;
245 return !buffer.fail();
246 }
247
stoi(const StringFragment & s,SKSL_INT * value)248 bool stoi(const StringFragment& s, SKSL_INT* value) {
249 char* p;
250 errno = 0;
251 unsigned long long result = strtoull(s.begin(), &p, /*base=*/0);
252 *value = static_cast<SKSL_INT>(result);
253 return p == s.end() && errno == 0 && result <= 0xFFFFFFFF;
254 }
255
256 } // namespace SkSL
257