annotate win64-msvc/include/kj/array.h @ 59:cd4953afea46

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