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