annotate win64-msvc/include/kj/string.h @ 83:ae30d91d2ffe

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