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