All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
GrowableBuffer.h
Go to the documentation of this file.
1// BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/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
58 PRIMITIVE& operator[](size_t i) { return ptr_.get()[i]; }
59
62 Panel*
64 next_ = std::move(std::unique_ptr<Panel>(new Panel(reserved)));
65 return next_.get();
66 }
67
69 void
70 fill_panel(PRIMITIVE datum) {
71 ptr_.get()[length_++] = datum;
72 }
73
75 std::unique_ptr<Panel>&
76 next() {
77 return next_;
78 }
79
81 size_t
83 return length_;
84 }
85
87 size_t
89 return reserved_;
90 }
91
99 void
100 append(PRIMITIVE* to_ptr, size_t offset, size_t from, int64_t length) const noexcept {
101 memcpy(to_ptr + offset,
102 reinterpret_cast<void*>(ptr_.get() + from),
103 length * sizeof(PRIMITIVE) - from);
104 }
105
113 void
114 concatenate_to_from(PRIMITIVE* to_ptr, size_t offset, size_t from) const noexcept {
115 memcpy(to_ptr + offset,
116 reinterpret_cast<void*>(ptr_.get() + from),
117 length_ * sizeof(PRIMITIVE) - from);
118 if (next_) {
119 next_->concatenate_to(to_ptr, offset + length_);
120 }
121 }
122
129 void
130 concatenate_to(PRIMITIVE* to_ptr, size_t offset) const noexcept {
131 memcpy(to_ptr + offset,
132 reinterpret_cast<void*>(ptr_.get()),
133 length_ * sizeof(PRIMITIVE));
134 if (next_) {
135 next_->concatenate_to(to_ptr, offset + length_);
136 }
137 }
138
143 template <typename TO_PRIMITIVE>
144 typename std::enable_if<(!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
148 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
149 for (size_t i = 0; i < length_; i++) {
150 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i]);
151 }
152 if (next_) {
153 next_->copy_as(to_ptr, offset);
154 }
155 }
156
157 template <typename TO_PRIMITIVE>
158 typename std::enable_if<!awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
160 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
161 for (size_t i = 0; i < length_; i++) {
162 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].real());
163 to_ptr[offset++] = static_cast<TO_PRIMITIVE>(ptr_.get()[i].imag());
164 }
165 if (next_) {
166 next_->copy_as(to_ptr, offset);
167 }
168 }
169
175 template <typename TO_PRIMITIVE>
176 typename std::enable_if<awkward::is_tt<std::complex, TO_PRIMITIVE>::value &&
178 copy_as(TO_PRIMITIVE* to_ptr, size_t offset) {
179 for (size_t i = 0; i < length_; i++) {
180 double val = static_cast<double>(ptr_.get()[i]);
181 to_ptr[offset++] = TO_PRIMITIVE(val);
182 }
183 if (next_) {
184 next_->copy_as(to_ptr, offset);
185 }
186 }
187
188 private:
190 std::unique_ptr<PRIMITIVE[]> ptr_;
191
193 size_t length_;
194
196 size_t reserved_;
197
199 std::unique_ptr<Panel> next_;
200 };
201
216 template <typename PRIMITIVE>
218 public:
224 return empty(options, 0);
225 }
226
234 empty(const BuilderOptions& options, int64_t minreserve) {
235 int64_t actual = options.initial();
236 if (actual < minreserve) {
237 actual = minreserve;
238 }
239 return GrowableBuffer(
240 options,
241 std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]),
242 0,
243 actual);
244 }
245
256 int64_t actual = options.initial();
257 if (actual < length) {
258 actual = length;
259 }
260 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
261 PRIMITIVE* rawptr = ptr.get();
262 for (int64_t i = 0; i < length; i++) {
263 rawptr[i] = 0;
264 }
265 return GrowableBuffer(options, std::move(ptr), length, actual);
266 }
267
279 full(const BuilderOptions& options, PRIMITIVE value, int64_t length) {
280 int64_t actual = options.initial();
281 if (actual < length) {
282 actual = length;
283 }
284 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
285 PRIMITIVE* rawptr = ptr.get();
286 for (int64_t i = 0; i < length; i++) {
287 rawptr[i] = value;
288 }
289 return GrowableBuffer<PRIMITIVE>(options, std::move(ptr), length, actual);
290 }
291
303 int64_t actual = options.initial();
304 if (actual < length) {
305 actual = length;
306 }
307 auto ptr = std::unique_ptr<PRIMITIVE[]>(new PRIMITIVE[(size_t)actual]);
308 PRIMITIVE* rawptr = ptr.get();
309 for (int64_t i = 0; i < length; i++) {
310 rawptr[i] = (PRIMITIVE)i;
311 }
312 return GrowableBuffer(options, std::move(ptr), length, actual);
313 }
314
320 template <typename TO_PRIMITIVE>
323 int64_t len = (int64_t)other.length();
324 int64_t actual =
325 (len < other.options_.initial()) ? other.options_.initial() : len;
326
329 len *= 2;
330 actual *= 2;
331 }
332
333 auto ptr =
334 std::unique_ptr<TO_PRIMITIVE[]>(new TO_PRIMITIVE[(size_t)actual]);
335 TO_PRIMITIVE* rawptr = ptr.get();
336
337 other.panel_->copy_as(rawptr, 0);
338
340 BuilderOptions(actual, other.options().resize()),
341 std::move(ptr),
342 len,
343 actual);
344 }
345
357 std::unique_ptr<PRIMITIVE[]> ptr,
358 int64_t length,
359 int64_t reserved)
360 : options_(options),
361 length_(0),
362 panel_(std::unique_ptr<Panel<PRIMITIVE>>(new Panel<PRIMITIVE>(
363 std::move(ptr), (size_t)length, (size_t)reserved))),
364 ptr_(panel_.get()) {}
365
372 std::unique_ptr<PRIMITIVE[]>(
373 new PRIMITIVE[(size_t)options.initial()]),
374 0,
375 options.initial()) {}
376
381 : options_(other.options_),
382 length_(other.length_),
383 panel_(std::move(other.panel_)),
384 ptr_(other.ptr_) {}
385
391 size_t
392 length() const {
393 return length_ + ptr_->current_length();
394 }
395
397 const BuilderOptions&
398 options() const {
399 return options_;
400 }
401
404 void
406 panel_ = std::move(std::unique_ptr<Panel<PRIMITIVE>>(
407 new Panel<PRIMITIVE>((size_t)options_.initial())));
408 ptr_ = panel_.get();
409 }
410
412 PRIMITIVE
413 last() const {
414 if (ptr_->current_length() == 0) {
415 throw std::runtime_error("Buffer is empty");
416 } else {
417 return (*ptr_)[ptr_->current_length() - 1];
418 }
419 }
420
422 size_t
423 nbytes() const {
424 return length() * sizeof(PRIMITIVE);
425 }
426
432 void
433 append(PRIMITIVE datum) {
434 if (ptr_->current_length() == ptr_->reserved()) {
435 add_panel((size_t)ceil((double)ptr_->reserved() * (double)options_.resize()));
436 }
437 fill_panel(datum);
438 }
439
446 void
447 extend(const PRIMITIVE* ptr, size_t size) {
448 size_t unfilled_items = ptr_->reserved() - ptr_->current_length();
449 if (size > unfilled_items) {
450 for (size_t i = 0; i < unfilled_items; i++) {
451 fill_panel(ptr[i]);
452 }
453 add_panel(size - unfilled_items > ptr_->reserved() ? size - unfilled_items
454 : ptr_->reserved());
455 for (size_t i = unfilled_items; i < size; i++) {
456 fill_panel(ptr[i]);
457 }
458 } else {
459 for (size_t i = 0; i < size; i++) {
460 fill_panel(ptr[i]);
461 }
462 }
463 }
464
466 PRIMITIVE&
467 append_and_get_ref(PRIMITIVE datum) {
468 append(datum);
469 return (*ptr_)[ptr_->current_length() - 1];
470 }
471
474 void
475 concatenate(PRIMITIVE* external_pointer) const noexcept {
476 if (external_pointer) {
477 panel_->concatenate_to(external_pointer, 0);
478 }
479 }
480
483 void
484 concatenate_from(PRIMITIVE* external_pointer, size_t to, size_t from) const noexcept {
485 if (external_pointer) {
486 panel_->concatenate_to_from(external_pointer, to, from);
487 }
488 }
489
491 void
492 append(PRIMITIVE* external_pointer, size_t offset, size_t from, int64_t length) const noexcept {
493 if (external_pointer) {
494 panel_->append(external_pointer, offset, from, length);
495 }
496 }
497
498 private:
500 void
501 fill_panel(PRIMITIVE datum) {
502 ptr_->fill_panel(datum);
503 }
504
507 void
508 add_panel(size_t reserved) {
509 length_ += ptr_->current_length();
510 ptr_ = ptr_->append_panel(reserved);
511 }
512
514 const BuilderOptions options_;
515
517 size_t length_;
518
520 std::unique_ptr<Panel<PRIMITIVE>> panel_;
521
525 Panel<PRIMITIVE>* ptr_;
526 };
527} // namespace awkward
528
529#endif // AWKWARD_GROWABLEBUFFER_H_
Discontiguous, one-dimensional buffer (which consists of multiple contiguous, one-dimensional panels)...
Definition: GrowableBuffer.h:217
static GrowableBuffer< PRIMITIVE > zeros(const BuilderOptions &options, int64_t length)
Creates a GrowableBuffer in which all elements are initialized to 0.
Definition: GrowableBuffer.h:255
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:447
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:322
PRIMITIVE last() const
Last element in last panel.
Definition: GrowableBuffer.h:413
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:484
size_t nbytes() const
Currently used number of bytes.
Definition: GrowableBuffer.h:423
GrowableBuffer(GrowableBuffer &&other) noexcept
Move constructor.
Definition: GrowableBuffer.h:380
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:279
const BuilderOptions & options() const
Return options of this GrowableBuffer.
Definition: GrowableBuffer.h:398
void concatenate(PRIMITIVE *external_pointer) const noexcept
Copies and concatenates all accumulated data from multiple panels to one contiguously allocated exter...
Definition: GrowableBuffer.h:475
PRIMITIVE & append_and_get_ref(PRIMITIVE datum)
Like append, but the type signature returns the reference to PRIMITIVE.
Definition: GrowableBuffer.h:467
size_t length() const
Currently used number of elements.
Definition: GrowableBuffer.h:392
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options, int64_t minreserve)
Creates an empty GrowableBuffer with a minimum reservation.
Definition: GrowableBuffer.h:234
void append(PRIMITIVE datum)
Inserts one datum into the panel, possibly triggering allocation of a new panel.
Definition: GrowableBuffer.h:433
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:302
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:492
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:356
static GrowableBuffer< PRIMITIVE > empty(const BuilderOptions &options)
Creates an empty GrowableBuffer.
Definition: GrowableBuffer.h:223
void clear()
Discards accumulated data, the #reserved returns to options.initial(), and a new #ptr is allocated.
Definition: GrowableBuffer.h:405
GrowableBuffer(const BuilderOptions &options)
Creates a GrowableBuffer by allocating a new buffer, taking an options #reserved from options.
Definition: GrowableBuffer.h:370
Definition: GrowableBuffer.h:33
void fill_panel(PRIMITIVE datum)
Inserts one datum into the panel.
Definition: GrowableBuffer.h:70
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:63
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:82
std::unique_ptr< Panel > & next()
Pointer to the next panel.
Definition: GrowableBuffer.h:76
size_t reserved()
Currently allocated number of elements in the panel.
Definition: GrowableBuffer.h:88
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:178
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:100
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:114
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:160
Panel(size_t reserved)
Creates a Panel by allocating a new panel, taking a reserved number of slots.
Definition: GrowableBuffer.h:40
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:148
PRIMITIVE & operator[](size_t i)
Overloads [] operator to access elements like an array.
Definition: GrowableBuffer.h:58
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:130
int64_t len(const T &self)
Definition: content.h:24
Definition: ArrayBuilder.h:14
std::true_type is_tt_impl(TT< Args... >)
Options< int64_t, double > BuilderOptions
Definition: BuilderOptions.h:63
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:41
double resize() const noexcept
The factor with which a GrowableBuffer is resized when its length reaches its reserved.
Definition: BuilderOptions.h:49