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