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 <type_traits>
17#include <stdexcept>
18#include <stdint.h>
19
20namespace awkward {
21
22 template <template <class...> class TT, class... Args>
23 std::true_type is_tt_impl(TT<Args...>);
24 template <template <class...> class TT>
25 std::false_type is_tt_impl(...);
26
27 template <template <class...> class TT, class T>
28 using is_tt = decltype(is_tt_impl<TT>(std::declval<typename std::decay<T>::type>()));
29
30 template <typename PRIMITIVE>
34 class Panel {
35 public:
36
42 : ptr_(std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[reserved])),
43 length_(0),
44 reserved_(reserved),
45 next_(nullptr) {}
46
52 Panel(std::unique_ptr<PRIMITIVE[]> ptr, size_t length, size_t reserved)
53 : ptr_(std::move(ptr)),
54 length_(length),
55 reserved_(reserved),
56 next_(nullptr) {}
57
63 for (std::unique_ptr<Panel> current = std::move(next_);
64 current;
65 current = std::move(current->next_));
66 }
67
69 PRIMITIVE& operator[](size_t i) { return ptr_.get()[i]; }
70
73 Panel*
75 next_ = std::make_unique<Panel>(reserved);
76 return next_.get();
77 }
78
80 void
81 fill_panel(PRIMITIVE datum) {
82 ptr_.get()[length_++] = datum;
83 }
84
89 void
90 fill_panel_from(const PRIMITIVE* from_ptr, size_t size) {
91 if (std::is_trivially_copyable<PRIMITIVE>::value) {
92 memcpy(ptr_.get() + length_, from_ptr, size * sizeof(PRIMITIVE));
93 length_ += size;
94 } else {
95 for (size_t i = 0; i < size; i++) {
96 ptr_.get()[length_++] = from_ptr[i];
97 }
98 }
99 }
100
102 std::unique_ptr<Panel>&
104 return next_;
105 }
106
108 size_t
110 return length_;
111 }
112
114 size_t
116 return reserved_;
117 }
118
120 std::unique_ptr<PRIMITIVE[]>&
122 return ptr_;
123 }
124
132 void
133 append(PRIMITIVE* to_ptr, size_t offset, size_t from, int64_t length) const noexcept {
134 memcpy(to_ptr + offset,
135 reinterpret_cast<void*>(ptr_.get() + from),
136 length * sizeof(PRIMITIVE) - from);
137 }
138
146 void
147 concatenate_to_from(PRIMITIVE* to_ptr, size_t offset, size_t from) const noexcept {
148 memcpy(to_ptr + offset,
149 reinterpret_cast<void*>(ptr_.get() + from),
150 length_ * sizeof(PRIMITIVE) - from);
151 if (next_) {
152 next_->concatenate_to(to_ptr, offset + length_);
153 }
154 }
155
162 void
163 concatenate_to(PRIMITIVE* to_ptr, size_t offset) const noexcept {
164 memcpy(to_ptr + offset,
165 reinterpret_cast<void*>(ptr_.get()),
166 length_ * sizeof(PRIMITIVE));
167 if (next_) {
168 next_->concatenate_to(to_ptr, offset + length_);
169 }
170 }
171
176 template <typename TO_PRIMITIVE>
177 typename std::enable_if<(!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
181 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
182 for (size_t i = 0; i < length_; i++) {
183 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i]);
184 }
185 if (next_) {
186 next_->copy_as(to_ptr, offset);
187 }
188 }
189
190 template <typename TO_PRIMITIVE>
191 typename std::enable_if<!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
193 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
194 for (size_t i = 0; i < length_; i++) {
195 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].real());
196 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].imag());
197 }
198 if (next_) {
199 next_->copy_as(to_ptr, offset);
200 }
201 }
202
208 template <typename TO_PRIMITIVE>
209 typename std::enable_if<awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
211 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
212 for (size_t i = 0; i < length_; i++) {
213 double val = static_cast<double>(ptr_.get()[i]);
214 to_ptr[offset++] = TO_PRIMITIVE(val);
215 }
216 if (next_) {
217 next_->copy_as(to_ptr, offset);
218 }
219 }
220
221 private:
223 std::unique_ptr<PRIMITIVE[]> ptr_;
224
226 size_t length_;
227
229 size_t reserved_;
230
232 std::unique_ptr<Panel> next_;
233 };
234
249 template <typename PRIMITIVE>
251 public:
257 return empty(options, 0);
258 }
259
267 empty(const BuilderOptions& options, int64_t minreserve) {
268 int64_t actual = options.initial();
269 if (actual < minreserve) {
270 actual = minreserve;
271 }
272 return GrowableBuffer(
273 options,
274 std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]),
275 0,
276 actual);
277 }
278
289 int64_t actual = options.initial();
290 if (actual < length) {
291 actual = length;
292 }
293 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
294 PRIMITIVE* rawptr = ptr.get();
295 for (int64_t i = 0; i < length; i++) {
296 rawptr[i] = 0;
297 }
298 return GrowableBuffer(options, std::move(ptr), length, actual);
299 }
300
312 full(const BuilderOptions& options, PRIMITIVE value, int64_t length) {
313 int64_t actual = options.initial();
314 if (actual < length) {
315 actual = length;
316 }
317 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
318 PRIMITIVE* rawptr = ptr.get();
319 for (int64_t i = 0; i < length; i++) {
320 rawptr[i] = value;
321 }
322 return GrowableBuffer<PRIMITIVE>(options, std::move(ptr), length, actual);
323 }
324
336 int64_t actual = options.initial();
337 if (actual < length) {
338 actual = length;
339 }
340 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
341 PRIMITIVE* rawptr = ptr.get();
342 for (int64_t i = 0; i < length; i++) {
343 rawptr[i] = (PRIMITIVE)i;
344 }
345 return GrowableBuffer(options, std::move(ptr), length, actual);
346 }
347
353 template <typename TO_PRIMITIVE>
356 int64_t len = (int64_t)other.length();
357 int64_t actual =
358 (len < other.options_.initial()) ? other.options_.initial() : len;
359
362 len *= 2;
363 actual *= 2;
364 }
365
366 auto ptr =
367 std::unique_ptr<TO_PRIMITIVE[]>(new TO_PRIMITIVE[(size_t)actual]);
368 TO_PRIMITIVE* rawptr = ptr.get();
369
370 other.panel_->copy_as(rawptr, 0);
371
373 BuilderOptions(actual, other.options().resize()),
374 std::move(ptr),
375 len,
376 actual);
377 }
378
390 std::unique_ptr<PRIMITIVE[]> ptr,
391 int64_t length,
392 int64_t reserved)
393 : options_(options),
394 length_(0),
395 panel_(std::unique_ptr<Panel<PRIMITIVE>>(new Panel<PRIMITIVE>(
396 std::move(ptr), (size_t)length, (size_t)reserved))),
397 ptr_(panel_.get()) {}
398
405 std::unique_ptr<PRIMITIVE[]>(
406 new PRIMITIVE[(size_t)options.initial()]),
407 0,
408 options.initial()) {}
409
414 : options_(other.options_),
415 length_(other.length_),
416 panel_(std::move(other.panel_)),
417 ptr_(other.ptr_) {}
418
423 GrowableBuffer& operator=(GrowableBuffer&& other) noexcept = default;
424
430 size_t
431 length() const {
432 return length_ + ptr_->current_length();
433 }
434
436 const BuilderOptions&
437 options() const {
438 return options_;
439 }
440
443 void
445 panel_ = std::make_unique<Panel<PRIMITIVE>>((size_t)options_.initial());
446 ptr_ = panel_.get();
447 length_ = 0;
448 }
449
451 PRIMITIVE
452 last() const {
453 if (ptr_->current_length() == 0) {
454 throw std::runtime_error("Buffer is empty");
455 } else {
456 return (*ptr_)[ptr_->current_length() - 1];
457 }
458 }
459
461 size_t
462 nbytes() const {
463 return length() * sizeof(PRIMITIVE);
464 }
465
471 void
472 append(PRIMITIVE datum) {
473 if (ptr_->current_length() == ptr_->reserved()) {
474 add_panel((size_t)ceil((double)ptr_->reserved() * options_.resize()));
475 }
476 fill_panel(datum);
477 }
478
485 void
486 extend(const PRIMITIVE* ptr, size_t size) {
487 size_t unfilled_items = ptr_->reserved() - ptr_->current_length();
488 if (size > unfilled_items) {
489 fill_panel_from(ptr, unfilled_items);
490 add_panel(size - unfilled_items > ptr_->reserved() ? size - unfilled_items
491 : ptr_->reserved());
492 fill_panel_from(ptr + unfilled_items, size - unfilled_items);
493 } else {
494 fill_panel_from(ptr, size);
495 }
496 }
497
499 PRIMITIVE&
500 append_and_get_ref(PRIMITIVE datum) {
501 append(datum);
502 return (*ptr_)[ptr_->current_length() - 1];
503 }
504
507 void
508 concatenate(PRIMITIVE* external_pointer) const noexcept {
509 if (external_pointer) {
510 panel_->concatenate_to(external_pointer, 0);
511 }
512 }
513
517 void
518 move_to(PRIMITIVE* to_ptr) noexcept {
519 size_t next_offset = 0;
520 while(panel_) {
521 memcpy(to_ptr + next_offset,
522 reinterpret_cast<void*>(panel_.get()->data().get()),
523 panel_.get()->current_length() * sizeof(PRIMITIVE));
524 next_offset += panel_.get()->current_length();
525 panel_ = std::move(panel_.get()->next());
526 }
527 clear();
528 }
529
532 void
533 concatenate_from(PRIMITIVE* external_pointer, size_t to, size_t from) const noexcept {
534 if (external_pointer) {
535 panel_->concatenate_to_from(external_pointer, to, from);
536 }
537 }
538
540 void
541 append(PRIMITIVE* external_pointer, size_t offset, size_t from, int64_t length) const noexcept {
542 if (external_pointer) {
543 panel_->append(external_pointer, offset, from, length);
544 }
545 }
546
547 private:
549 void
550 fill_panel(PRIMITIVE datum) {
551 ptr_->fill_panel(datum);
552 }
553
556 void
557 fill_panel_from(const PRIMITIVE* from_ptr, size_t size) {
558 ptr_->fill_panel_from(from_ptr, size);
559 }
560
563 void
564 add_panel(size_t reserved) {
565 length_ += ptr_->current_length();
566 ptr_ = ptr_->append_panel(reserved);
567 }
568
570 BuilderOptions options_;
571
573 size_t length_;
574
576 std::unique_ptr<Panel<PRIMITIVE>> panel_;
577
581 Panel<PRIMITIVE>* ptr_;
582 };
583} // namespace awkward
584
585#endif // AWKWARD_GROWABLEBUFFER_H_
Discontiguous, one-dimensional buffer (which consists of multiple contiguous, one-dimensional panels)...
Definition GrowableBuffer.h:250
static GrowableBuffer< PRIMITIVE > zeros(const BuilderOptions &options, int64_t length)
Creates a GrowableBuffer in which all elements are initialized to 0.
Definition GrowableBuffer.h:288
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:486
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:355
PRIMITIVE last() const
Last element in last panel.
Definition GrowableBuffer.h:452
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:533
size_t nbytes() const
Currently used number of bytes.
Definition GrowableBuffer.h:462
GrowableBuffer(GrowableBuffer &&other) noexcept
Move constructor.
Definition GrowableBuffer.h:413
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:312
const BuilderOptions & options() const
Return options of this GrowableBuffer.
Definition GrowableBuffer.h:437
void concatenate(PRIMITIVE *external_pointer) const noexcept
Copies and concatenates all accumulated data from multiple panels to one contiguously allocated exter...
Definition GrowableBuffer.h:508
PRIMITIVE & append_and_get_ref(PRIMITIVE datum)
Like append, but the type signature returns the reference to PRIMITIVE.
Definition GrowableBuffer.h:500
size_t length() const
Currently used number of elements.
Definition GrowableBuffer.h:431
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options, int64_t minreserve)
Creates an empty GrowableBuffer with a minimum reservation.
Definition GrowableBuffer.h:267
GrowableBuffer & operator=(GrowableBuffer &&other) noexcept=default
Move assignment.
void append(PRIMITIVE datum)
Inserts one datum into the panel, possibly triggering allocation of a new panel.
Definition GrowableBuffer.h:472
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:335
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:541
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:389
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options)
Creates an empty GrowableBuffer.
Definition GrowableBuffer.h:256
void clear()
Discards accumulated data, the #reserved returns to options.initial(), and a new #ptr is allocated.
Definition GrowableBuffer.h:444
void move_to(PRIMITIVE *to_ptr) noexcept
Moves all accumulated data from multiple panels to one contiguously allocated external_pointer....
Definition GrowableBuffer.h:518
GrowableBuffer(const BuilderOptions &options)
Creates a GrowableBuffer by allocating a new buffer, taking an options #reserved from options.
Definition GrowableBuffer.h:403
Definition GrowableBuffer.h:34
void fill_panel(PRIMITIVE datum)
Inserts one datum into the panel.
Definition GrowableBuffer.h:81
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:74
Panel(std::unique_ptr< PRIMITIVE[]> ptr, size_t length, size_t reserved)
Creates a Panel from a full set of parameters.
Definition GrowableBuffer.h:52
size_t current_length()
Currently used number of elements in the panel.
Definition GrowableBuffer.h:109
std::unique_ptr< Panel > & next()
Pointer to the next panel.
Definition GrowableBuffer.h:103
size_t reserved()
Currently allocated number of elements in the panel.
Definition GrowableBuffer.h:115
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:211
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:133
~Panel()
Deletes a Panel.
Definition GrowableBuffer.h:62
std::unique_ptr< PRIMITIVE[]> & data()
Unique pointer to the panel data.
Definition GrowableBuffer.h:121
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:147
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:193
void fill_panel_from(const PRIMITIVE *from_ptr, size_t size)
Inserts a contiguous segment of size elements from from_ptr into the panel.
Definition GrowableBuffer.h:90
Panel(size_t reserved)
Creates a Panel by allocating a new panel, taking a reserved number of slots.
Definition GrowableBuffer.h:41
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)>::type 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:181
PRIMITIVE & operator[](size_t i)
Overloads [] operator to access elements like an array.
Definition GrowableBuffer.h:69
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:163
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:28
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