annotate win32-mingw/include/kj/array.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 eccd51b72864
children
rev   line source
Chris@64 1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
Chris@64 2 // Licensed under the MIT License:
Chris@64 3 //
Chris@64 4 // Permission is hereby granted, free of charge, to any person obtaining a copy
Chris@64 5 // of this software and associated documentation files (the "Software"), to deal
Chris@64 6 // in the Software without restriction, including without limitation the rights
Chris@64 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Chris@64 8 // copies of the Software, and to permit persons to whom the Software is
Chris@64 9 // furnished to do so, subject to the following conditions:
Chris@64 10 //
Chris@64 11 // The above copyright notice and this permission notice shall be included in
Chris@64 12 // all copies or substantial portions of the Software.
Chris@64 13 //
Chris@64 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Chris@64 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Chris@64 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Chris@64 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Chris@64 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Chris@64 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
Chris@64 20 // THE SOFTWARE.
Chris@64 21
Chris@64 22 #ifndef KJ_ARRAY_H_
Chris@64 23 #define KJ_ARRAY_H_
Chris@64 24
Chris@64 25 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
Chris@64 26 #pragma GCC system_header
Chris@64 27 #endif
Chris@64 28
Chris@64 29 #include "common.h"
Chris@64 30 #include <string.h>
Chris@64 31 #include <initializer_list>
Chris@64 32
Chris@64 33 namespace kj {
Chris@64 34
Chris@64 35 // =======================================================================================
Chris@64 36 // ArrayDisposer -- Implementation details.
Chris@64 37
Chris@64 38 class ArrayDisposer {
Chris@64 39 // Much like Disposer from memory.h.
Chris@64 40
Chris@64 41 protected:
Chris@64 42 // Do not declare a destructor, as doing so will force a global initializer for
Chris@64 43 // HeapArrayDisposer::instance.
Chris@64 44
Chris@64 45 virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
Chris@64 46 size_t capacity, void (*destroyElement)(void*)) const = 0;
Chris@64 47 // Disposes of the array. `destroyElement` invokes the destructor of each element, or is nullptr
Chris@64 48 // if the elements have trivial destructors. `capacity` is the amount of space that was
Chris@64 49 // allocated while `elementCount` is the number of elements that were actually constructed;
Chris@64 50 // these are always the same number for Array<T> but may be different when using ArrayBuilder<T>.
Chris@64 51
Chris@64 52 public:
Chris@64 53
Chris@64 54 template <typename T>
Chris@64 55 void dispose(T* firstElement, size_t elementCount, size_t capacity) const;
Chris@64 56 // Helper wrapper around disposeImpl().
Chris@64 57 //
Chris@64 58 // Callers must not call dispose() on the same array twice, even if the first call throws
Chris@64 59 // an exception.
Chris@64 60
Chris@64 61 private:
Chris@64 62 template <typename T, bool hasTrivialDestructor = __has_trivial_destructor(T)>
Chris@64 63 struct Dispose_;
Chris@64 64 };
Chris@64 65
Chris@64 66 class ExceptionSafeArrayUtil {
Chris@64 67 // Utility class that assists in constructing or destroying elements of an array, where the
Chris@64 68 // constructor or destructor could throw exceptions. In case of an exception,
Chris@64 69 // ExceptionSafeArrayUtil's destructor will call destructors on all elements that have been
Chris@64 70 // constructed but not destroyed. Remember that destructors that throw exceptions are required
Chris@64 71 // to use UnwindDetector to detect unwind and avoid exceptions in this case. Therefore, no more
Chris@64 72 // than one exception will be thrown (and the program will not terminate).
Chris@64 73
Chris@64 74 public:
Chris@64 75 inline ExceptionSafeArrayUtil(void* ptr, size_t elementSize, size_t constructedElementCount,
Chris@64 76 void (*destroyElement)(void*))
Chris@64 77 : pos(reinterpret_cast<byte*>(ptr) + elementSize * constructedElementCount),
Chris@64 78 elementSize(elementSize), constructedElementCount(constructedElementCount),
Chris@64 79 destroyElement(destroyElement) {}
Chris@64 80 KJ_DISALLOW_COPY(ExceptionSafeArrayUtil);
Chris@64 81
Chris@64 82 inline ~ExceptionSafeArrayUtil() noexcept(false) {
Chris@64 83 if (constructedElementCount > 0) destroyAll();
Chris@64 84 }
Chris@64 85
Chris@64 86 void construct(size_t count, void (*constructElement)(void*));
Chris@64 87 // Construct the given number of elements.
Chris@64 88
Chris@64 89 void destroyAll();
Chris@64 90 // Destroy all elements. Call this immediately before ExceptionSafeArrayUtil goes out-of-scope
Chris@64 91 // to ensure that one element throwing an exception does not prevent the others from being
Chris@64 92 // destroyed.
Chris@64 93
Chris@64 94 void release() { constructedElementCount = 0; }
Chris@64 95 // Prevent ExceptionSafeArrayUtil's destructor from destroying the constructed elements.
Chris@64 96 // Call this after you've successfully finished constructing.
Chris@64 97
Chris@64 98 private:
Chris@64 99 byte* pos;
Chris@64 100 size_t elementSize;
Chris@64 101 size_t constructedElementCount;
Chris@64 102 void (*destroyElement)(void*);
Chris@64 103 };
Chris@64 104
Chris@64 105 class DestructorOnlyArrayDisposer: public ArrayDisposer {
Chris@64 106 public:
Chris@64 107 static const DestructorOnlyArrayDisposer instance;
Chris@64 108
Chris@64 109 void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
Chris@64 110 size_t capacity, void (*destroyElement)(void*)) const override;
Chris@64 111 };
Chris@64 112
Chris@64 113 class NullArrayDisposer: public ArrayDisposer {
Chris@64 114 // An ArrayDisposer that does nothing. Can be used to construct a fake Arrays that doesn't
Chris@64 115 // actually own its content.
Chris@64 116
Chris@64 117 public:
Chris@64 118 static const NullArrayDisposer instance;
Chris@64 119
Chris@64 120 void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
Chris@64 121 size_t capacity, void (*destroyElement)(void*)) const override;
Chris@64 122 };
Chris@64 123
Chris@64 124 // =======================================================================================
Chris@64 125 // Array
Chris@64 126
Chris@64 127 template <typename T>
Chris@64 128 class Array {
Chris@64 129 // An owned array which will automatically be disposed of (using an ArrayDisposer) in the
Chris@64 130 // destructor. Can be moved, but not copied. Much like Own<T>, but for arrays rather than
Chris@64 131 // single objects.
Chris@64 132
Chris@64 133 public:
Chris@64 134 inline Array(): ptr(nullptr), size_(0), disposer(nullptr) {}
Chris@64 135 inline Array(decltype(nullptr)): ptr(nullptr), size_(0), disposer(nullptr) {}
Chris@64 136 inline Array(Array&& other) noexcept
Chris@64 137 : ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
Chris@64 138 other.ptr = nullptr;
Chris@64 139 other.size_ = 0;
Chris@64 140 }
Chris@64 141 inline Array(Array<RemoveConstOrDisable<T>>&& other) noexcept
Chris@64 142 : ptr(other.ptr), size_(other.size_), disposer(other.disposer) {
Chris@64 143 other.ptr = nullptr;
Chris@64 144 other.size_ = 0;
Chris@64 145 }
Chris@64 146 inline Array(T* firstElement, size_t size, const ArrayDisposer& disposer)
Chris@64 147 : ptr(firstElement), size_(size), disposer(&disposer) {}
Chris@64 148
Chris@64 149 KJ_DISALLOW_COPY(Array);
Chris@64 150 inline ~Array() noexcept { dispose(); }
Chris@64 151
Chris@64 152 inline operator ArrayPtr<T>() {
Chris@64 153 return ArrayPtr<T>(ptr, size_);
Chris@64 154 }
Chris@64 155 inline operator ArrayPtr<const T>() const {
Chris@64 156 return ArrayPtr<T>(ptr, size_);
Chris@64 157 }
Chris@64 158 inline ArrayPtr<T> asPtr() {
Chris@64 159 return ArrayPtr<T>(ptr, size_);
Chris@64 160 }
Chris@64 161 inline ArrayPtr<const T> asPtr() const {
Chris@64 162 return ArrayPtr<T>(ptr, size_);
Chris@64 163 }
Chris@64 164
Chris@64 165 inline size_t size() const { return size_; }
Chris@64 166 inline T& operator[](size_t index) const {
Chris@64 167 KJ_IREQUIRE(index < size_, "Out-of-bounds Array access.");
Chris@64 168 return ptr[index];
Chris@64 169 }
Chris@64 170
Chris@64 171 inline const T* begin() const { return ptr; }
Chris@64 172 inline const T* end() const { return ptr + size_; }
Chris@64 173 inline const T& front() const { return *ptr; }
Chris@64 174 inline const T& back() const { return *(ptr + size_ - 1); }
Chris@64 175 inline T* begin() { return ptr; }
Chris@64 176 inline T* end() { return ptr + size_; }
Chris@64 177 inline T& front() { return *ptr; }
Chris@64 178 inline T& back() { return *(ptr + size_ - 1); }
Chris@64 179
Chris@64 180 inline ArrayPtr<T> slice(size_t start, size_t end) {
Chris@64 181 KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice().");
Chris@64 182 return ArrayPtr<T>(ptr + start, end - start);
Chris@64 183 }
Chris@64 184 inline ArrayPtr<const T> slice(size_t start, size_t end) const {
Chris@64 185 KJ_IREQUIRE(start <= end && end <= size_, "Out-of-bounds Array::slice().");
Chris@64 186 return ArrayPtr<const T>(ptr + start, end - start);
Chris@64 187 }
Chris@64 188
Chris@64 189 inline ArrayPtr<const byte> asBytes() const { return asPtr().asBytes(); }
Chris@64 190 inline ArrayPtr<PropagateConst<T, byte>> asBytes() { return asPtr().asBytes(); }
Chris@64 191 inline ArrayPtr<const char> asChars() const { return asPtr().asChars(); }
Chris@64 192 inline ArrayPtr<PropagateConst<T, char>> asChars() { return asPtr().asChars(); }
Chris@64 193
Chris@64 194 inline Array<PropagateConst<T, byte>> releaseAsBytes() {
Chris@64 195 // Like asBytes() but transfers ownership.
Chris@64 196 static_assert(sizeof(T) == sizeof(byte),
Chris@64 197 "releaseAsBytes() only possible on arrays with byte-size elements (e.g. chars).");
Chris@64 198 Array<PropagateConst<T, byte>> result(
Chris@64 199 reinterpret_cast<PropagateConst<T, byte>*>(ptr), size_, *disposer);
Chris@64 200 ptr = nullptr;
Chris@64 201 size_ = 0;
Chris@64 202 return result;
Chris@64 203 }
Chris@64 204 inline Array<PropagateConst<T, char>> releaseAsChars() {
Chris@64 205 // Like asChars() but transfers ownership.
Chris@64 206 static_assert(sizeof(T) == sizeof(PropagateConst<T, char>),
Chris@64 207 "releaseAsChars() only possible on arrays with char-size elements (e.g. bytes).");
Chris@64 208 Array<PropagateConst<T, char>> result(
Chris@64 209 reinterpret_cast<PropagateConst<T, char>*>(ptr), size_, *disposer);
Chris@64 210 ptr = nullptr;
Chris@64 211 size_ = 0;
Chris@64 212 return result;
Chris@64 213 }
Chris@64 214
Chris@64 215 inline bool operator==(decltype(nullptr)) const { return size_ == 0; }
Chris@64 216 inline bool operator!=(decltype(nullptr)) const { return size_ != 0; }
Chris@64 217
Chris@64 218 inline Array& operator=(decltype(nullptr)) {
Chris@64 219 dispose();
Chris@64 220 return *this;
Chris@64 221 }
Chris@64 222
Chris@64 223 inline Array& operator=(Array&& other) {
Chris@64 224 dispose();
Chris@64 225 ptr = other.ptr;
Chris@64 226 size_ = other.size_;
Chris@64 227 disposer = other.disposer;
Chris@64 228 other.ptr = nullptr;
Chris@64 229 other.size_ = 0;
Chris@64 230 return *this;
Chris@64 231 }
Chris@64 232
Chris@64 233 private:
Chris@64 234 T* ptr;
Chris@64 235 size_t size_;
Chris@64 236 const ArrayDisposer* disposer;
Chris@64 237
Chris@64 238 inline void dispose() {
Chris@64 239 // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
Chris@64 240 // dispose again.
Chris@64 241 T* ptrCopy = ptr;
Chris@64 242 size_t sizeCopy = size_;
Chris@64 243 if (ptrCopy != nullptr) {
Chris@64 244 ptr = nullptr;
Chris@64 245 size_ = 0;
Chris@64 246 disposer->dispose(ptrCopy, sizeCopy, sizeCopy);
Chris@64 247 }
Chris@64 248 }
Chris@64 249
Chris@64 250 template <typename U>
Chris@64 251 friend class Array;
Chris@64 252 };
Chris@64 253
Chris@64 254 static_assert(!canMemcpy<Array<char>>(), "canMemcpy<>() is broken");
Chris@64 255
Chris@64 256 namespace _ { // private
Chris@64 257
Chris@64 258 class HeapArrayDisposer final: public ArrayDisposer {
Chris@64 259 public:
Chris@64 260 template <typename T>
Chris@64 261 static T* allocate(size_t count);
Chris@64 262 template <typename T>
Chris@64 263 static T* allocateUninitialized(size_t count);
Chris@64 264
Chris@64 265 static const HeapArrayDisposer instance;
Chris@64 266
Chris@64 267 private:
Chris@64 268 static void* allocateImpl(size_t elementSize, size_t elementCount, size_t capacity,
Chris@64 269 void (*constructElement)(void*), void (*destroyElement)(void*));
Chris@64 270 // Allocates and constructs the array. Both function pointers are null if the constructor is
Chris@64 271 // trivial, otherwise destroyElement is null if the constructor doesn't throw.
Chris@64 272
Chris@64 273 virtual void disposeImpl(void* firstElement, size_t elementSize, size_t elementCount,
Chris@64 274 size_t capacity, void (*destroyElement)(void*)) const override;
Chris@64 275
Chris@64 276 template <typename T, bool hasTrivialConstructor = __has_trivial_constructor(T),
Chris@64 277 bool hasNothrowConstructor = __has_nothrow_constructor(T)>
Chris@64 278 struct Allocate_;
Chris@64 279 };
Chris@64 280
Chris@64 281 } // namespace _ (private)
Chris@64 282
Chris@64 283 template <typename T>
Chris@64 284 inline Array<T> heapArray(size_t size) {
Chris@64 285 // Much like `heap<T>()` from memory.h, allocates a new array on the heap.
Chris@64 286
Chris@64 287 return Array<T>(_::HeapArrayDisposer::allocate<T>(size), size,
Chris@64 288 _::HeapArrayDisposer::instance);
Chris@64 289 }
Chris@64 290
Chris@64 291 template <typename T> Array<T> heapArray(const T* content, size_t size);
Chris@64 292 template <typename T> Array<T> heapArray(ArrayPtr<T> content);
Chris@64 293 template <typename T> Array<T> heapArray(ArrayPtr<const T> content);
Chris@64 294 template <typename T, typename Iterator> Array<T> heapArray(Iterator begin, Iterator end);
Chris@64 295 template <typename T> Array<T> heapArray(std::initializer_list<T> init);
Chris@64 296 // Allocate a heap array containing a copy of the given content.
Chris@64 297
Chris@64 298 template <typename T, typename Container>
Chris@64 299 Array<T> heapArrayFromIterable(Container&& a) { return heapArray<T>(a.begin(), a.end()); }
Chris@64 300 template <typename T>
Chris@64 301 Array<T> heapArrayFromIterable(Array<T>&& a) { return mv(a); }
Chris@64 302
Chris@64 303 // =======================================================================================
Chris@64 304 // ArrayBuilder
Chris@64 305
Chris@64 306 template <typename T>
Chris@64 307 class ArrayBuilder {
Chris@64 308 // Class which lets you build an Array<T> specifying the exact constructor arguments for each
Chris@64 309 // element, rather than starting by default-constructing them.
Chris@64 310
Chris@64 311 public:
Chris@64 312 ArrayBuilder(): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
Chris@64 313 ArrayBuilder(decltype(nullptr)): ptr(nullptr), pos(nullptr), endPtr(nullptr) {}
Chris@64 314 explicit ArrayBuilder(RemoveConst<T>* firstElement, size_t capacity,
Chris@64 315 const ArrayDisposer& disposer)
Chris@64 316 : ptr(firstElement), pos(firstElement), endPtr(firstElement + capacity),
Chris@64 317 disposer(&disposer) {}
Chris@64 318 ArrayBuilder(ArrayBuilder&& other)
Chris@64 319 : ptr(other.ptr), pos(other.pos), endPtr(other.endPtr), disposer(other.disposer) {
Chris@64 320 other.ptr = nullptr;
Chris@64 321 other.pos = nullptr;
Chris@64 322 other.endPtr = nullptr;
Chris@64 323 }
Chris@64 324 KJ_DISALLOW_COPY(ArrayBuilder);
Chris@64 325 inline ~ArrayBuilder() noexcept(false) { dispose(); }
Chris@64 326
Chris@64 327 inline operator ArrayPtr<T>() {
Chris@64 328 return arrayPtr(ptr, pos);
Chris@64 329 }
Chris@64 330 inline operator ArrayPtr<const T>() const {
Chris@64 331 return arrayPtr(ptr, pos);
Chris@64 332 }
Chris@64 333 inline ArrayPtr<T> asPtr() {
Chris@64 334 return arrayPtr(ptr, pos);
Chris@64 335 }
Chris@64 336 inline ArrayPtr<const T> asPtr() const {
Chris@64 337 return arrayPtr(ptr, pos);
Chris@64 338 }
Chris@64 339
Chris@64 340 inline size_t size() const { return pos - ptr; }
Chris@64 341 inline size_t capacity() const { return endPtr - ptr; }
Chris@64 342 inline T& operator[](size_t index) const {
Chris@64 343 KJ_IREQUIRE(index < implicitCast<size_t>(pos - ptr), "Out-of-bounds Array access.");
Chris@64 344 return ptr[index];
Chris@64 345 }
Chris@64 346
Chris@64 347 inline const T* begin() const { return ptr; }
Chris@64 348 inline const T* end() const { return pos; }
Chris@64 349 inline const T& front() const { return *ptr; }
Chris@64 350 inline const T& back() const { return *(pos - 1); }
Chris@64 351 inline T* begin() { return ptr; }
Chris@64 352 inline T* end() { return pos; }
Chris@64 353 inline T& front() { return *ptr; }
Chris@64 354 inline T& back() { return *(pos - 1); }
Chris@64 355
Chris@64 356 ArrayBuilder& operator=(ArrayBuilder&& other) {
Chris@64 357 dispose();
Chris@64 358 ptr = other.ptr;
Chris@64 359 pos = other.pos;
Chris@64 360 endPtr = other.endPtr;
Chris@64 361 disposer = other.disposer;
Chris@64 362 other.ptr = nullptr;
Chris@64 363 other.pos = nullptr;
Chris@64 364 other.endPtr = nullptr;
Chris@64 365 return *this;
Chris@64 366 }
Chris@64 367 ArrayBuilder& operator=(decltype(nullptr)) {
Chris@64 368 dispose();
Chris@64 369 return *this;
Chris@64 370 }
Chris@64 371
Chris@64 372 template <typename... Params>
Chris@64 373 T& add(Params&&... params) {
Chris@64 374 KJ_IREQUIRE(pos < endPtr, "Added too many elements to ArrayBuilder.");
Chris@64 375 ctor(*pos, kj::fwd<Params>(params)...);
Chris@64 376 return *pos++;
Chris@64 377 }
Chris@64 378
Chris@64 379 template <typename Container>
Chris@64 380 void addAll(Container&& container) {
Chris@64 381 addAll<decltype(container.begin()), !isReference<Container>()>(
Chris@64 382 container.begin(), container.end());
Chris@64 383 }
Chris@64 384
Chris@64 385 template <typename Iterator, bool move = false>
Chris@64 386 void addAll(Iterator start, Iterator end);
Chris@64 387
Chris@64 388 void removeLast() {
Chris@64 389 KJ_IREQUIRE(pos > ptr, "No elements present to remove.");
Chris@64 390 kj::dtor(*--pos);
Chris@64 391 }
Chris@64 392
Chris@64 393 void truncate(size_t size) {
Chris@64 394 KJ_IREQUIRE(size <= this->size(), "can't use truncate() to expand");
Chris@64 395
Chris@64 396 T* target = ptr + size;
Chris@64 397 if (__has_trivial_destructor(T)) {
Chris@64 398 pos = target;
Chris@64 399 } else {
Chris@64 400 while (pos > target) {
Chris@64 401 kj::dtor(*--pos);
Chris@64 402 }
Chris@64 403 }
Chris@64 404 }
Chris@64 405
Chris@64 406 void resize(size_t size) {
Chris@64 407 KJ_IREQUIRE(size <= capacity(), "can't resize past capacity");
Chris@64 408
Chris@64 409 T* target = ptr + size;
Chris@64 410 if (target > pos) {
Chris@64 411 // expand
Chris@64 412 if (__has_trivial_constructor(T)) {
Chris@64 413 pos = target;
Chris@64 414 } else {
Chris@64 415 while (pos < target) {
Chris@64 416 kj::ctor(*pos++);
Chris@64 417 }
Chris@64 418 }
Chris@64 419 } else {
Chris@64 420 // truncate
Chris@64 421 if (__has_trivial_destructor(T)) {
Chris@64 422 pos = target;
Chris@64 423 } else {
Chris@64 424 while (pos > target) {
Chris@64 425 kj::dtor(*--pos);
Chris@64 426 }
Chris@64 427 }
Chris@64 428 }
Chris@64 429 }
Chris@64 430
Chris@64 431 Array<T> finish() {
Chris@64 432 // We could safely remove this check if we assume that the disposer implementation doesn't
Chris@64 433 // need to know the original capacity, as is thes case with HeapArrayDisposer since it uses
Chris@64 434 // operator new() or if we created a custom disposer for ArrayBuilder which stores the capacity
Chris@64 435 // in a prefix. But that would make it hard to write cleverer heap allocators, and anyway this
Chris@64 436 // check might catch bugs. Probably people should use Vector if they want to build arrays
Chris@64 437 // without knowing the final size in advance.
Chris@64 438 KJ_IREQUIRE(pos == endPtr, "ArrayBuilder::finish() called prematurely.");
Chris@64 439 Array<T> result(reinterpret_cast<T*>(ptr), pos - ptr, *disposer);
Chris@64 440 ptr = nullptr;
Chris@64 441 pos = nullptr;
Chris@64 442 endPtr = nullptr;
Chris@64 443 return result;
Chris@64 444 }
Chris@64 445
Chris@64 446 inline bool isFull() const {
Chris@64 447 return pos == endPtr;
Chris@64 448 }
Chris@64 449
Chris@64 450 private:
Chris@64 451 T* ptr;
Chris@64 452 RemoveConst<T>* pos;
Chris@64 453 T* endPtr;
Chris@64 454 const ArrayDisposer* disposer;
Chris@64 455
Chris@64 456 inline void dispose() {
Chris@64 457 // Make sure that if an exception is thrown, we are left with a null ptr, so we won't possibly
Chris@64 458 // dispose again.
Chris@64 459 T* ptrCopy = ptr;
Chris@64 460 T* posCopy = pos;
Chris@64 461 T* endCopy = endPtr;
Chris@64 462 if (ptrCopy != nullptr) {
Chris@64 463 ptr = nullptr;
Chris@64 464 pos = nullptr;
Chris@64 465 endPtr = nullptr;
Chris@64 466 disposer->dispose(ptrCopy, posCopy - ptrCopy, endCopy - ptrCopy);
Chris@64 467 }
Chris@64 468 }
Chris@64 469 };
Chris@64 470
Chris@64 471 template <typename T>
Chris@64 472 inline ArrayBuilder<T> heapArrayBuilder(size_t size) {
Chris@64 473 // Like `heapArray<T>()` but does not default-construct the elements. You must construct them
Chris@64 474 // manually by calling `add()`.
Chris@64 475
Chris@64 476 return ArrayBuilder<T>(_::HeapArrayDisposer::allocateUninitialized<RemoveConst<T>>(size),
Chris@64 477 size, _::HeapArrayDisposer::instance);
Chris@64 478 }
Chris@64 479
Chris@64 480 // =======================================================================================
Chris@64 481 // Inline Arrays
Chris@64 482
Chris@64 483 template <typename T, size_t fixedSize>
Chris@64 484 class FixedArray {
Chris@64 485 // A fixed-width array whose storage is allocated inline rather than on the heap.
Chris@64 486
Chris@64 487 public:
Chris@64 488 inline size_t size() const { return fixedSize; }
Chris@64 489 inline T* begin() { return content; }
Chris@64 490 inline T* end() { return content + fixedSize; }
Chris@64 491 inline const T* begin() const { return content; }
Chris@64 492 inline const T* end() const { return content + fixedSize; }
Chris@64 493
Chris@64 494 inline operator ArrayPtr<T>() {
Chris@64 495 return arrayPtr(content, fixedSize);
Chris@64 496 }
Chris@64 497 inline operator ArrayPtr<const T>() const {
Chris@64 498 return arrayPtr(content, fixedSize);
Chris@64 499 }
Chris@64 500
Chris@64 501 inline T& operator[](size_t index) { return content[index]; }
Chris@64 502 inline const T& operator[](size_t index) const { return content[index]; }
Chris@64 503
Chris@64 504 private:
Chris@64 505 T content[fixedSize];
Chris@64 506 };
Chris@64 507
Chris@64 508 template <typename T, size_t fixedSize>
Chris@64 509 class CappedArray {
Chris@64 510 // Like `FixedArray` but can be dynamically resized as long as the size does not exceed the limit
Chris@64 511 // specified by the template parameter.
Chris@64 512 //
Chris@64 513 // TODO(someday): Don't construct elements past currentSize?
Chris@64 514
Chris@64 515 public:
Chris@64 516 inline KJ_CONSTEXPR() CappedArray(): currentSize(fixedSize) {}
Chris@64 517 inline explicit constexpr CappedArray(size_t s): currentSize(s) {}
Chris@64 518
Chris@64 519 inline size_t size() const { return currentSize; }
Chris@64 520 inline void setSize(size_t s) { KJ_IREQUIRE(s <= fixedSize); currentSize = s; }
Chris@64 521 inline T* begin() { return content; }
Chris@64 522 inline T* end() { return content + currentSize; }
Chris@64 523 inline const T* begin() const { return content; }
Chris@64 524 inline const T* end() const { return content + currentSize; }
Chris@64 525
Chris@64 526 inline operator ArrayPtr<T>() {
Chris@64 527 return arrayPtr(content, currentSize);
Chris@64 528 }
Chris@64 529 inline operator ArrayPtr<const T>() const {
Chris@64 530 return arrayPtr(content, currentSize);
Chris@64 531 }
Chris@64 532
Chris@64 533 inline T& operator[](size_t index) { return content[index]; }
Chris@64 534 inline const T& operator[](size_t index) const { return content[index]; }
Chris@64 535
Chris@64 536 private:
Chris@64 537 size_t currentSize;
Chris@64 538 T content[fixedSize];
Chris@64 539 };
Chris@64 540
Chris@64 541 // =======================================================================================
Chris@64 542 // KJ_MAP
Chris@64 543
Chris@64 544 #define KJ_MAP(elementName, array) \
Chris@64 545 ::kj::_::Mapper<KJ_DECLTYPE_REF(array)>(array) * \
Chris@64 546 [&](typename ::kj::_::Mapper<KJ_DECLTYPE_REF(array)>::Element elementName)
Chris@64 547 // Applies some function to every element of an array, returning an Array of the results, with
Chris@64 548 // nice syntax. Example:
Chris@64 549 //
Chris@64 550 // StringPtr foo = "abcd";
Chris@64 551 // Array<char> bar = KJ_MAP(c, foo) -> char { return c + 1; };
Chris@64 552 // KJ_ASSERT(str(bar) == "bcde");
Chris@64 553
Chris@64 554 namespace _ { // private
Chris@64 555
Chris@64 556 template <typename T>
Chris@64 557 struct Mapper {
Chris@64 558 T array;
Chris@64 559 Mapper(T&& array): array(kj::fwd<T>(array)) {}
Chris@64 560 template <typename Func>
Chris@64 561 auto operator*(Func&& func) -> Array<decltype(func(*array.begin()))> {
Chris@64 562 auto builder = heapArrayBuilder<decltype(func(*array.begin()))>(array.size());
Chris@64 563 for (auto iter = array.begin(); iter != array.end(); ++iter) {
Chris@64 564 builder.add(func(*iter));
Chris@64 565 }
Chris@64 566 return builder.finish();
Chris@64 567 }
Chris@64 568 typedef decltype(*kj::instance<T>().begin()) Element;
Chris@64 569 };
Chris@64 570
Chris@64 571 template <typename T, size_t s>
Chris@64 572 struct Mapper<T(&)[s]> {
Chris@64 573 T* array;
Chris@64 574 Mapper(T* array): array(array) {}
Chris@64 575 template <typename Func>
Chris@64 576 auto operator*(Func&& func) -> Array<decltype(func(*array))> {
Chris@64 577 auto builder = heapArrayBuilder<decltype(func(*array))>(s);
Chris@64 578 for (size_t i = 0; i < s; i++) {
Chris@64 579 builder.add(func(array[i]));
Chris@64 580 }
Chris@64 581 return builder.finish();
Chris@64 582 }
Chris@64 583 typedef decltype(*array)& Element;
Chris@64 584 };
Chris@64 585
Chris@64 586 } // namespace _ (private)
Chris@64 587
Chris@64 588 // =======================================================================================
Chris@64 589 // Inline implementation details
Chris@64 590
Chris@64 591 template <typename T>
Chris@64 592 struct ArrayDisposer::Dispose_<T, true> {
Chris@64 593 static void dispose(T* firstElement, size_t elementCount, size_t capacity,
Chris@64 594 const ArrayDisposer& disposer) {
Chris@64 595 disposer.disposeImpl(const_cast<RemoveConst<T>*>(firstElement),
Chris@64 596 sizeof(T), elementCount, capacity, nullptr);
Chris@64 597 }
Chris@64 598 };
Chris@64 599 template <typename T>
Chris@64 600 struct ArrayDisposer::Dispose_<T, false> {
Chris@64 601 static void destruct(void* ptr) {
Chris@64 602 kj::dtor(*reinterpret_cast<T*>(ptr));
Chris@64 603 }
Chris@64 604
Chris@64 605 static void dispose(T* firstElement, size_t elementCount, size_t capacity,
Chris@64 606 const ArrayDisposer& disposer) {
Chris@64 607 disposer.disposeImpl(firstElement, sizeof(T), elementCount, capacity, &destruct);
Chris@64 608 }
Chris@64 609 };
Chris@64 610
Chris@64 611 template <typename T>
Chris@64 612 void ArrayDisposer::dispose(T* firstElement, size_t elementCount, size_t capacity) const {
Chris@64 613 Dispose_<T>::dispose(firstElement, elementCount, capacity, *this);
Chris@64 614 }
Chris@64 615
Chris@64 616 namespace _ { // private
Chris@64 617
Chris@64 618 template <typename T>
Chris@64 619 struct HeapArrayDisposer::Allocate_<T, true, true> {
Chris@64 620 static T* allocate(size_t elementCount, size_t capacity) {
Chris@64 621 return reinterpret_cast<T*>(allocateImpl(
Chris@64 622 sizeof(T), elementCount, capacity, nullptr, nullptr));
Chris@64 623 }
Chris@64 624 };
Chris@64 625 template <typename T>
Chris@64 626 struct HeapArrayDisposer::Allocate_<T, false, true> {
Chris@64 627 static void construct(void* ptr) {
Chris@64 628 kj::ctor(*reinterpret_cast<T*>(ptr));
Chris@64 629 }
Chris@64 630 static T* allocate(size_t elementCount, size_t capacity) {
Chris@64 631 return reinterpret_cast<T*>(allocateImpl(
Chris@64 632 sizeof(T), elementCount, capacity, &construct, nullptr));
Chris@64 633 }
Chris@64 634 };
Chris@64 635 template <typename T>
Chris@64 636 struct HeapArrayDisposer::Allocate_<T, false, false> {
Chris@64 637 static void construct(void* ptr) {
Chris@64 638 kj::ctor(*reinterpret_cast<T*>(ptr));
Chris@64 639 }
Chris@64 640 static void destruct(void* ptr) {
Chris@64 641 kj::dtor(*reinterpret_cast<T*>(ptr));
Chris@64 642 }
Chris@64 643 static T* allocate(size_t elementCount, size_t capacity) {
Chris@64 644 return reinterpret_cast<T*>(allocateImpl(
Chris@64 645 sizeof(T), elementCount, capacity, &construct, &destruct));
Chris@64 646 }
Chris@64 647 };
Chris@64 648
Chris@64 649 template <typename T>
Chris@64 650 T* HeapArrayDisposer::allocate(size_t count) {
Chris@64 651 return Allocate_<T>::allocate(count, count);
Chris@64 652 }
Chris@64 653
Chris@64 654 template <typename T>
Chris@64 655 T* HeapArrayDisposer::allocateUninitialized(size_t count) {
Chris@64 656 return Allocate_<T, true, true>::allocate(0, count);
Chris@64 657 }
Chris@64 658
Chris@64 659 template <typename Element, typename Iterator, bool move, bool = canMemcpy<Element>()>
Chris@64 660 struct CopyConstructArray_;
Chris@64 661
Chris@64 662 template <typename T, bool move>
Chris@64 663 struct CopyConstructArray_<T, T*, move, true> {
Chris@64 664 static inline T* apply(T* __restrict__ pos, T* start, T* end) {
Chris@64 665 memcpy(pos, start, reinterpret_cast<byte*>(end) - reinterpret_cast<byte*>(start));
Chris@64 666 return pos + (end - start);
Chris@64 667 }
Chris@64 668 };
Chris@64 669
Chris@64 670 template <typename T>
Chris@64 671 struct CopyConstructArray_<T, const T*, false, true> {
Chris@64 672 static inline T* apply(T* __restrict__ pos, const T* start, const T* end) {
Chris@64 673 memcpy(pos, start, reinterpret_cast<const byte*>(end) - reinterpret_cast<const byte*>(start));
Chris@64 674 return pos + (end - start);
Chris@64 675 }
Chris@64 676 };
Chris@64 677
Chris@64 678 template <typename T, typename Iterator, bool move>
Chris@64 679 struct CopyConstructArray_<T, Iterator, move, true> {
Chris@64 680 static inline T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
Chris@64 681 // Since both the copy constructor and assignment operator are trivial, we know that assignment
Chris@64 682 // is equivalent to copy-constructing. So we can make this case somewhat easier for the
Chris@64 683 // compiler to optimize.
Chris@64 684 while (start != end) {
Chris@64 685 *pos++ = *start++;
Chris@64 686 }
Chris@64 687 return pos;
Chris@64 688 }
Chris@64 689 };
Chris@64 690
Chris@64 691 template <typename T, typename Iterator>
Chris@64 692 struct CopyConstructArray_<T, Iterator, false, false> {
Chris@64 693 struct ExceptionGuard {
Chris@64 694 T* start;
Chris@64 695 T* pos;
Chris@64 696 inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {}
Chris@64 697 ~ExceptionGuard() noexcept(false) {
Chris@64 698 while (pos > start) {
Chris@64 699 dtor(*--pos);
Chris@64 700 }
Chris@64 701 }
Chris@64 702 };
Chris@64 703
Chris@64 704 static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
Chris@64 705 // Verify that T can be *implicitly* constructed from the source values.
Chris@64 706 if (false) implicitCast<T>(*start);
Chris@64 707
Chris@64 708 if (noexcept(T(*start))) {
Chris@64 709 while (start != end) {
Chris@64 710 ctor(*pos++, *start++);
Chris@64 711 }
Chris@64 712 return pos;
Chris@64 713 } else {
Chris@64 714 // Crap. This is complicated.
Chris@64 715 ExceptionGuard guard(pos);
Chris@64 716 while (start != end) {
Chris@64 717 ctor(*guard.pos, *start++);
Chris@64 718 ++guard.pos;
Chris@64 719 }
Chris@64 720 guard.start = guard.pos;
Chris@64 721 return guard.pos;
Chris@64 722 }
Chris@64 723 }
Chris@64 724 };
Chris@64 725
Chris@64 726 template <typename T, typename Iterator>
Chris@64 727 struct CopyConstructArray_<T, Iterator, true, false> {
Chris@64 728 // Actually move-construct.
Chris@64 729
Chris@64 730 struct ExceptionGuard {
Chris@64 731 T* start;
Chris@64 732 T* pos;
Chris@64 733 inline explicit ExceptionGuard(T* pos): start(pos), pos(pos) {}
Chris@64 734 ~ExceptionGuard() noexcept(false) {
Chris@64 735 while (pos > start) {
Chris@64 736 dtor(*--pos);
Chris@64 737 }
Chris@64 738 }
Chris@64 739 };
Chris@64 740
Chris@64 741 static T* apply(T* __restrict__ pos, Iterator start, Iterator end) {
Chris@64 742 // Verify that T can be *implicitly* constructed from the source values.
Chris@64 743 if (false) implicitCast<T>(kj::mv(*start));
Chris@64 744
Chris@64 745 if (noexcept(T(kj::mv(*start)))) {
Chris@64 746 while (start != end) {
Chris@64 747 ctor(*pos++, kj::mv(*start++));
Chris@64 748 }
Chris@64 749 return pos;
Chris@64 750 } else {
Chris@64 751 // Crap. This is complicated.
Chris@64 752 ExceptionGuard guard(pos);
Chris@64 753 while (start != end) {
Chris@64 754 ctor(*guard.pos, kj::mv(*start++));
Chris@64 755 ++guard.pos;
Chris@64 756 }
Chris@64 757 guard.start = guard.pos;
Chris@64 758 return guard.pos;
Chris@64 759 }
Chris@64 760 }
Chris@64 761 };
Chris@64 762
Chris@64 763 } // namespace _ (private)
Chris@64 764
Chris@64 765 template <typename T>
Chris@64 766 template <typename Iterator, bool move>
Chris@64 767 void ArrayBuilder<T>::addAll(Iterator start, Iterator end) {
Chris@64 768 pos = _::CopyConstructArray_<RemoveConst<T>, Decay<Iterator>, move>::apply(pos, start, end);
Chris@64 769 }
Chris@64 770
Chris@64 771 template <typename T>
Chris@64 772 Array<T> heapArray(const T* content, size_t size) {
Chris@64 773 ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
Chris@64 774 builder.addAll(content, content + size);
Chris@64 775 return builder.finish();
Chris@64 776 }
Chris@64 777
Chris@64 778 template <typename T>
Chris@64 779 Array<T> heapArray(T* content, size_t size) {
Chris@64 780 ArrayBuilder<T> builder = heapArrayBuilder<T>(size);
Chris@64 781 builder.addAll(content, content + size);
Chris@64 782 return builder.finish();
Chris@64 783 }
Chris@64 784
Chris@64 785 template <typename T>
Chris@64 786 Array<T> heapArray(ArrayPtr<T> content) {
Chris@64 787 ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
Chris@64 788 builder.addAll(content);
Chris@64 789 return builder.finish();
Chris@64 790 }
Chris@64 791
Chris@64 792 template <typename T>
Chris@64 793 Array<T> heapArray(ArrayPtr<const T> content) {
Chris@64 794 ArrayBuilder<T> builder = heapArrayBuilder<T>(content.size());
Chris@64 795 builder.addAll(content);
Chris@64 796 return builder.finish();
Chris@64 797 }
Chris@64 798
Chris@64 799 template <typename T, typename Iterator> Array<T>
Chris@64 800 heapArray(Iterator begin, Iterator end) {
Chris@64 801 ArrayBuilder<T> builder = heapArrayBuilder<T>(end - begin);
Chris@64 802 builder.addAll(begin, end);
Chris@64 803 return builder.finish();
Chris@64 804 }
Chris@64 805
Chris@64 806 template <typename T>
Chris@64 807 inline Array<T> heapArray(std::initializer_list<T> init) {
Chris@64 808 return heapArray<T>(init.begin(), init.end());
Chris@64 809 }
Chris@64 810
Chris@64 811 } // namespace kj
Chris@64 812
Chris@64 813 #endif // KJ_ARRAY_H_