Aleph-w  1.9
General library for algorithms and data structures
tpl_memArray.H
1 
2 /* Aleph-w
3 
4  / \ | | ___ _ __ | |__ __ __
5  / _ \ | |/ _ \ '_ \| '_ \ ____\ \ /\ / / Data structures & Algorithms
6  / ___ \| | __/ |_) | | | |_____\ V V / version 1.9b
7  /_/ \_\_|\___| .__/|_| |_| \_/\_/ https://github.com/lrleon/Aleph-w
8  |_|
9 
10  This file is part of Aleph-w library
11 
12  Copyright (c) 2002-2018 Leandro Rabindranath Leon & Alejandro Mujica
13 
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  This program is distributed in the hope that it will be useful, but
20  WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with this program. If not, see <https://www.gnu.org/licenses/>.
26 */
27 # ifndef TPL_MEMARRAY_H
28 # define TPL_MEMARRAY_H
29 
30 # include <utility>
31 # include <cstdlib>
32 # include <cmath>
33 # include <stdexcept>
34 
35 # include <ahUtils.H>
36 # include <ahDry.H>
37 # include <ahIterator.H>
38 # include <array_it.H>
39 # include <array_utils.H>
40 
41 using namespace Aleph;
42 
43 namespace Aleph
44 {
45 
72  template <typename T>
73 class MemArray
74 {
75 public:
76 
77  static constexpr size_t Min_Dim = 4;
78 
79 protected:
80 
81  T * ptr = nullptr;
82  size_t dim = Min_Dim;
83  size_t n = 0;
84 
85 public:
86 
87  mutable size_t contract_threshold;
88 
89 public:
90 
92  T * get_ptr() const noexcept { return ptr; }
93 
95  const size_t & get_dim() const noexcept { return dim; }
96 
97 protected:
98 
100  void allocate()
101  {
102  assert(is_power_of_2(dim));
103  ptr = new T [dim];
104  contract_threshold = dim / 4;
105  }
106 
118  bool expand(const size_t first = 0)
119  {
120  assert(ptr);
121  assert(is_power_of_2(dim));
122  if (n < dim)
123  return false;
124 
125  const size_t newsz = dim << 1; // 2*dim
126  const size_t mask = dim - 1;
127  T * new_ptr = new T [newsz];
128  for (size_t i = 0; i < dim; ++i)
129  {
130  assert(((i + first) & mask) == ((i + first) % dim));
131  std::swap(ptr[(i + first) & mask], new_ptr[i]);
132  }
133  delete [] ptr;
134  ptr = new_ptr;
135  dim = newsz;
136  contract_threshold = dim/4;
137 
138  return true;
139  }
140 
151  bool contract(const size_t first = 0)
152  {
153  assert(ptr);
154  if (n > contract_threshold)
155  return false;
156 
157  const size_t newsz = dim >> 1; // dim/2
158 
159  if (newsz <= Min_Dim)
160  return false;
161 
162  T * new_ptr = new T [newsz];
163 
164  const size_t mask = dim - 1;
165  for (int i = 0; i < newsz; ++i)
166  {
167  assert(((first + i) & mask) == ((first + i) % dim));
168  std::swap(ptr[(first + i) & mask], new_ptr[i]);
169  }
170 
171  for (int i = newsz; i < dim; ++i) // call destructors
172  ptr[i].~T();
173 
174  delete [] ptr;
175  ptr = new_ptr;
176  dim = newsz;
177  contract_threshold = dim/4;
178 
179  return true;
180  }
181 
182  // if dim == 2^k returns dim; else next two power 2^k > dim
183  void init_dim(size_t d) noexcept
184  {
185  if (d == 0)
186  d = Min_Dim;
187 
188  size_t k = log2(d);
189  dim = is_power_of_2(d) ? d : 1 << ++k;
190 
191  assert(dim >= d);
192  assert(dim == 1 << k);
193  }
194 
195 public:
196 
197  using Item_Type = T;
198 
200  size_t capacity() const noexcept { return dim; }
201 
203  size_t size() const noexcept { return n; }
204 
206  bool is_empty() const noexcept { return n == 0; }
207 
214  MemArray(size_t __dim = Min_Dim) : ptr(nullptr), n(0)
215  {
216  static_assert(std::is_copy_constructible<T>::value,
217  "No copy constructor for T");
218  static_assert(std::is_move_constructible<T>::value,
219  "No move constructor for T");
220  static_assert(std::is_copy_assignable<T>::value,
221  "No copy assign for T");
222  static_assert(std::is_move_assignable<T>::value,
223  "No move assign for T");
224  init_dim(__dim);
225  allocate();
226  }
227 
228  ~MemArray()
229  {
230  if (ptr != nullptr)
231  {
232  delete [] ptr;
233  ptr = nullptr;
234  }
235  }
236 
238  void swap(MemArray & a) noexcept
239  {
240  std::swap(ptr, a.ptr);
241  std::swap(dim, a.dim);
242  std::swap(n, a.n);
243  std::swap(contract_threshold, a.contract_threshold);
244  }
245 
247  MemArray(const MemArray & a)
248  : ptr(nullptr), dim(a.dim), n(a.n)
249  {
250  allocate();
251  for (int i = 0; i < dim; ++i)
252  ptr[i] = a.ptr[i];
253  }
254 
256  MemArray(MemArray && a) noexcept
257  : ptr(nullptr), dim(0), n(0), contract_threshold(0)
258  {
259  assert(a.ptr);
260  swap(a);
261  }
262 
265  {
266  if (this == &a)
267  return *this;
268 
269  assert(a.ptr);
270 
271  T * newptr = new T [a.dim]; // allocate new array
272  for (int i = 0; i < a.n; ++i) // copy items to new array
273  newptr[i] = a.ptr[i];
274 
275  if (ptr != nullptr)
276  delete [] ptr;
277  ptr = newptr;
278  dim = a.dim;
279  n = a.n;
280 
281  return *this;
282  }
283 
285  MemArray & operator = (MemArray && a) noexcept
286  {
287  swap(a);
288  return *this;
289  }
290 
292  void empty() { n = 0; }
293 
296  {
297  n = 0;
298  if (dim <= Min_Dim)
299  return;
300 
301  assert(ptr);
302  delete [] ptr;
303  ptr = nullptr;
304  dim = Min_Dim;
305  allocate();
306  }
307 
310  T & put(const T & item)
311  {
312  assert(ptr);
313  expand();
314 
315  ptr[n] = item;
316  T & ret = ptr[n++];
317  return ret;
318  }
319 
322  T & put(T && item)
323  {
324  assert(ptr);
325  expand();
326 
327  ptr[n] = std::forward<T>(item);
328  T & ret = ptr[n++];
329  return ret;
330  }
331 
332 private:
333 
334  void open_gap(size_t pos = 0, size_t num_entries = 1)
335  {
336  putn(num_entries);
337  Aleph::open_gap(ptr, n, pos, num_entries);
338  }
339 
340  void close_gap(size_t pos, size_t num_entries = 1)
341  {
342  Aleph::close_gap(ptr, n, pos, num_entries);
343  get(num_entries);
344  }
345 
346 public:
347 
350  T & push(const T & item)
351  {
352  assert(ptr);
353  open_gap();
354 
355  ptr[0] = item;
356  T & ret = ptr[0];
357  return ret;
358  }
359 
362  T & push(T && item)
363  {
364  assert(ptr);
365  open_gap();
366 
367  ptr[0] = std::forward<T>(item);
368  T & ret = ptr[0];
369  return ret;
370  }
371 
372  T & top() const
373  {
374  if (n == 0)
375  throw std::underflow_error("top(): MemArray is empty");
376 
377  return ptr[0];
378  }
379 
382  {
383  if (n == 0)
384  throw std::underflow_error("remove_first(): MemArray is empty");
385  assert(ptr);
386  T ret = move(ptr[0]);
387  close_gap(0);
388  return ret;
389  }
390 
392  T pop() { return remove_first(); }
393 
395  T & append(T & item)
396  {
397  assert(ptr);
398  return put(item);
399  }
400 
402  T & append(T && item)
403  {
404  assert(ptr);
405  return put(std::forward<T>(item));
406  }
407 
409  T & insert(T & item)
410  {
411  assert(ptr);
412  return push(item);
413  }
414 
416  T & insert(T && item)
417  {
418  assert(ptr);
419  return push(std::forward<T>(item));
420  }
421 
431  void putn(const size_t more)
432  {
433  assert(ptr);
434  size_t new_n = n + more;
435  if (new_n <= dim)
436  {
437  n = new_n;
438  return;
439  }
440 
441  size_t new_dim = dim;
442  while (new_dim < new_n)
443  new_dim <<= 1; // dim = 2*dim
444 
445  T * new_ptr = new T[new_dim];
446  for (size_t i = 0; i < n; ++i)
447  std::swap(ptr[i], new_ptr[i]);
448 
449  delete [] ptr;
450  ptr = new_ptr;
451  dim = new_dim;
452  n = new_n;
453  contract_threshold = dim/4;
454  }
455 
456  MemArray & append(const MemArray & a)
457  {
458  const size_t old_n = n;
459  const size_t num_entries = a.size();
460  putn(num_entries);
461  for (size_t i = 0; i < num_entries; ++i)
462  ptr[old_n + i] = a.ptr[i];
463 
464  return *this;
465  }
466 
467  /*
468  MemArray & insert(const MemArray & a)
469  {
470  const size_t old_n = n;
471  const size_t & num_entries = a.size();
472  Aleph::open_gap(ptr, n);
473  }
474  */
475 
481  void reserve(const size_t cap)
482  {
483  assert(ptr);
484  if (cap < dim)
485  return;
486 
487  size_t k = log2(cap);
488  const size_t new_dim = is_power_of_2(cap) ? cap : 1 << ++k;
489 
490  T * new_ptr = new T[new_dim];
491  for (size_t i = 0; i < n; ++i)
492  std::swap(ptr[i], new_ptr[i]);
493 
494  delete [] ptr;
495  ptr = new_ptr;
496  dim = new_dim;
497  contract_threshold = dim/4;
498  }
499 
502  T get(size_t i = 1)
503  {
504  assert(ptr);
505  long idx = n - i;
506  if (idx < 0)
507  throw std::underflow_error("MemArray::get(): deleted more entries"
508  " than capacity");
509 
510  n = idx;
511  T ret = std::move(ptr[n]);
512 
513  contract();
514 
515  return ret;
516  }
517 
518  T get_ne(size_t i = 1) noexcept
519  {
520  assert(ptr);
521  long idx = n - i;
522  n = idx;
523  T ret = std::move(ptr[n]);
524 
525  contract();
526 
527  return ret;
528  }
529 
531  T remove_last() { return get(); }
532 
534  T & last() const
535  {
536  if (n == 0)
537  throw std::underflow_error("MemArray::last(): empty array");
538  return ptr[n - 1];
539  }
540 
542  T & first() const
543  {
544  if (n == 0)
545  throw std::underflow_error("MemArray::first(): empty array");
546  return ptr[0];
547  }
548 
550  T & get_first() const { return first(); }
551 
553  T & get_last() const { return last(); }
554 
557  {
558  for (size_t i = 0, j = n - 1; i < j; ++i, --j)
559  std::swap(ptr[i], ptr[j]);
560  return *this;
561  }
562 
565  T & access(const size_t i) const noexcept
566  {
567  assert(ptr);
568  return ptr[i];
569  }
570 
573  T & operator [] (const size_t i) const
574  {
575  assert(ptr);
576  if (i >= n)
577  throw std::out_of_range("access out of range");
578 
579  return ptr[i];
580  }
581 
583  T & operator () (const size_t i) const noexcept
584  {
585  assert(ptr);
586  assert(i < dim);
587  return ptr[i];
588  }
589 
597  template <class Operation>
598  bool traverse(Operation & operation)
599  {
600  assert(ptr);
601  for (int i = 0; i < n; i++)
602  if (not operation(ptr[i]))
603  return false;
604 
605  return true;
606  }
607 
609  template <class Operation>
610  bool traverse(Operation & operation) const
611  {
612  return const_cast<MemArray*>(this)->traverse(operation);
613  }
614 
616  template <class Operation>
617  bool traverse(Operation && operation) const
618  {
619  return traverse<Operation>(operation);
620  }
621 
623  template <class Operation>
624  bool traverse(Operation && operation)
625  {
626  return traverse<Operation>(operation);
627  }
628 
629  bool is_valid() const noexcept { return ptr; }
630 
635  struct Iterator : public Array_Iterator<T>
636  {
637  using Base = Array_Iterator<T>;
638  using Base::Base;
639 
641  Iterator(const MemArray<T> & a) noexcept
642  : Array_Iterator<T>(no_exception_ctor, a.ptr, a.dim, a.n)
643  {
644  assert(a.ptr != nullptr);
645  }
646  };
647 };
648 
649 
650 } // end namespace Aleph
651 
652 # endif // TPL_MEMARRAY_H
Definition: tpl_memArray.H:73
T & get_first() const
Definition: tpl_memArray.H:550
void empty_and_release()
Empty the array and release all memory.
Definition: tpl_memArray.H:295
T & access(const size_t i) const noexcept
Definition: tpl_memArray.H:565
const size_t & get_dim() const noexcept
Return the current dimension of array.
Definition: tpl_memArray.H:95
T pop()
pop() the most recently pushed item
Definition: tpl_memArray.H:392
bool traverse(Operation &&operation) const
Definition: tpl_memArray.H:617
T & push(const T &item)
Definition: tpl_memArray.H:350
size_t capacity() const noexcept
The type of element of array.
Definition: tpl_memArray.H:200
T & first() const
Return a modifiable reference to the first element.
Definition: tpl_memArray.H:542
void reserve(const size_t cap)
Definition: tpl_memArray.H:481
void allocate()
Allocate memory for the current dimension.
Definition: tpl_memArray.H:100
void swap(MemArray &a) noexcept
Swap in constant time this with a
Definition: tpl_memArray.H:238
T & put(T &&item)
Definition: tpl_memArray.H:322
bool contract(const size_t first=0)
Definition: tpl_memArray.H:151
T & last() const
Return a modifiable reference to the last element.
Definition: tpl_memArray.H:534
MemArray(const MemArray &a)
Construct a copy of a
Definition: tpl_memArray.H:247
Definition: array_it.H:45
T * get_ptr() const noexcept
Return the current base of array.
Definition: tpl_memArray.H:92
bool traverse(Operation &operation)
Definition: tpl_memArray.H:598
size_t size() const noexcept
Return the number of elements.
Definition: tpl_memArray.H:203
Definition: ah-comb.H:35
bool traverse(Operation &operation) const
Definition: tpl_memArray.H:610
T remove_last()
Definition: tpl_memArray.H:531
Definition: tpl_memArray.H:635
void putn(const size_t more)
Definition: tpl_memArray.H:431
T & append(T &&item)
Definition: tpl_memArray.H:402
T & insert(T &&item)
Definition: tpl_memArray.H:416
T remove_first()
Remove first item. Gap is closed.
Definition: tpl_memArray.H:381
T & get_last() const
Definition: tpl_memArray.H:553
T & append(T &item)
Definition: tpl_memArray.H:395
void empty()
Empty the container. The array is not contracted.
Definition: tpl_memArray.H:292
bool expand(const size_t first=0)
Definition: tpl_memArray.H:118
T & operator[](const size_t i) const
Definition: tpl_memArray.H:573
MemArray(MemArray &&a) noexcept
Construct a array moved of rvalue a
Definition: tpl_memArray.H:256
bool is_empty() const noexcept
Return true is the array is empty.
Definition: tpl_memArray.H:206
T & put(const T &item)
Definition: tpl_memArray.H:310
MemArray & operator=(const MemArray &a)
Assign by copy a to this
Definition: tpl_memArray.H:264
MemArray(size_t __dim=Min_Dim)
Definition: tpl_memArray.H:214
MemArray & reverse()
Reverse the order of items in array.
Definition: tpl_memArray.H:556
T & insert(T &item)
Definition: tpl_memArray.H:409
Iterator(const MemArray< T > &a) noexcept
Construct an iterator on array a
Definition: tpl_memArray.H:641
bool traverse(Operation &&operation)
Definition: tpl_memArray.H:624
T & push(T &&item)
Definition: tpl_memArray.H:362
T & operator()(const size_t i) const noexcept
Definition: tpl_memArray.H:583

Leandro Rabindranath León