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/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
93# ifndef TPL_MEMARRAY_H
94# define TPL_MEMARRAY_H
95
96# include <utility>
97# include <cstdlib>
98# include <cmath>
99# include <stdexcept>
100
101# include <ah-errors.H>
102# include <ahUtils.H>
103# include <ahDry.H>
104# include <ahIterator.H>
105# include <array_it.H>
106# include <array_utils.H>
107
108namespace Aleph
109{
110
137 template <typename T>
139 {
140 public:
141
142 static constexpr size_t Min_Dim = 4;
143
144 protected:
145
146 T *ptr = nullptr;
147 size_t dim = Min_Dim;
148 size_t n = 0;
149
150 public:
151
152 mutable size_t contract_threshold;
153
155 T *get_ptr() const noexcept { return ptr; }
156
158 const size_t &get_dim() const noexcept { return dim; }
159
160 protected:
161
163 void allocate()
164 {
166 ptr = new T[dim];
168 }
169
181 bool expand(const size_t first = 0)
182 {
183 assert(ptr);
185 if (n < dim)
186 return false;
187
188 const size_t newsz = dim << 1; // 2*dim
189 const size_t mask = dim - 1;
190 T *new_ptr = new T[newsz];
191 for (size_t i = 0; i < dim; ++i)
192 {
193 assert(((i + first) & mask) == ((i + first) % dim));
194 std::swap(ptr[(i + first) & mask], new_ptr[i]);
195 }
196 delete[] ptr;
197 ptr = new_ptr;
198 dim = newsz;
200
201 return true;
202 }
203
214 bool contract(const size_t first = 0)
215 {
216 assert(ptr);
217 if (n > contract_threshold)
218 return false;
219
220 const size_t newsz = dim >> 1; // dim/2
221
222 if (newsz <= Min_Dim)
223 return false;
224
225 T *new_ptr = new T[newsz];
226
227 const size_t mask = dim - 1;
228 for (int i = 0; i < newsz; ++i)
229 {
230 assert(((first + i) & mask) == ((first + i) % dim));
231 std::swap(ptr[(first + i) & mask], new_ptr[i]);
232 }
233
234
235 delete[] ptr;
236 ptr = new_ptr;
237 dim = newsz;
239
240 return true;
241 }
242
248 void init_dim(size_t d) noexcept
249 {
250 if (d == 0)
251 d = Min_Dim;
252
253 size_t k = log2(d);
254 dim = is_power_of_2(d) ? d : 1 << ++k;
255
256 assert(dim >= d);
257 assert(dim == 1 << k);
258 }
259
260 public:
261
262 using Item_Type = T;
263
265 [[nodiscard]] constexpr size_t capacity() const noexcept { return dim; }
266
268 size_t size() const noexcept { return n; }
269
271 bool is_empty() const noexcept { return n == 0; }
272
280 {
281 static_assert(std::is_copy_constructible_v<T>,
282 "No copy constructor for T");
283 static_assert(std::is_move_constructible_v<T>,
284 "No move constructor for T");
285 static_assert(std::is_copy_assignable_v<T>,
286 "No copy assign for T");
287 static_assert(std::is_move_assignable_v<T>,
288 "No move assign for T");
290 allocate();
291 }
292
294 {
295 if (ptr != nullptr)
296 {
297 delete[] ptr;
298 ptr = nullptr;
299 }
300 }
301
303 void swap(MemArray &a) noexcept
304 {
305 std::swap(ptr, a.ptr);
306 std::swap(dim, a.dim);
307 std::swap(n, a.n);
308 std::swap(contract_threshold, a.contract_threshold);
309 }
310
313 : ptr(nullptr), dim(a.dim), n(a.n)
314 {
315 allocate();
316 for (int i = 0; i < dim; ++i)
317 ptr[i] = a.ptr[i];
318 }
319
322 : ptr(nullptr), dim(0), n(0), contract_threshold(0)
323 {
324 assert(a.ptr);
325 swap(a);
326 }
327
330 {
331 if (this == &a)
332 return *this;
333
334 assert(a.ptr);
335
336 T *newptr = new T[a.dim]; // allocate a new array
337 for (int i = 0; i < a.n; ++i) // copy items to a new array
338 newptr[i] = a.ptr[i];
339
340 if (ptr != nullptr)
341 delete[] ptr;
342 ptr = newptr;
343 dim = a.dim;
344 n = a.n;
346
347 return *this;
348 }
349
352 {
353 swap(a);
354 return *this;
355 }
356
358 void empty() { n = 0; }
359
362 {
363 n = 0;
364 if (dim <= Min_Dim)
365 return;
366
367 assert(ptr);
368 delete[] ptr;
369 ptr = nullptr;
370 dim = Min_Dim;
371 allocate();
372 }
373
376 T &put(const T &item)
377 {
378 assert(ptr);
379 expand();
380
381 ptr[n] = item;
382 T &ret = ptr[n++];
383 return ret;
384 }
385
388 T &put(T &&item)
389 {
390 assert(ptr);
391 expand();
392
393 ptr[n] = std::forward<T>(item);
394 T &ret = ptr[n++];
395 return ret;
396 }
397
398 private:
399
400 void open_gap(size_t pos = 0, size_t num_entries = 1)
401 {
404 }
405
406 void close_gap(size_t pos, size_t num_entries = 1)
407 {
410 }
411
412 public:
413
416 T &push(const T &item)
417 {
418 assert(ptr);
419 open_gap();
420
421 ptr[0] = item;
422 T &ret = ptr[0];
423 return ret;
424 }
425
428 T &push(T &&item)
429 {
430 assert(ptr);
431 open_gap(0, 1);
432
433 ptr[0] = std::forward<T>(item);
434 T &ret = ptr[0];
435 return ret;
436 }
437
438 T &top() const
439 {
440 ah_underflow_error_if(n == 0) << "top(): MemArray is empty";
441
442 return ptr[0];
443 }
444
447 {
448 ah_underflow_error_if(n == 0) << "remove_first(): MemArray is empty";
449 assert(ptr);
450 T ret = std::move(ptr[0]);
451 this->close_gap(0, 1);
452 return ret;
453 }
454
456 T pop() { return remove_first(); }
457
459 T &append(T &item)
460 {
461 assert(ptr);
462 return put(item);
463 }
464
466 T &append(T &&item)
467 {
468 assert(ptr);
469 return put(std::forward<T>(item));
470 }
471
473 T &insert(T &item)
474 {
475 assert(ptr);
476 return push(item);
477 }
478
480 T &insert(T &&item)
481 {
482 assert(ptr);
483 return push(std::forward<T>(item));
484 }
485
496 void putn(const size_t more)
497 {
498 assert(ptr);
499 const size_t new_n = n + more;
500 if (new_n <= dim)
501 {
502 n = new_n;
503 return;
504 }
505
506 size_t new_dim = dim;
507 while (new_dim < new_n)
508 new_dim <<= 1; // dim = 2*dim
509
510 T *new_ptr = new T[new_dim];
511 for (size_t i = 0; i < n; ++i)
512 std::swap(ptr[i], new_ptr[i]);
513
514 delete[] ptr;
515 ptr = new_ptr;
516 dim = new_dim;
517 n = new_n;
519 }
520
522 {
523 const size_t old_n = n;
524 const size_t num_entries = a.size();
526 for (size_t i = 0; i < num_entries; ++i)
527 ptr[old_n + i] = a.ptr[i];
528
529 return *this;
530 }
531
537 void reserve(const size_t cap)
538 {
539 assert(ptr);
540 if (cap < dim)
541 return;
542
543 size_t k = log2(cap);
544 const size_t new_dim = is_power_of_2(cap) ? cap : 1 << ++k;
545
546 T *new_ptr = new T[new_dim];
547 for (size_t i = 0; i < n; ++i)
548 std::swap(ptr[i], new_ptr[i]);
549
550 delete[] ptr;
551 ptr = new_ptr;
552 dim = new_dim;
554 }
555
558 T get(const size_t i = 1)
559 {
560 assert(ptr);
561 const long idx = n - i;
562 ah_underflow_error_if(idx < 0)
563 << "MemArray::get(): deleted more entries than capacity";
564
565 n = idx;
566 T ret = std::move(ptr[n]);
567
568 contract();
569
570 return ret;
571 }
572
573 T get_ne(const size_t i = 1) noexcept
574 {
575 assert(ptr);
576 const long idx = n - i;
577 n = idx;
578 T ret = std::move(ptr[n]);
579
580 contract();
581
582 return ret;
583 }
584
586 T remove_last() { return get(); }
587
589 T &last() const
590 {
591 ah_underflow_error_if(n == 0) << "MemArray::last(): empty array";
592 return ptr[n - 1];
593 }
594
596 T &first() const
597 {
598 ah_underflow_error_if(n == 0) << "MemArray::first(): empty array";
599 return ptr[0];
600 }
601
603 T &get_first() const { return first(); }
604
606 T &get_last() const { return last(); }
607
610 {
611 for (size_t i = 0, j = n - 1; i < j; ++i, --j)
612 std::swap(ptr[i], ptr[j]);
613 return *this;
614 }
615
618 T &access(const size_t i) const noexcept
619 {
620 assert(ptr);
621 return ptr[i];
622 }
623
626 T &operator[](const size_t i) const
627 {
628 assert(ptr);
629 ah_out_of_range_error_if(i >= n) << "access out of range";
630
631 return ptr[i];
632 }
633
635 T &operator()(const size_t i) const noexcept
636 {
637 assert(ptr);
638 assert(i < dim);
639 return ptr[i];
640 }
641
649 template <class Operation>
651 {
652 assert(ptr);
653 for (int i = 0; i < n; i++)
654 if (not operation(ptr[i]))
655 return false;
656
657 return true;
658 }
659
661 template <class Operation>
663 {
664 return const_cast<MemArray *>(this)->traverse(operation);
665 }
666
668 template <class Operation>
670 {
672 }
673
675 template <class Operation>
677 {
679 }
680
681 bool is_valid() const noexcept { return ptr; }
682
687 struct Iterator : public Array_Iterator<T>
688 {
690 using Base::Base;
691
694 : Array_Iterator<T>(no_exception_ctor, a.ptr, a.dim, a.n)
695 {
696 assert(a.ptr != nullptr);
697 }
698 };
699 };
700
701} // end namespace Aleph
702
703# 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:579
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:368
@ no_exception_ctor
Definition ahDefs.H:72
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:77
Simple, scalable and fast dynamic array.
T & put(const T &item)
Put a copy of item at the end of sequence.
T & operator()(const size_t i) const noexcept
MemArray(const MemArray &a)
Construct a copy of a
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
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.
size_t contract_threshold
MemArray & append(const MemArray &a)
MemArray & operator=(const MemArray &a)
Assign by copy a to this
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 empty()
Empty the container. The array is not contracted.
void allocate()
Allocate memory for the current dimension.
bool traverse(Operation &&operation) const
T & append(T &item)
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...
T & append(T &&item)
T & insert(T &&item)
void init_dim(size_t d) noexcept
Initialize the dimension of the array to d or to the next two power if d is not a two power.
constexpr size_t capacity() const noexcept
The type of element of array.
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
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.
MemArray(size_t __dim=Min_Dim)
Construct an array con capacity equal or gre+ater than __dim.
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 & insert(T &item)
T & put(T &&item)
Move item at the end of sequence.
T & push(const T &item)
Push a copy of item at the beginning of sequence.
T remove_first()
Remove first item. Gap is closed.
MemArray & operator=(MemArray &&a) noexcept
Assign by moving a to this
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log2_function > > log2(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4064
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
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:224
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.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Simple iterator on elements of array.
Iterator(const MemArray< T > &a) noexcept
Construct an iterator on array a