comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/include/kj/array.h @ 69:33d812a61356

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