annotate win32-mingw/include/kj/array.h @ 53:e1712f7d74a4

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