Loading...
Searching...
No Matches
GrowableBuffer.h
Go to the documentation of this file.
1// BSD 3-Clause License; see https://github.com/scikit-hep/awkward/blob/main/LICENSE
2
3#ifndef AWKWARD_GROWABLEBUFFER_H_
4#define AWKWARD_GROWABLEBUFFER_H_
5
7
8#include <cstring>
9#include <vector>
10#include <memory>
11#include <numeric>
12#include <cmath>
13#include <complex>
14#include <iostream>
15#include <utility>
16#include <stdexcept>
17#include <stdint.h>
18
19namespace awkward {
20
21 template <template <class...> class TT, class... Args>
22 std::true_type is_tt_impl(TT<Args...>);
23 template <template <class...> class TT>
24 std::false_type is_tt_impl(...);
25
26 template <template <class...> class TT, class T>
27 using is_tt = decltype(is_tt_impl<TT>(std::declval<typename std::decay<T>::type>()));
28
29 template <typename PRIMITIVE>
33 class Panel {
34 public:
35
41 : ptr_(std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[reserved])),
42 length_(0),
43 reserved_(reserved),
44 next_(nullptr) {}
45
51 Panel(std::unique_ptr<PRIMITIVE[]> ptr, size_t length, size_t reserved)
52 : ptr_(std::move(ptr)),
53 length_(length),
54 reserved_(reserved),
55 next_(nullptr) {}
56
62 for (std::unique_ptr<Panel> current = std::move(next_);
63 current;
64 current = std::move(current->next_));
65 }
66
68 PRIMITIVE& operator[](size_t i) { return ptr_.get()[i]; }
69
72 Panel*
74 next_ = std::move(std::unique_ptr<Panel>(new Panel(reserved)));
75 return next_.get();
76 }
77
79 void
80 fill_panel(PRIMITIVE datum) {
81 ptr_.get()[length_++] = datum;
82 }
83
85 std::unique_ptr<Panel>&
86 next() {
87 return next_;
88 }
89
91 size_t
93 return length_;
94 }
95
97 size_t
99 return reserved_;
100 }
101
103 std::unique_ptr<PRIMITIVE[]>&
105 return ptr_;
106 }
107
115 void
116 append(PRIMITIVE* to_ptr, size_t offset, size_t from, int64_t length) const noexcept {
117 memcpy(to_ptr + offset,
118 reinterpret_cast<void*>(ptr_.get() + from),
119 length * sizeof(PRIMITIVE) - from);
120 }
121
129 void
130 concatenate_to_from(PRIMITIVE* to_ptr, size_t offset, size_t from) const noexcept {
131 memcpy(to_ptr + offset,
132 reinterpret_cast<void*>(ptr_.get() + from),
133 length_ * sizeof(PRIMITIVE) - from);
134 if (next_) {
135 next_->concatenate_to(to_ptr, offset + length_);
136 }
137 }
138
145 void
146 concatenate_to(PRIMITIVE* to_ptr, size_t offset) const noexcept {
147 memcpy(to_ptr + offset,
148 reinterpret_cast<void*>(ptr_.get()),
149 length_ * sizeof(PRIMITIVE));
150 if (next_) {
151 next_->concatenate_to(to_ptr, offset + length_);
152 }
153 }
154
159 template <typename TO_PRIMITIVE>
160 typename std::enable_if<(!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
164 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
165 for (size_t i = 0; i < length_; i++) {
166 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i]);
167 }
168 if (next_) {
169 next_->copy_as(to_ptr, offset);
170 }
171 }
172
173 template <typename TO_PRIMITIVE>
174 typename std::enable_if<!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
176 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
177 for (size_t i = 0; i < length_; i++) {
178 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].real());
179 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].imag());
180 }
181 if (next_) {
182 next_->copy_as(to_ptr, offset);
183 }
184 }
185
191 template <typename TO_PRIMITIVE>
192 typename std::enable_if<awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
194 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
195 for (size_t i = 0; i < length_; i++) {
196 double val = static_cast<double>(ptr_.get()[i]);
197 to_ptr[offset++] = TO_PRIMITIVE(val);
198 }
199 if (next_) {
200 next_->copy_as(to_ptr, offset);
201 }
202 }
203
204 private:
206 std::unique_ptr<PRIMITIVE[]> ptr_;
207
209 size_t length_;
210
212 size_t reserved_;
213
215 std::unique_ptr<Panel> next_;
216 };
217
232 template <typename PRIMITIVE>
234 public:
240 return empty(options, 0);
241 }
242
250 empty(const BuilderOptions& options, int64_t minreserve) {
251 int64_t actual = options.initial();
252 if (actual < minreserve) {
253 actual = minreserve;
254 }
255 return GrowableBuffer(
256 options,
257 std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]),
258 0,
259 actual);
260 }
261
272 int64_t actual = options.initial();
273 if (actual < length) {
274 actual = length;
275 }
276 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
277 PRIMITIVE* rawptr = ptr.get();
278 for (int64_t i = 0; i < length; i++) {
279 rawptr[i] = 0;
280 }
281 return GrowableBuffer(options, std::move(ptr), length, actual);
282 }
283
295 full(const BuilderOptions& options, PRIMITIVE value, int64_t length) {
296 int64_t actual = options.initial();
297 if (actual < length) {
298 actual = length;
299 }
300 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
301 PRIMITIVE* rawptr = ptr.get();
302 for (int64_t i = 0; i < length; i++) {
303 rawptr[i] = value;
304 }
305 return GrowableBuffer<PRIMITIVE>(options, std::move(ptr), length, actual);
306 }
307
319 int64_t actual = options.initial();
320 if (actual < length) {
321 actual = length;
322 }
323 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
324 PRIMITIVE* rawptr = ptr.get();
325 for (int64_t i = 0; i < length; i++) {
326 rawptr[i] = (PRIMITIVE)i;
327 }
328 return GrowableBuffer(options, std::move(ptr), length, actual);
329 }
330
336 template <typename TO_PRIMITIVE>
339 int64_t len = (int64_t)other.length();
340 int64_t actual =
341 (len < other.options_.initial()) ? other.options_.initial() : len;
342
345 len *= 2;
346 actual *= 2;
347 }
348
349 auto ptr =
350 std::unique_ptr<TO_PRIMITIVE[]>(new TO_PRIMITIVE[(size_t)actual]);
351 TO_PRIMITIVE* rawptr = ptr.get();
352
353 other.panel_->copy_as(rawptr, 0);
354
356 BuilderOptions(actual, other.options().resize()),
357 std::move(ptr),
358 len,
359 actual);
360 }
361
373 std::unique_ptr<PRIMITIVE[]> ptr,
374 int64_t length,
375 int64_t reserved)
376 : options_(options),
377 length_(0),
378 panel_(std::unique_ptr<Panel<PRIMITIVE>>(new Panel<PRIMITIVE>(
379 std::move(ptr), (size_t)length, (size_t)reserved))),
380 ptr_(panel_.get()) {}
381
388 std::unique_ptr<PRIMITIVE[]>(
389 new PRIMITIVE[(size_t)options.initial()]),
390 0,
391 options.initial()) {}
392
397 : options_(other.options_),
398 length_(other.length_),
399 panel_(std::move(other.panel_)),
400 ptr_(other.ptr_) {}
401
407 size_t
408 length() const {
409 return length_ + ptr_->current_length();
410 }
411
413 const BuilderOptions&
414 options() const {
415 return options_;
416 }
417
420 void
422 panel_ = std::move(std::unique_ptr<Panel<PRIMITIVE>>(
423 new Panel<PRIMITIVE>((size_t)options_.initial())));
424 ptr_ = panel_.get();
425 length_ = 0;
426 }
427
429 PRIMITIVE
430 last() const {
431 if (ptr_->current_length() == 0) {
432 throw std::runtime_error("Buffer is empty");
433 } else {
434 return (*ptr_)[ptr_->current_length() - 1];
435 }
436 }
437
439 size_t
440 nbytes() const {
441 return length() * sizeof(PRIMITIVE);
442 }
443
449 void
450 append(PRIMITIVE datum) {
451 if (ptr_->current_length() == ptr_->reserved()) {
452 add_panel((size_t)ceil(options_.initial() * options_.resize()));
453 }
454 fill_panel(datum);
455 }
456
463 void
464 extend(const PRIMITIVE* ptr, size_t size) {
465 size_t unfilled_items = ptr_->reserved() - ptr_->current_length();
466 if (size > unfilled_items) {
467 for (size_t i = 0; i < unfilled_items; i++) {
468 fill_panel(ptr[i]);
469 }
470 add_panel(size - unfilled_items > ptr_->reserved() ? size - unfilled_items
471 : ptr_->reserved());
472 for (size_t i = unfilled_items; i < size; i++) {
473 fill_panel(ptr[i]);
474 }
475 } else {
476 for (size_t i = 0; i < size; i++) {
477 fill_panel(ptr[i]);
478 }
479 }
480 }
481
483 PRIMITIVE&
484 append_and_get_ref(PRIMITIVE datum) {
485 append(datum);
486 return (*ptr_)[ptr_->current_length() - 1];
487 }
488
491 void
492 concatenate(PRIMITIVE* external_pointer) const noexcept {
493 if (external_pointer) {
494 panel_->concatenate_to(external_pointer, 0);
495 }
496 }
497
501 void
502 move_to(PRIMITIVE* to_ptr) noexcept {
503 size_t next_offset = 0;
504 while(panel_) {
505 memcpy(to_ptr + next_offset,
506 reinterpret_cast<void*>(panel_.get()->data().get()),
507 panel_.get()->current_length() * sizeof(PRIMITIVE));
508 next_offset += panel_.get()->current_length();
509 panel_ = std::move(panel_.get()->next());
510 }
511 clear();
512 }
513
516 void
517 concatenate_from(PRIMITIVE* external_pointer, size_t to, size_t from) const noexcept {
518 if (external_pointer) {
519 panel_->concatenate_to_from(external_pointer, to, from);
520 }
521 }
522
524 void
525 append(PRIMITIVE* external_pointer, size_t offset, size_t from, int64_t length) const noexcept {
526 if (external_pointer) {
527 panel_->append(external_pointer, offset, from, length);
528 }
529 }
530
531 private:
533 void
534 fill_panel(PRIMITIVE datum) {
535 ptr_->fill_panel(datum);
536 }
537
540 void
541 add_panel(size_t reserved) {
542 length_ += ptr_->current_length();
543 ptr_ = ptr_->append_panel(reserved);
544 }
545
547 const BuilderOptions options_;
548
550 size_t length_;
551
553 std::unique_ptr<Panel<PRIMITIVE>> panel_;
554
558 Panel<PRIMITIVE>* ptr_;
559 };
560} // namespace awkward
561
562#endif // AWKWARD_GROWABLEBUFFER_H_
Discontiguous, one-dimensional buffer (which consists of multiple contiguous, one-dimensional panels)...
Definition GrowableBuffer.h:233
static GrowableBuffer< PRIMITIVE > zeros(const BuilderOptions &options, int64_t length)
Creates a GrowableBuffer in which all elements are initialized to 0.
Definition GrowableBuffer.h:271
void extend(const PRIMITIVE *ptr, size_t size)
Inserts an entire array into the panel(s), possibly triggering allocation of a new panel.
Definition GrowableBuffer.h:464
static GrowableBuffer< TO_PRIMITIVE > copy_as(const GrowableBuffer< PRIMITIVE > &other)
Takes a (possibly multi-panels) GrowableBuffer<PRIMITIVE> and makes another (one panel) GrowableBuffe...
Definition GrowableBuffer.h:338
PRIMITIVE last() const
Last element in last panel.
Definition GrowableBuffer.h:430
void concatenate_from(PRIMITIVE *external_pointer, size_t to, size_t from) const noexcept
Copies and concatenates all accumulated data from multiple panels to one contiguously allocated exter...
Definition GrowableBuffer.h:517
size_t nbytes() const
Currently used number of bytes.
Definition GrowableBuffer.h:440
GrowableBuffer(GrowableBuffer &&other) noexcept
Move constructor.
Definition GrowableBuffer.h:396
static GrowableBuffer< PRIMITIVE > full(const BuilderOptions &options, PRIMITIVE value, int64_t length)
Creates a GrowableBuffer in which all elements are initialized to a given value.
Definition GrowableBuffer.h:295
const BuilderOptions & options() const
Return options of this GrowableBuffer.
Definition GrowableBuffer.h:414
void concatenate(PRIMITIVE *external_pointer) const noexcept
Copies and concatenates all accumulated data from multiple panels to one contiguously allocated exter...
Definition GrowableBuffer.h:492
PRIMITIVE & append_and_get_ref(PRIMITIVE datum)
Like append, but the type signature returns the reference to PRIMITIVE.
Definition GrowableBuffer.h:484
size_t length() const
Currently used number of elements.
Definition GrowableBuffer.h:408
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options, int64_t minreserve)
Creates an empty GrowableBuffer with a minimum reservation.
Definition GrowableBuffer.h:250
void append(PRIMITIVE datum)
Inserts one datum into the panel, possibly triggering allocation of a new panel.
Definition GrowableBuffer.h:450
static GrowableBuffer< PRIMITIVE > arange(const BuilderOptions &options, int64_t length)
Creates a GrowableBuffer in which the elements are initialized to numbers counting from 0 to length.
Definition GrowableBuffer.h:318
void append(PRIMITIVE *external_pointer, size_t offset, size_t from, int64_t length) const noexcept
Copies data from a panel to one contiguously allocated external_pointer.
Definition GrowableBuffer.h:525
GrowableBuffer(const BuilderOptions &options, std::unique_ptr< PRIMITIVE[]> ptr, int64_t length, int64_t reserved)
Creates a GrowableBuffer from a full set of parameters.
Definition GrowableBuffer.h:372
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options)
Creates an empty GrowableBuffer.
Definition GrowableBuffer.h:239
void clear()
Discards accumulated data, the #reserved returns to options.initial(), and a new #ptr is allocated.
Definition GrowableBuffer.h:421
void move_to(PRIMITIVE *to_ptr) noexcept
Moves all accumulated data from multiple panels to one contiguously allocated external_pointer....
Definition GrowableBuffer.h:502
GrowableBuffer(const BuilderOptions &options)
Creates a GrowableBuffer by allocating a new buffer, taking an options #reserved from options.
Definition GrowableBuffer.h:386
Definition GrowableBuffer.h:33
void fill_panel(PRIMITIVE datum)
Inserts one datum into the panel.
Definition GrowableBuffer.h:80
Panel * append_panel(size_t reserved)
Creates a new panel with slots equal to reserved and appends it after the current panel.
Definition GrowableBuffer.h:73
Panel(std::unique_ptr< PRIMITIVE[]> ptr, size_t length, size_t reserved)
Creates a Panel from a full set of parameters.
Definition GrowableBuffer.h:51
size_t current_length()
Currently used number of elements in the panel.
Definition GrowableBuffer.h:92
std::unique_ptr< Panel > & next()
Pointer to the next panel.
Definition GrowableBuffer.h:86
size_t reserved()
Currently allocated number of elements in the panel.
Definition GrowableBuffer.h:98
std::enable_if< awkward::is_tt< std::complex, TO_PRIMITIVE >::value &&!awkward::is_tt< std::complex, PRIMITIVE >::value >::type copy_as(TO_PRIMITIVE *to_ptr, size_t offset)
'copy_as' specialization of a 'std::complex' template type. Fills (one panel) GrowableBuffer<std::com...
Definition GrowableBuffer.h:194
void append(PRIMITIVE *to_ptr, size_t offset, size_t from, int64_t length) const noexcept
Copies the data from a panel to one contiguously allocated to_ptr.
Definition GrowableBuffer.h:116
~Panel()
Deletes a Panel.
Definition GrowableBuffer.h:61
std::enable_if<(!awkward::is_tt< std::complex, TO_PRIMITIVE >::value &&!awkward::is_tt< std::complex, PRIMITIVE >::value)||(awkward::is_tt< std::complex, TO_PRIMITIVE >::value &&awkward::is_tt< std::complex, PRIMITIVE >::value)>::typ copy_as)(TO_PRIMITIVE *to_ptr, size_t offset)
Fills (one panel) GrowableBuffer<TO_PRIMITIVE> with the elements of (possibly multi-panels) GrowableB...
Definition GrowableBuffer.h:164
std::unique_ptr< PRIMITIVE[]> & data()
Unique pointer to the panel data.
Definition GrowableBuffer.h:104
void concatenate_to_from(PRIMITIVE *to_ptr, size_t offset, size_t from) const noexcept
Copies and concatenates the accumulated data from multiple panels ptr_ to one contiguously allocated ...
Definition GrowableBuffer.h:130
std::enable_if<!awkward::is_tt< std::complex, TO_PRIMITIVE >::value &&awkward::is_tt< std::complex, PRIMITIVE >::value >::type copy_as(TO_PRIMITIVE *to_ptr, size_t offset)
Definition GrowableBuffer.h:176
Panel(size_t reserved)
Creates a Panel by allocating a new panel, taking a reserved number of slots.
Definition GrowableBuffer.h:40
PRIMITIVE & operator[](size_t i)
Overloads [] operator to access elements like an array.
Definition GrowableBuffer.h:68
void concatenate_to(PRIMITIVE *to_ptr, size_t offset) const noexcept
Copies and concatenates the accumulated data from multiple panels ptr_ to one contiguously allocated ...
Definition GrowableBuffer.h:146
Definition ArrayBuilder.h:14
std::true_type is_tt_impl(TT< Args... >)
Options< int64_t, double > BuilderOptions
Definition BuilderOptions.h:56
decltype(is_tt_impl< TT >(std::declval< typename std::decay< T >::type >())) is_tt
Definition GrowableBuffer.h:27
Container for all configuration options needed by ArrayBuilder, GrowableBuffer, LayoutBuilder and the...
Definition BuilderOptions.h:20
int64_t initial() const noexcept
The initial number of reserved entries for a GrowableBuffer.
Definition BuilderOptions.h:34
double resize() const noexcept
The factor with which a GrowableBuffer is resized when its length reaches its reserved.
Definition BuilderOptions.h:42