Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_memArray.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
91#ifndef TPL_MEMARRAY_H
92#define TPL_MEMARRAY_H
93
94#include <utility>
95#include <cstdlib>
96#include <cmath>
97#include <limits>
98#include <stdexcept>
99
100#include <ah-errors.H>
101#include <ahUtils.H>
102#include <ahDry.H>
103#include <ahIterator.H>
104#include <array_it.H>
105#include <array_utils.H>
106
107namespace Aleph {
134template <typename T>
136{
137public:
138 static constexpr size_t Min_Dim = 4;
139
140protected:
141 T *ptr = nullptr;
142 size_t dim = Min_Dim;
143 size_t n = 0;
144
145public:
146 mutable size_t contract_threshold;
147
150 {
151 return ptr;
152 }
153
155 const size_t &get_dim() const noexcept
156 {
157 return dim;
158 }
159
160protected:
161 static size_t next_power_of_two(const size_t requested)
162 {
163 size_t ret = 1;
164 while (ret < requested)
165 {
166 ah_overflow_error_if(ret > (std::numeric_limits<size_t>::max() >> 1))
167 << "MemArray capacity overflow";
168 ret <<= 1;
169 }
170 return ret;
171 }
172
174 void allocate()
175 {
177 ptr = new T[dim];
179 }
180
192 bool expand(const size_t first = 0)
193 {
194 assert(ptr);
196 if (n < dim)
197 return false;
198
199 ah_overflow_error_if(dim > (std::numeric_limits<size_t>::max() >> 1))
200 << "MemArray::expand(): capacity overflow";
201 const size_t newsz = dim << 1; // 2*dim
202 const size_t mask = dim - 1;
203 // Value-initialize (not just default-initialize): for scalar T,
204 // `new T[newsz]` alone leaves every slot indeterminate, and the
205 // std::swap() below reads new_ptr[i] before this loop ever writes a
206 // real value into it -- an uninitialized-read even though the stale
207 // bits end up discarded a few lines later (Coverity CID 412651).
208 T *new_ptr = new T[newsz]();
209 for (size_t i = 0; i < dim; ++i)
210 {
211 assert(((i + first) & mask) == ((i + first) % dim));
212 std::swap(ptr[(i + first) & mask], new_ptr[i]);
213 }
214 delete[] ptr;
215 ptr = new_ptr;
216 dim = newsz;
218
219 return true;
220 }
221
232 bool contract(const size_t first = 0)
233 {
234 assert(ptr);
235 if (n > contract_threshold)
236 return false;
237
238 const size_t newsz = dim >> 1; // dim/2
239
240 if (newsz <= Min_Dim)
241 return false;
242
243 // Same rationale as expand(): value-initialize so the std::swap()
244 // below never reads an indeterminate scalar out of new_ptr[i].
245 T *new_ptr = new T[newsz]();
246
247 const size_t mask = dim - 1;
248 for (size_t i = 0; i < newsz; ++i)
249 {
250 assert(((first + i) & mask) == ((first + i) % dim));
251 std::swap(ptr[(first + i) & mask], new_ptr[i]);
252 }
253
254 delete[] ptr;
255 ptr = new_ptr;
256 dim = newsz;
258
259 return true;
260 }
261
267 void init_dim(size_t d)
268 {
269 if (d == 0)
270 d = Min_Dim;
271
272 dim = is_power_of_2(d) ? d : next_power_of_two(d);
273
274 assert(dim >= d);
276 }
277
278public:
279 using Item_Type = T;
280
282 [[nodiscard]] constexpr size_t capacity() const noexcept
283 {
284 return dim;
285 }
286
289 {
290 return n;
291 }
292
295 {
296 return n == 0;
297 }
298
305 MemArray(size_t _dim = Min_Dim) : ptr(nullptr), n(0)
306 {
307 static_assert(std::is_move_constructible_v<T>, "T must be move constructible");
308 static_assert(std::is_move_assignable_v<T>, "T must be move assignable");
309 init_dim(_dim);
310 allocate();
311 }
312
314 {
315 if (ptr != nullptr)
316 {
317 delete[] ptr;
318 ptr = nullptr;
319 }
320 }
321
323 void swap(MemArray &a) noexcept
324 {
325 std::swap(ptr, a.ptr);
326 std::swap(dim, a.dim);
327 std::swap(n, a.n);
328 std::swap(contract_threshold, a.contract_threshold);
329 }
330
333 requires(std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)
334 : ptr(nullptr), dim(a.dim), n(a.n)
335 {
336 allocate();
337 for (size_t i = 0; i < n; ++i)
338 ptr[i] = a.ptr[i];
339 }
340
343 {
344 assert(a.ptr);
345 swap(a);
346 }
347
350 requires(std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T>)
351 {
352 if (this == &a)
353 return *this;
354
355 assert(a.ptr);
356
357 T *newptr = new T[a.dim]; // allocate a new array
358 for (size_t i = 0; i < a.n; ++i) // copy items to a new array
359 newptr[i] = a.ptr[i];
360
361 if (ptr != nullptr)
362 delete[] ptr;
363 ptr = newptr;
364 dim = a.dim;
365 n = a.n;
367
368 return *this;
369 }
370
373 {
374 swap(a);
375 return *this;
376 }
377
385 {
386 n = 0;
387 }
388
395 {
396 empty();
397 }
398
401 {
402 n = 0;
403 if (dim <= Min_Dim)
404 return;
405
406 assert(ptr);
407 delete[] ptr;
408 ptr = nullptr;
409 dim = Min_Dim;
410 allocate();
411 }
412
415 T &put(const T &item)
416 requires std::is_copy_assignable_v<T>
417 {
418 assert(ptr);
419 expand();
420
421 ptr[n] = item;
422 T &ret = ptr[n++];
423 return ret;
424 }
425
428 T &put(T &&item)
429 {
430 assert(ptr);
431 expand();
432
433 ptr[n] = std::forward<T>(item);
434 T &ret = ptr[n++];
435 return ret;
436 }
437
438private:
439 void open_gap(size_t pos = 0, size_t num_entries = 1)
440 {
443 }
444
445 void close_gap(size_t pos, size_t num_entries = 1)
446 {
449 }
450
451public:
454 T &push(const T &item)
455 requires std::is_copy_assignable_v<T>
456 {
457 assert(ptr);
458 open_gap();
459
460 ptr[0] = item;
461 T &ret = ptr[0];
462 return ret;
463 }
464
467 T &push(T &&item)
468 {
469 assert(ptr);
470 open_gap(0, 1);
471
472 ptr[0] = std::forward<T>(item);
473 T &ret = ptr[0];
474 return ret;
475 }
476
477 T &top() const
478 {
479 ah_underflow_error_if(n == 0) << "top(): MemArray is empty";
480
481 return ptr[0];
482 }
483
486 {
487 ah_underflow_error_if(n == 0) << "remove_first(): MemArray is empty";
488 assert(ptr);
489 T ret = std::move(ptr[0]);
490 this->close_gap(0, 1);
491 return ret;
492 }
493
496 {
497 return remove_first();
498 }
499
501 T &append(const T &item)
502 requires std::is_copy_assignable_v<T>
503 {
504 assert(ptr);
505 return put(item);
506 }
507
509 T &append(T &&item)
510 {
511 assert(ptr);
512 return put(std::forward<T>(item));
513 }
514
516 T &insert(const T &item)
517 requires std::is_copy_assignable_v<T>
518 {
519 assert(ptr);
520 return push(item);
521 }
522
524 T &insert(T &&item)
525 {
526 assert(ptr);
527 return push(std::forward<T>(item));
528 }
529
540 void putn(const size_t more)
541 {
542 assert(ptr);
543 ah_overflow_error_if(more > std::numeric_limits<size_t>::max() - n)
544 << "MemArray::putn(): size overflow";
545 const size_t new_n = n + more;
546 if (new_n <= dim)
547 {
548 n = new_n;
549 return;
550 }
551
552 size_t new_dim = dim;
553 while (new_dim < new_n)
554 {
555 ah_overflow_error_if(new_dim > (std::numeric_limits<size_t>::max() >> 1))
556 << "MemArray::putn(): capacity overflow";
557 new_dim <<= 1; // dim = 2*dim
558 }
559
560 T *new_ptr = new T[new_dim];
561 for (size_t i = 0; i < n; ++i)
562 std::swap(ptr[i], new_ptr[i]);
563
564 delete[] ptr;
565 ptr = new_ptr;
566 dim = new_dim;
567 n = new_n;
569 }
570
572 requires std::is_copy_assignable_v<T>
573 {
574 const size_t old_n = n;
575 const size_t num_entries = a.size();
577 for (size_t i = 0; i < num_entries; ++i)
578 ptr[old_n + i] = a.ptr[i];
579
580 return *this;
581 }
582
588 void reserve(const size_t cap)
589 {
590 assert(ptr);
591 if (cap < dim)
592 return;
593
594 const size_t new_dim = is_power_of_2(cap) ? cap : next_power_of_two(cap);
595
596 T *new_ptr = new T[new_dim];
597 for (size_t i = 0; i < n; ++i)
598 std::swap(ptr[i], new_ptr[i]);
599
600 delete[] ptr;
601 ptr = new_ptr;
602 dim = new_dim;
604 }
605
608 T get(const size_t i = 1)
609 {
610 assert(ptr);
611 ah_underflow_error_if(i == 0 or i > n)
612 << "MemArray::get(): invalid number of entries";
613
614 n -= i;
615 T ret = std::move(ptr[n]);
616
617 contract();
618
619 return ret;
620 }
621
622 T get_ne(const size_t i = 1) noexcept
623 {
624 assert(ptr);
625 assert(i > 0);
626 assert(i <= n);
627 n -= i;
628 T ret = std::move(ptr[n]);
629
630 contract();
631
632 return ret;
633 }
634
637 {
638 return get();
639 }
640
642 T &last() const
643 {
644 ah_underflow_error_if(n == 0) << "MemArray::last(): empty array";
645 return ptr[n - 1];
646 }
647
649 T &first() const
650 {
651 ah_underflow_error_if(n == 0) << "MemArray::first(): empty array";
652 return ptr[0];
653 }
654
656 T &get_first() const
657 {
658 return first();
659 }
660
662 T &get_last() const
663 {
664 return last();
665 }
666
669 {
670 if (n < 2)
671 return *this;
672
673 for (size_t i = 0, j = n - 1; i < j; ++i, --j)
674 std::swap(ptr[i], ptr[j]);
675 return *this;
676 }
677
680 T &access(const size_t i) const noexcept
681 {
682 assert(ptr);
683 return ptr[i];
684 }
685
688 T &operator[](const size_t i) const
689 {
690 assert(ptr);
691 ah_out_of_range_error_if(i >= n) << "access out of range";
692
693 return ptr[i];
694 }
695
697 T &operator()(const size_t i) const noexcept
698 {
699 assert(ptr);
700 assert(i < dim);
701 return ptr[i];
702 }
703
711 template <class Operation>
713 {
714 assert(ptr);
715 for (size_t i = 0; i < n; i++)
716 if (not operation(ptr[i]))
717 return false;
718
719 return true;
720 }
721
723 template <class Operation>
725 {
726 return const_cast<MemArray *>(this)->traverse(operation);
727 }
728
730 template <class Operation>
732 {
734 }
735
737 template <class Operation>
739 {
741 }
742
744 {
745 return ptr;
746 }
747
752 struct Iterator : public Array_Iterator<T>
753 {
755 using Base::Base;
756
759 : Array_Iterator<T>(no_exception_ctor, a.ptr, a.dim, a.n)
760 {
761 assert(a.ptr != nullptr);
762 }
763 };
764};
765} // end namespace Aleph
766
767#endif // TPL_MEMARRAY_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:373
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:468
@ no_exception_ctor
Definition ahDefs.H:74
DRY (Don't Repeat Yourself) utilities and macros.
Iterator traits and STL-compatible iterator wrappers.
General utility functions and helpers.
Iterator wrapper for C++ raw arrays and circular buffers.
Utility functions for array manipulation.
Iterator wrapper for C++ raw arrays.
Definition array_it.H:85
Simple, scalable and fast dynamic array.
T & operator()(const size_t i) const noexcept
void reserve(const size_t cap)
Reserves cap cells into the array.
void open_gap(size_t pos=0, size_t num_entries=1)
T & push(T &&item)
Push a copy of item at the beginning of sequence.
bool traverse(Operation &operation)
Traverse all the elements from index 0 to n - 1 and execute operation on each on them.
bool contract(const size_t first=0)
Test if n is lesser than contract_threshold and eventually contract the array half long and copies it...
size_t size() const noexcept
Return the number of elements.
void putn(const size_t more)
Reserve more additional logical slots in the array.
T get_ne(const size_t i=1) noexcept
void clear() noexcept
Alias for empty().
T & first() const
Return a modifiable reference to the first element.
T & top() const
T & access(const size_t i) const noexcept
Return a modifiable reference to the ith element.
T & append(const T &item)
size_t contract_threshold
void empty_and_release()
Empty the array and release all memory.
static constexpr size_t Min_Dim
MemArray(MemArray &&a) noexcept
Construct an array moved of rvalue a
void allocate()
Allocate memory for the current dimension.
bool traverse(Operation &&operation) const
T * get_ptr() const noexcept
Return the current base of array.
bool expand(const size_t first=0)
Test is array is full and if affrimative, then expand the array twice as long and copy the content by...
MemArray(const MemArray &a)
Construct a copy of a
T & push(const T &item)
Push a copy of item at the beginning of sequence.
T & append(T &&item)
MemArray & append(const MemArray &a)
MemArray(size_t _dim=Min_Dim)
Construct an array con capacity equal or greater than _dim.
T & insert(T &&item)
constexpr size_t capacity() const noexcept
The type of element of array.
MemArray & operator=(const MemArray &a)
Assign by copy a to this
T & insert(const T &item)
static size_t next_power_of_two(const size_t requested)
void init_dim(size_t d)
Initialize the dimension of the array to d or to the next two power if d is not a two power.
T & last() const
Return a modifiable reference to the last element.
bool is_valid() const noexcept
T & get_last() const
void close_gap(size_t pos, size_t num_entries=1)
bool is_empty() const noexcept
Return true is the array is empty.
bool traverse(Operation &&operation)
T & get_first() const
T pop()
pop() the most recently pushed item
void empty() noexcept
Empties the container.
MemArray & reverse()
Reverse the order of items in array.
const size_t & get_dim() const noexcept
Return the current dimension of array.
T get(const size_t i=1)
Remove i elements from the end.
void swap(MemArray &a) noexcept
Swap in constant time this with a
bool traverse(Operation &operation) const
T & operator[](const size_t i) const
Return a reference to the ith element.
T & put(T &&item)
Move item at the end of sequence.
T & put(const T &item)
Put a copy of item at the end of sequence.
T remove_first()
Remove the first item. Gap is closed.
MemArray & operator=(MemArray &&a) noexcept
Assign by moving a to this
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
void open_gap(Tarray &ptr, size_t n, size_t pos=0, size_t num_entries=1)
Open a gap in an array by shifting elements right.
Definition array_utils.H:96
bool is_power_of_2(unsigned long x)
Taken from http://stackoverflow.com/questions/3638431/determine-if-an-int-is-a-power-of-2-or-not-in-a...
Definition ahUtils.H:228
void close_gap(T *ptr, size_t n, size_t pos, size_t num_entries=1)
Close a gap in an array by shifting elements left.
Simple iterator on elements of array.
Iterator(const MemArray< T > &a) noexcept
Construct an iterator on array a