blob: c8ff15b3988ada892252a2d972486883587a3cad [file] [log] [blame]
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001/*
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"
Brian Osmande7220f2018-02-09 09:32:36 -050011#include <algorithm>
Ethan Nicholas0df1b042017-03-31 13:56:23 -040012#include <errno.h>
Ethan Nicholas0df1b042017-03-31 13:56:23 -040013#include <limits.h>
14#include <locale>
15#include <sstream>
16#include <string>
17
18namespace SkSL {
19
20String String::printf(const char* fmt, ...) {
21 va_list args;
22 va_start(args, fmt);
23 String result;
24 result.vappendf(fmt, args);
25 return result;
26}
27
Brian Osman93ba0a42017-08-14 14:48:10 -040028#ifdef SKSL_USE_STD_STRING
Ethan Nicholas0df1b042017-03-31 13:56:23 -040029void String::appendf(const char* fmt, ...) {
30 va_list args;
31 va_start(args, fmt);
32 this->vappendf(fmt, args);
33}
34#endif
35
36void String::vappendf(const char* fmt, va_list args) {
37#ifdef SKSL_BUILD_FOR_WIN
38 #define VSNPRINTF _vsnprintf
39#else
40 #define VSNPRINTF vsnprintf
41#endif
42 #define BUFFER_SIZE 256
43 char buffer[BUFFER_SIZE];
Ethan Nicholas762466e2017-06-29 10:03:38 -040044 va_list reuse;
45 va_copy(reuse, args);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040046 size_t size = VSNPRINTF(buffer, BUFFER_SIZE, fmt, args);
47 if (BUFFER_SIZE >= size) {
48 this->append(buffer, size);
49 } else {
Ethan Nicholas762466e2017-06-29 10:03:38 -040050 auto newBuffer = std::unique_ptr<char[]>(new char[size + 1]);
51 VSNPRINTF(newBuffer.get(), size + 1, fmt, reuse);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040052 this->append(newBuffer.get(), size);
53 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -040054}
55
56
57bool String::startsWith(const char* s) const {
Ethan Nicholas985febf2017-05-19 14:03:45 -040058 return !strncmp(c_str(), s, strlen(s));
Ethan Nicholas0df1b042017-03-31 13:56:23 -040059}
60
61bool String::endsWith(const char* s) const {
62 size_t len = strlen(s);
63 if (size() < len) {
64 return false;
65 }
Ethan Nicholas985febf2017-05-19 14:03:45 -040066 return !strncmp(c_str() + size() - len, s, len);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040067}
68
69String String::operator+(const char* s) const {
70 String result(*this);
71 result.append(s);
72 return result;
73}
74
75String String::operator+(const String& s) const {
76 String result(*this);
77 result.append(s);
78 return result;
79}
80
Ethan Nicholas5b5f0962017-09-11 13:50:14 -070081String String::operator+(StringFragment s) const {
82 String result(*this);
83 result.append(s.fChars, s.fLength);
84 return result;
85}
86
87String& String::operator+=(char c) {
88 INHERITED::operator+=(c);
89 return *this;
90}
91
92String& String::operator+=(const char* s) {
93 INHERITED::operator+=(s);
94 return *this;
95}
96
97String& String::operator+=(const String& s) {
98 INHERITED::operator+=(s);
99 return *this;
100}
101
102String& String::operator+=(StringFragment s) {
103 this->append(s.fChars, s.fLength);
104 return *this;
105}
106
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400107bool String::operator==(const String& s) const {
108 return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size());
109}
110
111bool String::operator!=(const String& s) const {
112 return !(*this == s);
113}
114
115bool String::operator==(const char* s) const {
116 return this->size() == strlen(s) && !memcmp(c_str(), s, this->size());
117}
118
119bool String::operator!=(const char* s) const {
120 return !(*this == s);
121}
122
123String operator+(const char* s1, const String& s2) {
124 String result(s1);
125 result.append(s2);
126 return result;
127}
128
129bool operator==(const char* s1, const String& s2) {
130 return s2 == s1;
131}
132
133bool operator!=(const char* s1, const String& s2) {
134 return s2 != s1;
135}
136
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700137bool StringFragment::operator==(StringFragment s) const {
138 if (fLength != s.fLength) {
139 return false;
140 }
141 return !memcmp(fChars, s.fChars, fLength);
142}
143
144bool StringFragment::operator!=(StringFragment s) const {
145 if (fLength != s.fLength) {
146 return true;
147 }
148 return memcmp(fChars, s.fChars, fLength);
149}
150
151bool StringFragment::operator==(const char* s) const {
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500152 for (size_t i = 0; i < fLength; ++i) {
153 if (fChars[i] != s[i]) {
154 return false;
155 }
156 }
157 return 0 == s[fLength];
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700158}
159
160bool StringFragment::operator!=(const char* s) const {
Ethan Nicholase9d172a2017-11-20 12:12:24 -0500161 for (size_t i = 0; i < fLength; ++i) {
162 if (fChars[i] != s[i]) {
163 return true;
164 }
165 }
166 return 0 != s[fLength];
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700167}
168
Ethan Nicholas2c33e3e2018-01-08 15:36:28 -0500169bool StringFragment::operator<(StringFragment other) const {
170 int comparison = strncmp(fChars, other.fChars, std::min(fLength, other.fLength));
171 if (comparison) {
172 return comparison < 0;
173 }
174 return fLength < other.fLength;
175}
176
Ethan Nicholascc305772017-10-13 16:17:45 -0400177bool operator==(const char* s1, StringFragment s2) {
178 return s2 == s1;
179}
180
181bool operator!=(const char* s1, StringFragment s2) {
182 return s2 != s1;
183}
184
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400185String to_string(int32_t value) {
186 return SkSL::String::printf("%d", value);
187}
188
189String to_string(uint32_t value) {
190 return SkSL::String::printf("%u", value);
191}
192
193String to_string(int64_t value) {
Ethan Nicholasc8c17602017-03-31 18:53:05 -0400194 std::stringstream buffer;
195 buffer << value;
196 return String(buffer.str().c_str());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400197}
198
199String to_string(uint64_t value) {
Ethan Nicholasc8c17602017-03-31 18:53:05 -0400200 std::stringstream buffer;
201 buffer << value;
202 return String(buffer.str().c_str());
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400203}
204
205String to_string(double value) {
206#ifdef SKSL_BUILD_FOR_WIN
207 #define SNPRINTF _snprintf
208#else
209 #define SNPRINTF snprintf
210#endif
211#define MAX_DOUBLE_CHARS 25
212 char buffer[MAX_DOUBLE_CHARS];
213 SKSL_DEBUGCODE(int len = )SNPRINTF(buffer, sizeof(buffer), "%.17g", value);
214 ASSERT(len < MAX_DOUBLE_CHARS);
215 String result(buffer);
216 if (!strchr(buffer, '.') && !strchr(buffer, 'e')) {
217 result += ".0";
218 }
219 return result;
220#undef SNPRINTF
221#undef MAX_DOUBLE_CHARS
222}
223
Brian Osman634624a2017-08-15 11:14:30 -0400224int stoi(const String& s) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400225 char* p;
226 SKSL_DEBUGCODE(errno = 0;)
227 long result = strtoul(s.c_str(), &p, 0);
228 ASSERT(*p == 0);
229 ASSERT(!errno);
230 return (int) result;
231}
232
Brian Osman634624a2017-08-15 11:14:30 -0400233double stod(const String& s) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400234 double result;
235 std::string str(s.c_str(), s.size());
236 std::stringstream buffer(str);
237 buffer.imbue(std::locale::classic());
238 buffer >> result;
239 ASSERT(!buffer.fail());
240 return result;
241}
242
Brian Osman634624a2017-08-15 11:14:30 -0400243long stol(const String& s) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400244 char* p;
245 SKSL_DEBUGCODE(errno = 0;)
246 long result = strtoul(s.c_str(), &p, 0);
247 ASSERT(*p == 0);
248 ASSERT(!errno);
249 return result;
250}
251
252} // namespace