Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/string.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #ifndef KJ_STRING_H_ | |
23 #define KJ_STRING_H_ | |
24 | |
25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS | |
26 #pragma GCC system_header | |
27 #endif | |
28 | |
29 #include <initializer_list> | |
30 #include "array.h" | |
31 #include <string.h> | |
32 | |
33 namespace kj { | |
34 | |
35 class StringPtr; | |
36 class String; | |
37 | |
38 class StringTree; // string-tree.h | |
39 | |
40 // Our STL string SFINAE trick does not work with GCC 4.7, but it works with Clang and GCC 4.8, so | |
41 // we'll just preprocess it out if not supported. | |
42 #if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || _MSC_VER | |
43 #define KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP 1 | |
44 #endif | |
45 | |
46 // ======================================================================================= | |
47 // StringPtr -- A NUL-terminated ArrayPtr<const char> containing UTF-8 text. | |
48 // | |
49 // NUL bytes are allowed to appear before the end of the string. The only requirement is that | |
50 // a NUL byte appear immediately after the last byte of the content. This terminator byte is not | |
51 // counted in the string's size. | |
52 | |
53 class StringPtr { | |
54 public: | |
55 inline StringPtr(): content("", 1) {} | |
56 inline StringPtr(decltype(nullptr)): content("", 1) {} | |
57 inline StringPtr(const char* value): content(value, strlen(value) + 1) {} | |
58 inline StringPtr(const char* value, size_t size): content(value, size + 1) { | |
59 KJ_IREQUIRE(value[size] == '\0', "StringPtr must be NUL-terminated."); | |
60 } | |
61 inline StringPtr(const char* begin, const char* end): StringPtr(begin, end - begin) {} | |
62 inline StringPtr(const String& value); | |
63 | |
64 #if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP | |
65 template <typename T, typename = decltype(instance<T>().c_str())> | |
66 inline StringPtr(const T& t): StringPtr(t.c_str()) {} | |
67 // Allow implicit conversion from any class that has a c_str() method (namely, std::string). | |
68 // We use a template trick to detect std::string in order to avoid including the header for | |
69 // those who don't want it. | |
70 | |
71 template <typename T, typename = decltype(instance<T>().c_str())> | |
72 inline operator T() const { return cStr(); } | |
73 // Allow implicit conversion to any class that has a c_str() method (namely, std::string). | |
74 // We use a template trick to detect std::string in order to avoid including the header for | |
75 // those who don't want it. | |
76 #endif | |
77 | |
78 inline operator ArrayPtr<const char>() const; | |
79 inline ArrayPtr<const char> asArray() const; | |
80 inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); } | |
81 // Result does not include NUL terminator. | |
82 | |
83 inline const char* cStr() const { return content.begin(); } | |
84 // Returns NUL-terminated string. | |
85 | |
86 inline size_t size() const { return content.size() - 1; } | |
87 // Result does not include NUL terminator. | |
88 | |
89 inline char operator[](size_t index) const { return content[index]; } | |
90 | |
91 inline const char* begin() const { return content.begin(); } | |
92 inline const char* end() const { return content.end() - 1; } | |
93 | |
94 inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } | |
95 inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } | |
96 | |
97 inline bool operator==(const StringPtr& other) const; | |
98 inline bool operator!=(const StringPtr& other) const { return !(*this == other); } | |
99 inline bool operator< (const StringPtr& other) const; | |
100 inline bool operator> (const StringPtr& other) const { return other < *this; } | |
101 inline bool operator<=(const StringPtr& other) const { return !(other < *this); } | |
102 inline bool operator>=(const StringPtr& other) const { return !(*this < other); } | |
103 | |
104 inline StringPtr slice(size_t start) const; | |
105 inline ArrayPtr<const char> slice(size_t start, size_t end) const; | |
106 // A string slice is only NUL-terminated if it is a suffix, so slice() has a one-parameter | |
107 // version that assumes end = size(). | |
108 | |
109 inline bool startsWith(const StringPtr& other) const; | |
110 inline bool endsWith(const StringPtr& other) const; | |
111 | |
112 inline Maybe<size_t> findFirst(char c) const; | |
113 inline Maybe<size_t> findLast(char c) const; | |
114 | |
115 template <typename T> | |
116 T parseAs() const; | |
117 // Parse string as template number type. | |
118 // Integer numbers prefixed by "0x" and "0X" are parsed in base 16 (like strtoi with base 0). | |
119 // Integer numbers prefixed by "0" are parsed in base 10 (unlike strtoi with base 0). | |
120 // Overflowed integer numbers throw exception. | |
121 // Overflowed floating numbers return inf. | |
122 | |
123 private: | |
124 inline StringPtr(ArrayPtr<const char> content): content(content) {} | |
125 | |
126 ArrayPtr<const char> content; | |
127 }; | |
128 | |
129 inline bool operator==(const char* a, const StringPtr& b) { return b == a; } | |
130 inline bool operator!=(const char* a, const StringPtr& b) { return b != a; } | |
131 | |
132 template <> char StringPtr::parseAs<char>() const; | |
133 template <> signed char StringPtr::parseAs<signed char>() const; | |
134 template <> unsigned char StringPtr::parseAs<unsigned char>() const; | |
135 template <> short StringPtr::parseAs<short>() const; | |
136 template <> unsigned short StringPtr::parseAs<unsigned short>() const; | |
137 template <> int StringPtr::parseAs<int>() const; | |
138 template <> unsigned StringPtr::parseAs<unsigned>() const; | |
139 template <> long StringPtr::parseAs<long>() const; | |
140 template <> unsigned long StringPtr::parseAs<unsigned long>() const; | |
141 template <> long long StringPtr::parseAs<long long>() const; | |
142 template <> unsigned long long StringPtr::parseAs<unsigned long long>() const; | |
143 template <> float StringPtr::parseAs<float>() const; | |
144 template <> double StringPtr::parseAs<double>() const; | |
145 | |
146 // ======================================================================================= | |
147 // String -- A NUL-terminated Array<char> containing UTF-8 text. | |
148 // | |
149 // NUL bytes are allowed to appear before the end of the string. The only requirement is that | |
150 // a NUL byte appear immediately after the last byte of the content. This terminator byte is not | |
151 // counted in the string's size. | |
152 // | |
153 // To allocate a String, you must call kj::heapString(). We do not implement implicit copying to | |
154 // the heap because this hides potential inefficiency from the developer. | |
155 | |
156 class String { | |
157 public: | |
158 String() = default; | |
159 inline String(decltype(nullptr)): content(nullptr) {} | |
160 inline String(char* value, size_t size, const ArrayDisposer& disposer); | |
161 // Does not copy. `size` does not include NUL terminator, but `value` must be NUL-terminated. | |
162 inline explicit String(Array<char> buffer); | |
163 // Does not copy. Requires `buffer` ends with `\0`. | |
164 | |
165 inline operator ArrayPtr<char>(); | |
166 inline operator ArrayPtr<const char>() const; | |
167 inline ArrayPtr<char> asArray(); | |
168 inline ArrayPtr<const char> asArray() const; | |
169 inline ArrayPtr<byte> asBytes() { return asArray().asBytes(); } | |
170 inline ArrayPtr<const byte> asBytes() const { return asArray().asBytes(); } | |
171 // Result does not include NUL terminator. | |
172 | |
173 inline const char* cStr() const; | |
174 | |
175 inline size_t size() const; | |
176 // Result does not include NUL terminator. | |
177 | |
178 inline char operator[](size_t index) const; | |
179 inline char& operator[](size_t index); | |
180 | |
181 inline char* begin(); | |
182 inline char* end(); | |
183 inline const char* begin() const; | |
184 inline const char* end() const; | |
185 | |
186 inline bool operator==(decltype(nullptr)) const { return content.size() <= 1; } | |
187 inline bool operator!=(decltype(nullptr)) const { return content.size() > 1; } | |
188 | |
189 inline bool operator==(const StringPtr& other) const { return StringPtr(*this) == other; } | |
190 inline bool operator!=(const StringPtr& other) const { return StringPtr(*this) != other; } | |
191 inline bool operator< (const StringPtr& other) const { return StringPtr(*this) < other; } | |
192 inline bool operator> (const StringPtr& other) const { return StringPtr(*this) > other; } | |
193 inline bool operator<=(const StringPtr& other) const { return StringPtr(*this) <= other; } | |
194 inline bool operator>=(const StringPtr& other) const { return StringPtr(*this) >= other; } | |
195 | |
196 inline bool startsWith(const StringPtr& other) const { return StringPtr(*this).startsWith(other);} | |
197 inline bool endsWith(const StringPtr& other) const { return StringPtr(*this).endsWith(other); } | |
198 | |
199 inline StringPtr slice(size_t start) const { return StringPtr(*this).slice(start); } | |
200 inline ArrayPtr<const char> slice(size_t start, size_t end) const { | |
201 return StringPtr(*this).slice(start, end); | |
202 } | |
203 | |
204 inline Maybe<size_t> findFirst(char c) const { return StringPtr(*this).findFirst(c); } | |
205 inline Maybe<size_t> findLast(char c) const { return StringPtr(*this).findLast(c); } | |
206 | |
207 template <typename T> | |
208 T parseAs() const { return StringPtr(*this).parseAs<T>(); } | |
209 // Parse as number | |
210 | |
211 private: | |
212 Array<char> content; | |
213 }; | |
214 | |
215 inline bool operator==(const char* a, const String& b) { return b == a; } | |
216 inline bool operator!=(const char* a, const String& b) { return b != a; } | |
217 | |
218 String heapString(size_t size); | |
219 // Allocate a String of the given size on the heap, not including NUL terminator. The NUL | |
220 // terminator will be initialized automatically but the rest of the content is not initialized. | |
221 | |
222 String heapString(const char* value); | |
223 String heapString(const char* value, size_t size); | |
224 String heapString(StringPtr value); | |
225 String heapString(const String& value); | |
226 String heapString(ArrayPtr<const char> value); | |
227 // Allocates a copy of the given value on the heap. | |
228 | |
229 // ======================================================================================= | |
230 // Magic str() function which transforms parameters to text and concatenates them into one big | |
231 // String. | |
232 | |
233 namespace _ { // private | |
234 | |
235 inline size_t sum(std::initializer_list<size_t> nums) { | |
236 size_t result = 0; | |
237 for (auto num: nums) { | |
238 result += num; | |
239 } | |
240 return result; | |
241 } | |
242 | |
243 inline char* fill(char* ptr) { return ptr; } | |
244 | |
245 template <typename... Rest> | |
246 char* fill(char* __restrict__ target, const StringTree& first, Rest&&... rest); | |
247 // Make str() work with stringifiers that return StringTree by patching fill(). | |
248 // | |
249 // Defined in string-tree.h. | |
250 | |
251 template <typename First, typename... Rest> | |
252 char* fill(char* __restrict__ target, const First& first, Rest&&... rest) { | |
253 auto i = first.begin(); | |
254 auto end = first.end(); | |
255 while (i != end) { | |
256 *target++ = *i++; | |
257 } | |
258 return fill(target, kj::fwd<Rest>(rest)...); | |
259 } | |
260 | |
261 template <typename... Params> | |
262 String concat(Params&&... params) { | |
263 // Concatenate a bunch of containers into a single Array. The containers can be anything that | |
264 // is iterable and whose elements can be converted to `char`. | |
265 | |
266 String result = heapString(sum({params.size()...})); | |
267 fill(result.begin(), kj::fwd<Params>(params)...); | |
268 return result; | |
269 } | |
270 | |
271 inline String concat(String&& arr) { | |
272 return kj::mv(arr); | |
273 } | |
274 | |
275 struct Stringifier { | |
276 // This is a dummy type with only one instance: STR (below). To make an arbitrary type | |
277 // stringifiable, define `operator*(Stringifier, T)` to return an iterable container of `char`. | |
278 // The container type must have a `size()` method. Be sure to declare the operator in the same | |
279 // namespace as `T` **or** in the global scope. | |
280 // | |
281 // A more usual way to accomplish what we're doing here would be to require that you define | |
282 // a function like `toString(T)` and then rely on argument-dependent lookup. However, this has | |
283 // the problem that it pollutes other people's namespaces and even the global namespace. For | |
284 // example, some other project may already have functions called `toString` which do something | |
285 // different. Declaring `operator*` with `Stringifier` as the left operand cannot conflict with | |
286 // anything. | |
287 | |
288 inline ArrayPtr<const char> operator*(ArrayPtr<const char> s) const { return s; } | |
289 inline ArrayPtr<const char> operator*(ArrayPtr<char> s) const { return s; } | |
290 inline ArrayPtr<const char> operator*(const Array<const char>& s) const { return s; } | |
291 inline ArrayPtr<const char> operator*(const Array<char>& s) const { return s; } | |
292 template<size_t n> | |
293 inline ArrayPtr<const char> operator*(const CappedArray<char, n>& s) const { return s; } | |
294 template<size_t n> | |
295 inline ArrayPtr<const char> operator*(const FixedArray<char, n>& s) const { return s; } | |
296 inline ArrayPtr<const char> operator*(const char* s) const { return arrayPtr(s, strlen(s)); } | |
297 inline ArrayPtr<const char> operator*(const String& s) const { return s.asArray(); } | |
298 inline ArrayPtr<const char> operator*(const StringPtr& s) const { return s.asArray(); } | |
299 | |
300 inline Range<char> operator*(const Range<char>& r) const { return r; } | |
301 inline Repeat<char> operator*(const Repeat<char>& r) const { return r; } | |
302 | |
303 inline FixedArray<char, 1> operator*(char c) const { | |
304 FixedArray<char, 1> result; | |
305 result[0] = c; | |
306 return result; | |
307 } | |
308 | |
309 StringPtr operator*(decltype(nullptr)) const; | |
310 StringPtr operator*(bool b) const; | |
311 | |
312 CappedArray<char, 5> operator*(signed char i) const; | |
313 CappedArray<char, 5> operator*(unsigned char i) const; | |
314 CappedArray<char, sizeof(short) * 3 + 2> operator*(short i) const; | |
315 CappedArray<char, sizeof(unsigned short) * 3 + 2> operator*(unsigned short i) const; | |
316 CappedArray<char, sizeof(int) * 3 + 2> operator*(int i) const; | |
317 CappedArray<char, sizeof(unsigned int) * 3 + 2> operator*(unsigned int i) const; | |
318 CappedArray<char, sizeof(long) * 3 + 2> operator*(long i) const; | |
319 CappedArray<char, sizeof(unsigned long) * 3 + 2> operator*(unsigned long i) const; | |
320 CappedArray<char, sizeof(long long) * 3 + 2> operator*(long long i) const; | |
321 CappedArray<char, sizeof(unsigned long long) * 3 + 2> operator*(unsigned long long i) const; | |
322 CappedArray<char, 24> operator*(float f) const; | |
323 CappedArray<char, 32> operator*(double f) const; | |
324 CappedArray<char, sizeof(const void*) * 3 + 2> operator*(const void* s) const; | |
325 | |
326 template <typename T> | |
327 String operator*(ArrayPtr<T> arr) const; | |
328 template <typename T> | |
329 String operator*(const Array<T>& arr) const; | |
330 | |
331 #if KJ_COMPILER_SUPPORTS_STL_STRING_INTEROP // supports expression SFINAE? | |
332 template <typename T, typename Result = decltype(instance<T>().toString())> | |
333 inline Result operator*(T&& value) const { return kj::fwd<T>(value).toString(); } | |
334 #endif | |
335 }; | |
336 static KJ_CONSTEXPR(const) Stringifier STR = Stringifier(); | |
337 | |
338 } // namespace _ (private) | |
339 | |
340 template <typename T> | |
341 auto toCharSequence(T&& value) -> decltype(_::STR * kj::fwd<T>(value)) { | |
342 // Returns an iterable of chars that represent a textual representation of the value, suitable | |
343 // for debugging. | |
344 // | |
345 // Most users should use str() instead, but toCharSequence() may occasionally be useful to avoid | |
346 // heap allocation overhead that str() implies. | |
347 // | |
348 // To specialize this function for your type, see KJ_STRINGIFY. | |
349 | |
350 return _::STR * kj::fwd<T>(value); | |
351 } | |
352 | |
353 CappedArray<char, sizeof(unsigned char) * 2 + 1> hex(unsigned char i); | |
354 CappedArray<char, sizeof(unsigned short) * 2 + 1> hex(unsigned short i); | |
355 CappedArray<char, sizeof(unsigned int) * 2 + 1> hex(unsigned int i); | |
356 CappedArray<char, sizeof(unsigned long) * 2 + 1> hex(unsigned long i); | |
357 CappedArray<char, sizeof(unsigned long long) * 2 + 1> hex(unsigned long long i); | |
358 | |
359 template <typename... Params> | |
360 String str(Params&&... params) { | |
361 // Magic function which builds a string from a bunch of arbitrary values. Example: | |
362 // str(1, " / ", 2, " = ", 0.5) | |
363 // returns: | |
364 // "1 / 2 = 0.5" | |
365 // To teach `str` how to stringify a type, see `Stringifier`. | |
366 | |
367 return _::concat(toCharSequence(kj::fwd<Params>(params))...); | |
368 } | |
369 | |
370 inline String str(String&& s) { return mv(s); } | |
371 // Overload to prevent redundant allocation. | |
372 | |
373 template <typename T> | |
374 String strArray(T&& arr, const char* delim) { | |
375 size_t delimLen = strlen(delim); | |
376 KJ_STACK_ARRAY(decltype(_::STR * arr[0]), pieces, kj::size(arr), 8, 32); | |
377 size_t size = 0; | |
378 for (size_t i = 0; i < kj::size(arr); i++) { | |
379 if (i > 0) size += delimLen; | |
380 pieces[i] = _::STR * arr[i]; | |
381 size += pieces[i].size(); | |
382 } | |
383 | |
384 String result = heapString(size); | |
385 char* pos = result.begin(); | |
386 for (size_t i = 0; i < kj::size(arr); i++) { | |
387 if (i > 0) { | |
388 memcpy(pos, delim, delimLen); | |
389 pos += delimLen; | |
390 } | |
391 pos = _::fill(pos, pieces[i]); | |
392 } | |
393 return result; | |
394 } | |
395 | |
396 namespace _ { // private | |
397 | |
398 template <typename T> | |
399 inline String Stringifier::operator*(ArrayPtr<T> arr) const { | |
400 return strArray(arr, ", "); | |
401 } | |
402 | |
403 template <typename T> | |
404 inline String Stringifier::operator*(const Array<T>& arr) const { | |
405 return strArray(arr, ", "); | |
406 } | |
407 | |
408 } // namespace _ (private) | |
409 | |
410 #define KJ_STRINGIFY(...) operator*(::kj::_::Stringifier, __VA_ARGS__) | |
411 // Defines a stringifier for a custom type. Example: | |
412 // | |
413 // class Foo {...}; | |
414 // inline StringPtr KJ_STRINGIFY(const Foo& foo) { return foo.name(); } | |
415 // | |
416 // This allows Foo to be passed to str(). | |
417 // | |
418 // The function should be declared either in the same namespace as the target type or in the global | |
419 // namespace. It can return any type which is an iterable container of chars. | |
420 | |
421 // ======================================================================================= | |
422 // Inline implementation details. | |
423 | |
424 inline StringPtr::StringPtr(const String& value): content(value.begin(), value.size() + 1) {} | |
425 | |
426 inline StringPtr::operator ArrayPtr<const char>() const { | |
427 return content.slice(0, content.size() - 1); | |
428 } | |
429 | |
430 inline ArrayPtr<const char> StringPtr::asArray() const { | |
431 return content.slice(0, content.size() - 1); | |
432 } | |
433 | |
434 inline bool StringPtr::operator==(const StringPtr& other) const { | |
435 return content.size() == other.content.size() && | |
436 memcmp(content.begin(), other.content.begin(), content.size() - 1) == 0; | |
437 } | |
438 | |
439 inline bool StringPtr::operator<(const StringPtr& other) const { | |
440 bool shorter = content.size() < other.content.size(); | |
441 int cmp = memcmp(content.begin(), other.content.begin(), | |
442 shorter ? content.size() : other.content.size()); | |
443 return cmp < 0 || (cmp == 0 && shorter); | |
444 } | |
445 | |
446 inline StringPtr StringPtr::slice(size_t start) const { | |
447 return StringPtr(content.slice(start, content.size())); | |
448 } | |
449 inline ArrayPtr<const char> StringPtr::slice(size_t start, size_t end) const { | |
450 return content.slice(start, end); | |
451 } | |
452 | |
453 inline bool StringPtr::startsWith(const StringPtr& other) const { | |
454 return other.content.size() <= content.size() && | |
455 memcmp(content.begin(), other.content.begin(), other.size()) == 0; | |
456 } | |
457 inline bool StringPtr::endsWith(const StringPtr& other) const { | |
458 return other.content.size() <= content.size() && | |
459 memcmp(end() - other.size(), other.content.begin(), other.size()) == 0; | |
460 } | |
461 | |
462 inline Maybe<size_t> StringPtr::findFirst(char c) const { | |
463 const char* pos = reinterpret_cast<const char*>(memchr(content.begin(), c, size())); | |
464 if (pos == nullptr) { | |
465 return nullptr; | |
466 } else { | |
467 return pos - content.begin(); | |
468 } | |
469 } | |
470 | |
471 inline Maybe<size_t> StringPtr::findLast(char c) const { | |
472 for (size_t i = size(); i > 0; --i) { | |
473 if (content[i-1] == c) { | |
474 return i-1; | |
475 } | |
476 } | |
477 return nullptr; | |
478 } | |
479 | |
480 inline String::operator ArrayPtr<char>() { | |
481 return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1); | |
482 } | |
483 inline String::operator ArrayPtr<const char>() const { | |
484 return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1); | |
485 } | |
486 | |
487 inline ArrayPtr<char> String::asArray() { | |
488 return content == nullptr ? ArrayPtr<char>(nullptr) : content.slice(0, content.size() - 1); | |
489 } | |
490 inline ArrayPtr<const char> String::asArray() const { | |
491 return content == nullptr ? ArrayPtr<const char>(nullptr) : content.slice(0, content.size() - 1); | |
492 } | |
493 | |
494 inline const char* String::cStr() const { return content == nullptr ? "" : content.begin(); } | |
495 | |
496 inline size_t String::size() const { return content == nullptr ? 0 : content.size() - 1; } | |
497 | |
498 inline char String::operator[](size_t index) const { return content[index]; } | |
499 inline char& String::operator[](size_t index) { return content[index]; } | |
500 | |
501 inline char* String::begin() { return content == nullptr ? nullptr : content.begin(); } | |
502 inline char* String::end() { return content == nullptr ? nullptr : content.end() - 1; } | |
503 inline const char* String::begin() const { return content == nullptr ? nullptr : content.begin(); } | |
504 inline const char* String::end() const { return content == nullptr ? nullptr : content.end() - 1; } | |
505 | |
506 inline String::String(char* value, size_t size, const ArrayDisposer& disposer) | |
507 : content(value, size + 1, disposer) { | |
508 KJ_IREQUIRE(value[size] == '\0', "String must be NUL-terminated."); | |
509 } | |
510 | |
511 inline String::String(Array<char> buffer): content(kj::mv(buffer)) { | |
512 KJ_IREQUIRE(content.size() > 0 && content.back() == '\0', "String must be NUL-terminated."); | |
513 } | |
514 | |
515 inline String heapString(const char* value) { | |
516 return heapString(value, strlen(value)); | |
517 } | |
518 inline String heapString(StringPtr value) { | |
519 return heapString(value.begin(), value.size()); | |
520 } | |
521 inline String heapString(const String& value) { | |
522 return heapString(value.begin(), value.size()); | |
523 } | |
524 inline String heapString(ArrayPtr<const char> value) { | |
525 return heapString(value.begin(), value.size()); | |
526 } | |
527 | |
528 } // namespace kj | |
529 | |
530 #endif // KJ_STRING_H_ |