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