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
17namespace SkSL {
18
19String 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
28void String::appendf(const char* fmt, ...) {
29    va_list args;
30    va_start(args, fmt);
31    this->vappendf(fmt, args);
32}
33#endif
34
35void 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
56bool String::startsWith(const char* s) const {
57    return !strncmp(c_str(), s, strlen(s));
58}
59
60bool 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
68String String::operator+(const char* s) const {
69    String result(*this);
70    result.append(s);
71    return result;
72}
73
74String String::operator+(const String& s) const {
75    String result(*this);
76    result.append(s);
77    return result;
78}
79
80String String::operator+(StringFragment s) const {
81    String result(*this);
82    result.append(s.fChars, s.fLength);
83    return result;
84}
85
86String& String::operator+=(char c) {
87    INHERITED::operator+=(c);
88    return *this;
89}
90
91String& String::operator+=(const char* s) {
92    INHERITED::operator+=(s);
93    return *this;
94}
95
96String& String::operator+=(const String& s) {
97    INHERITED::operator+=(s);
98    return *this;
99}
100
101String& String::operator+=(StringFragment s) {
102    this->append(s.fChars, s.fLength);
103    return *this;
104}
105
106bool String::operator==(const String& s) const {
107    return this->size() == s.size() && !memcmp(c_str(), s.c_str(), this->size());
108}
109
110bool String::operator!=(const String& s) const {
111    return !(*this == s);
112}
113
114bool String::operator==(const char* s) const {
115    return this->size() == strlen(s) && !memcmp(c_str(), s, this->size());
116}
117
118bool String::operator!=(const char* s) const {
119    return !(*this == s);
120}
121
122String operator+(const char* s1, const String& s2) {
123    String result(s1);
124    result.append(s2);
125    return result;
126}
127
128bool operator==(const char* s1, const String& s2) {
129    return s2 == s1;
130}
131
132bool operator!=(const char* s1, const String& s2) {
133    return s2 != s1;
134}
135
136bool StringFragment::operator==(StringFragment s) const {
137    if (fLength != s.fLength) {
138        return false;
139    }
140    return !memcmp(fChars, s.fChars, fLength);
141}
142
143bool StringFragment::operator!=(StringFragment s) const {
144    if (fLength != s.fLength) {
145        return true;
146    }
147    return memcmp(fChars, s.fChars, fLength);
148}
149
150bool 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
159bool 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
168bool 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
176bool operator==(const char* s1, StringFragment s2) {
177    return s2 == s1;
178}
179
180bool operator!=(const char* s1, StringFragment s2) {
181    return s2 != s1;
182}
183
184String to_string(int32_t value) {
185    return SkSL::String::printf("%d", value);
186}
187
188String to_string(uint32_t value) {
189    return SkSL::String::printf("%u", value);
190}
191
192String to_string(int64_t value) {
193    std::stringstream buffer;
194    buffer << value;
195    return String(buffer.str().c_str());
196}
197
198String to_string(uint64_t value) {
199    std::stringstream buffer;
200    buffer << value;
201    return String(buffer.str().c_str());
202}
203
204String 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
223int 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
232double 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
242long 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