annotate osx/include/kj/array.h @ 49:3ab5a40c4e3b

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