annotate win32-mingw/include/kj/array.h @ 140:59a8758c56b1

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