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