Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
darray.hpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #ifndef JAU_DYN_ARRAY_HPP_
26 #define JAU_DYN_ARRAY_HPP_
27 
28 #include <cstring>
29 #include <string>
30 #include <cstdint>
31 #include <limits>
32 #include <atomic>
33 #include <memory>
34 #include <mutex>
35 #include <condition_variable>
36 #include <initializer_list>
37 #include <algorithm>
38 #include <utility>
39 
40 #include <jau/debug.hpp>
41 #include <jau/basic_types.hpp>
42 #include <jau/ordered_atomic.hpp>
43 #include <jau/callocator.hpp>
44 #include <jau/basic_algos.hpp>
45 
46 namespace jau {
47 
48 // #define DEBUG_DARRAY 1
49 
50 #if DEBUG_DARRAY
51  #define DARRAY_PRINTF(...) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
52 #else
53  #define DARRAY_PRINTF(...)
54 #endif
55 
56  /**
57  * Implementation of a dynamic linear array storage, aka vector.<br>
58  * Goals are to support a high-performance CoW dynamic array implementation, jau::cow_darray,<br>
59  * exposing fine grained control over its underlying storage facility.<br>
60  * Further, jau::darray provides high-performance and efficient storage properties on its own.
61  * <p>
62  * This class shall be compliant with <i>C++ named requirements for Container</i>.
63  * </p>
64  * <p>
65  * API and design differences to std::vector
66  * <ul>
67  * <li>jau::darray adds a parameterized <i>growth factor</i> aspect, default to golden ration jau::darray::DEFAULT_GROWTH_FACTOR</li>
68  * <li><i>capacity</i> control via constructor and operations, related to <i>growth factor</i>.</li>
69  * <li>Iterator jau::darray::const_iterator .. are harmonized with jau::cow_ro_iterator .. used in jau:cow_darray.</li>
70  * <li>...</li>
71  * <li>Custom constructor and operations, supporting a more efficient jau::cow_darray implementation.</li>
72  * <li>Custom template typename Size_type, defaults to jau::nsize_t.</li>
73  * <li>...</li>
74  * <li><b>Removed</b>: size_type x value_type fill operations, e.g. assign, constructor, .... for clarity, since supporting <i>capacity</i>.</li>
75  * <li>...</li>
76  * <li><b>TODO</b>: std::initializer_list<T> methods, ctor is provided.</li>
77  * </ul>
78  * </p>
79  * <p>
80  * Implementation differences to std::vector and some details
81  * <ul>
82  * <li>Using zero overhead <i>value_type*</i> as iterator type.</li>
83  * <li>...</li>
84  * <li>Storage is operated on three iterator: <i>begin</i>, <i>end</i> and <i>storage_end</i>.</li>
85  * <li>Constructs and destructs value_type via <i>placement new</i> within the pre-allocated array capacity. Latter is managed via allocator_type.</li>
86  * </ul>
87  * </p>
88  * <p>
89  * Non-Type Template Parameter <code>use_memmove</code> can be overriden by the user
90  * and has its default value <code>std::is_trivially_copyable_v<Value_type></code>.<br>
91  * The default value has been chosen with care, see C++ Standard section 6.9 Types <i>trivially copyable</i>.<br>
92  * However, one can set <code>use_memmove</code> to true even without the value_type being <i>trivially copyable</i>,
93  * as long certain memory side-effects can be excluded (TBD).
94  * </p>
95  */
96  template <typename Value_type, typename Alloc_type = jau::callocator<Value_type>, typename Size_type = jau::nsize_t,
97  bool use_memmove = std::is_trivially_copyable_v<Value_type>,
98  bool use_realloc = std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>,
99  bool sec_mem = false
100  >
101  class darray
102  {
103  public:
104  /** Default growth factor using the golden ratio 1.618 */
105  constexpr static const float DEFAULT_GROWTH_FACTOR = 1.618f;
106 
107  constexpr static const bool uses_memmove = use_memmove;
108  constexpr static const bool uses_realloc = use_realloc;
109  constexpr static const bool uses_secmem = sec_mem;
110 
111  // typedefs' for C++ named requirements: Container
112 
113  typedef Value_type value_type;
114  typedef value_type* pointer;
115  typedef const value_type* const_pointer;
117  typedef const value_type& const_reference;
119  typedef const value_type* const_iterator;
120  typedef Size_type size_type;
121  typedef typename std::make_signed<size_type>::type difference_type;
122  // typedef std::reverse_iterator<iterator> reverse_iterator;
123  // typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
124  typedef Alloc_type allocator_type;
125 
126  /** Used to determine whether this type is a darray or has a darray, see ::is_darray_type<T> */
127  typedef bool darray_tag;
128 
129  private:
130  constexpr static const size_type DIFF_MAX = std::numeric_limits<difference_type>::max();
131  constexpr static const size_type MIN_SIZE_AT_GROW = 10;
132 
133  allocator_type alloc_inst;
134  pointer begin_;
135  pointer end_;
136  pointer storage_end_;
137  float growth_factor_;
138 
139  /**
140  * Allocates a new store using allocator_type.
141  * <p>
142  * Throws jau::IllegalArgumentException() if size_ > <code>std::numeric_limits<difference_type>::max()</code>, i.e. difference_type maximum.
143  * </p>
144  * <p>
145  * Throws jau::OutOfMemoryError() if allocator_type::allocate() returns nullptr.
146  * </p>
147  * @param alloc the allocator_type instance
148  * @param size_ the element count, must be <= <code>std::numeric_limits<difference_type>::max()</code>
149  * @return nullptr if given <code>0 == size_</code> or the newly allocated memory
150  */
151  constexpr value_type * allocStore(const size_type size_) {
152  if( 0 != size_ ) {
153  if( size_ > DIFF_MAX ) {
154  throw jau::IllegalArgumentException("alloc "+std::to_string(size_)+" > difference_type max "+
155  std::to_string(DIFF_MAX), E_FILE_LINE);
156  }
157  value_type * m = alloc_inst.allocate(size_);
158  if( nullptr == m ) {
159  throw jau::OutOfMemoryError("alloc "+std::to_string(size_)+" elements * "+
160  std::to_string(sizeof(value_type))+" bytes/element = "+
161  std::to_string(size_ * sizeof(value_type))+" bytes -> nullptr", E_FILE_LINE);
162  }
163  if( sec_mem ) {
164  explicit_bzero((void*)m, size_*sizeof(value_type));
165  }
166  return m;
167  }
168  return nullptr;
169  }
170 
171  template<class _Alloc_type>
172  constexpr value_type * reallocStore(const size_type new_capacity_,
173  std::enable_if_t< std::is_base_of<jau::callocator<value_type>, _Alloc_type>::value, bool > = true )
174  {
175  if( new_capacity_ > DIFF_MAX ) {
176  throw jau::IllegalArgumentException("realloc "+std::to_string(new_capacity_)+" > difference_type max "+
177  std::to_string(DIFF_MAX), E_FILE_LINE);
178  }
179  if( sec_mem ) {
180  explicit_bzero((void*)end_, (storage_end_-end_)*sizeof(value_type));
181  }
182  value_type * m = alloc_inst.reallocate(begin_, storage_end_-begin_, new_capacity_);
183  if( nullptr == m ) {
184  free(begin_); // has not been touched by realloc
185  throw jau::OutOfMemoryError("realloc "+std::to_string(new_capacity_)+" elements * "+
186  std::to_string(sizeof(value_type))+" bytes/element = "+
187  std::to_string(new_capacity_ * sizeof(value_type))+" bytes -> nullptr", E_FILE_LINE);
188  }
189  if( sec_mem ) {
190  explicit_bzero((void*)(m+(end_-begin_)), (new_capacity_-(end_-begin_))*sizeof(value_type));
191  }
192  return m;
193  }
194  template<class _Alloc_type>
195  constexpr value_type * reallocStore(const size_type new_capacity_,
196  std::enable_if_t< !std::is_base_of<jau::callocator<value_type>, _Alloc_type>::value, bool > = true )
197  {
198  (void)new_capacity_;
199  throw jau::UnsupportedOperationException("realloc not supported on non allocator_type not based upon jau::callocator", E_FILE_LINE);
200  }
201 
202  constexpr void freeStore() {
203  if( nullptr != begin_ ) {
204  if( sec_mem ) {
205  explicit_bzero((void*)begin_, (storage_end_-begin_)*sizeof(value_type));
206  }
207  alloc_inst.deallocate(begin_, storage_end_-begin_);
208  }
209  }
210 
211  constexpr void set_iterator(pointer new_storage_, difference_type size_, difference_type capacity_) noexcept {
212  begin_ = new_storage_;
213  end_ = new_storage_+size_;
214  storage_end_ = new_storage_+capacity_;
215  }
216 
217  constexpr void set_iterator(difference_type size_, difference_type capacity_) noexcept {
218  end_ = begin_+size_;
219  storage_end_ = begin_+capacity_;
220  }
221 
222  constexpr void dtor_one(iterator pos) {
223  DARRAY_PRINTF("dtor [%zd], count 1\n", (pos-begin_));
224  ( pos )->~value_type(); // placement new -> manual destruction!
225  if( sec_mem ) {
226  explicit_bzero((void*)pos, sizeof(value_type));
227  }
228  }
229 
230  constexpr size_type dtor_range(iterator first, const_iterator last) {
231  size_type count=0;
232  DARRAY_PRINTF("dtor [%zd .. %zd], count %zd\n", (first-begin_), (last-begin_)-1, (last-first));
233  for(; first < last; ++first, ++count ) {
234  ( first )->~value_type(); // placement new -> manual destruction!
235  }
236  if( sec_mem ) {
237  explicit_bzero((void*)(last-count), count*sizeof(value_type));
238  }
239  return count;
240  }
241 
242  constexpr void ctor_copy_range(pointer dest, iterator first, const_iterator last) {
243  DARRAY_PRINTF("ctor_copy_range [%zd .. %zd] -> ??, dist %zd\n", (first-begin_), (last-begin_)-1, (last-first));
244  for(; first < last; ++dest, ++first) {
245  new (dest) value_type( *first ); // placement new
246  }
247  }
248  constexpr pointer clone_range(iterator first, const_iterator last) {
249  DARRAY_PRINTF("clone_range [%zd .. %zd], count %zd\n", (first-begin_), (last-begin_)-1, (last-first));
250  pointer dest = allocStore(size_type(last-first));
251  ctor_copy_range(dest, first, last);
252  return dest;
253  }
254  constexpr pointer clone_range(const size_type dest_capacity, iterator first, const_iterator last) {
255  DARRAY_PRINTF("clone_range [%zd .. %zd], count %zd -> %d\n", (first-begin_), (last-begin_)-1, (last-first), (int)dest_capacity);
256  pointer dest = allocStore(dest_capacity);
257  ctor_copy_range(dest, first, last);
258  return dest;
259  }
260  constexpr void ctor_copy_range_check(pointer dest, iterator first, const_iterator last) {
261  DARRAY_PRINTF("ctor_copy_range_check [%zd .. %zd] -> ??, dist %zd\n", (first-begin_), (last-begin_)-1, (last-first));
262  if( first > last ) {
263  throw jau::IllegalArgumentException("first "+to_hexstring(first)+" > last "+to_hexstring(last), E_FILE_LINE);
264  }
265  for(; first < last; ++dest, ++first) {
266  new (dest) value_type( *first ); // placement new
267  }
268  }
269  constexpr pointer clone_range_check(const size_type dest_capacity, iterator first, const_iterator last) {
270  DARRAY_PRINTF("clone_range_check [%zd .. %zd], count %zd -> %d\n", (first-begin_), (last-begin_)-1, (last-first), (int)dest_capacity);
271  if( dest_capacity < size_type(last-first) ) {
272  throw jau::IllegalArgumentException("capacity "+std::to_string(dest_capacity)+" < source range "+
274  }
275  pointer dest = allocStore(dest_capacity);
276  ctor_copy_range_check(dest, first, last);
277  return dest;
278  }
279  template< class InputIt >
280  constexpr static void ctor_copy_range_foreign(pointer dest, InputIt first, InputIt last) {
281  if( first > last ) {
282  throw jau::IllegalArgumentException("first "+jau::to_string( first )+" > last "+
283  jau::to_string( last ), E_FILE_LINE);
284  }
285  for(; first != last; ++dest, ++first) {
286  new (dest) value_type( *first ); // placement new
287  }
288  }
289  template< class InputIt >
290  constexpr pointer clone_range_foreign(const size_type dest_capacity, InputIt first, InputIt last) {
291  if( dest_capacity < size_type(last-first) ) {
292  throw jau::IllegalArgumentException("capacity "+std::to_string(dest_capacity)+" < source range "+
294  }
295  pointer dest = allocStore(dest_capacity);
296  ctor_copy_range_foreign(dest, first, last);
297  return dest;
298  }
299 
300  constexpr void grow_storage_move(const size_type new_capacity) {
301  if( !use_memmove ) {
302  pointer new_storage = allocStore(new_capacity);
303  {
304  iterator dest = new_storage;
305  iterator first = begin_;
306  for(; first < end_; ++dest, ++first) {
307  new (dest) value_type( std::move( *first ) ); // placement new
308  dtor_one(first); // manual destruction, even after std::move (object still exists)
309  }
310  }
311  freeStore();
312  set_iterator(new_storage, size(), new_capacity);
313  } else if( use_realloc ) {
314  pointer new_storage = reallocStore<allocator_type>(new_capacity);
315  set_iterator(new_storage, size(), new_capacity);
316  } else {
317  pointer new_storage = allocStore(new_capacity);
318  memcpy(reinterpret_cast<void*>(new_storage),
319  reinterpret_cast<void*>(begin_), (uint8_t*)end_-(uint8_t*)begin_); // we can simply copy the memory over, also no overlap
320 
321  freeStore();
322  set_iterator(new_storage, size(), new_capacity);
323  }
324  }
325  constexpr void grow_storage_move() {
326  grow_storage_move( get_grown_capacity() );
327  }
328 
329  constexpr void move_elements(iterator dest, const_iterator first, const difference_type count) noexcept {
330  // Debatable here: "Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!"
331  // Debatable, b/c is this even possible for user to hold an instance the way, that a dtor gets called? Probably not.
332  // Hence we leave it to 'sec_mem' to bzero...
333  if( use_memmove ) {
334  // handles overlap
335  memmove(reinterpret_cast<void*>(dest),
336  reinterpret_cast<const void*>(first), sizeof(value_type)*count);
337  if( sec_mem ) {
338  if( dest < first ) {
339  // move elems left
340  DARRAY_PRINTF("move_elements.mmm.left [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), ((first + count)-begin_)-1, (dest-begin_), (first-dest));
341  explicit_bzero((void*)(dest+count), (first-dest)*sizeof(value_type));
342  } else {
343  // move elems right
344  DARRAY_PRINTF("move_elements.mmm.right [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), ((first + count)-begin_)-1, (dest-begin_), (dest-first));
345  explicit_bzero((void*)first, (dest-first)*sizeof(value_type));
346  }
347  }
348  } else {
349  if( dest < first ) {
350  // move elems left
351  const_iterator last = first + count;
352  DARRAY_PRINTF("move_elements.def.left [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), (last-begin_)-1, (dest-begin_), (first-dest));
353  for(; first < last; ++dest, ++first ) {
354  new (dest) value_type( std::move( *first ) ); // placement new
355  dtor_one( const_cast<value_type*>( first ) ); // manual destruction, even after std::move (object still exists)
356  }
357  } else {
358  // move elems right
359  iterator last = const_cast<iterator>(first + count);
360  DARRAY_PRINTF("move_elements.def.right [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), (last-begin_)-1, (dest-begin_), (dest-first));
361  dest += count - 1;
362  for(--last; first <= last; --dest, --last ) {
363  new (dest) value_type( std::move( *last ) ); // placement new
364  dtor_one( last ); // manual destruction, even after std::move (object still exists)
365  }
366  }
367  }
368  }
369 
370 
371  public:
372 
373  // ctor w/o elements
374 
375  /**
376  * Default constructor, giving zero capacity and zero memory footprint.
377  */
378  constexpr darray() noexcept
379  : alloc_inst(), begin_( nullptr ), end_( nullptr ), storage_end_( nullptr ),
380  growth_factor_(DEFAULT_GROWTH_FACTOR) {
381  DARRAY_PRINTF("ctor def: %s\n", get_info().c_str());
382  }
383 
384  /**
385  * Creating an empty instance with initial capacity and other (default) properties.
386  * @param capacity initial capacity of the new instance.
387  * @param growth_factor given growth factor
388  * @param alloc given allocator_type
389  */
390  constexpr explicit darray(size_type capacity, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type& alloc = allocator_type())
391  : alloc_inst( alloc ), begin_( allocStore(capacity) ), end_( begin_ ), storage_end_( begin_ + capacity ),
392  growth_factor_( growth_factor ) {
393  DARRAY_PRINTF("ctor 1: %s\n", get_info().c_str());
394  }
395 
396  // copy_ctor on darray elements
397 
398  /**
399  * Creates a new instance, copying all elements from the given darray.<br>
400  * Capacity and size will equal the given array, i.e. the result is a trimmed jau::darray.
401  * @param x the given darray, all elements will be copied into the new instance.
402  */
403  constexpr darray(const darray& x)
404  : alloc_inst( x.alloc_inst ), begin_( clone_range(x.begin_, x.end_) ), end_( begin_ + x.size() ),
405  storage_end_( begin_ + x.size() ), growth_factor_( x.growth_factor_ ) {
406  DARRAY_PRINTF("ctor copy0: this %s\n", get_info().c_str());
407  DARRAY_PRINTF("ctor copy0: x %s\n", x.get_info().c_str());
408  }
409 
410  /**
411  * Creates a new instance, copying all elements from the given darray.<br>
412  * Capacity and size will equal the given array, i.e. the result is a trimmed jau::darray.
413  * @param x the given darray, all elements will be copied into the new instance.
414  * @param growth_factor custom growth factor
415  * @param alloc custom allocator_type instance
416  */
417  constexpr explicit darray(const darray& x, const float growth_factor, const allocator_type& alloc)
418  : alloc_inst( alloc ), begin_( clone_range(x.begin_, x.end_) ), end_( begin_ + x.size() ),
419  storage_end_( begin_ + x.size() ), growth_factor_( growth_factor ) {
420  DARRAY_PRINTF("ctor copy1: this %s\n", get_info().c_str());
421  DARRAY_PRINTF("ctor copy1: x %s\n", x.get_info().c_str());
422  }
423 
424  /**
425  * Creates a new instance with custom initial storage capacity, copying all elements from the given darray.<br>
426  * Size will equal the given array.
427  * <p>
428  * Throws jau::IllegalArgumentException() if <code>_capacity < x.size()</code>.
429  * </p>
430  * @param x the given darray, all elements will be copied into the new instance.
431  * @param _capacity custom initial storage capacity
432  * @param growth_factor custom growth factor
433  * @param alloc custom allocator_type instance
434  */
435  constexpr explicit darray(const darray& x, const size_type _capacity, const float growth_factor, const allocator_type& alloc)
436  : alloc_inst( alloc ), begin_( clone_range( _capacity, x.begin_, x.end_) ), end_( begin_ + x.size() ),
437  storage_end_( begin_ + _capacity ), growth_factor_( growth_factor ) {
438  DARRAY_PRINTF("ctor copy2: this %s\n", get_info().c_str());
439  DARRAY_PRINTF("ctor copy2: x %s\n", x.get_info().c_str());
440  }
441 
442  /**
443  * Like std::vector::operator=(&), assignment
444  */
445  constexpr darray& operator=(const darray& x) {
446  DARRAY_PRINTF("assignment copy.0: this %s\n", get_info().c_str());
447  DARRAY_PRINTF("assignment copy.0: x %s\n", x.get_info().c_str());
448  if( this != &x ) {
449  const size_type capacity_ = capacity();
450  const size_type x_size_ = x.size();
451  dtor_range(begin_, end_);
452  growth_factor_ = x.growth_factor_;
453  if( x_size_ > capacity_ ) {
454  freeStore();
455  begin_ = clone_range(x_size_, x.begin_, x.end_);
456  set_iterator(x_size_, x_size_);
457  } else {
458  ctor_copy_range(begin_, x.begin_, x.end_);
459  set_iterator(x_size_, capacity_);
460  }
461  }
462  DARRAY_PRINTF("assignment copy.X: this %s\n", get_info().c_str());
463  DARRAY_PRINTF("assignment copy.X: x %s\n", x.get_info().c_str());
464  return *this;
465  }
466 
467  // move_ctor on darray elements
468 
469  constexpr darray(darray && x) noexcept
470  : alloc_inst( std::move(x.alloc_inst) ), begin_( std::move(x.begin_) ), end_( std::move(x.end_) ),
471  storage_end_( std::move(x.storage_end_) ), growth_factor_( std::move(x.growth_factor_) )
472  {
473  DARRAY_PRINTF("ctor move0: this %s\n", get_info().c_str());
474  DARRAY_PRINTF("ctor move0: x %s\n", x.get_info().c_str());
475  // Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
476  explicit_bzero((void*)&x, sizeof(x));
477  }
478 
479  constexpr explicit darray(darray && x, const float growth_factor, const allocator_type& alloc) noexcept
480  : alloc_inst( std::move(alloc) ), begin_( std::move(x.begin_) ), end_( std::move(x.end_) ),
481  storage_end_( std::move(x.storage_end_) ), growth_factor_( std::move(growth_factor) )
482  {
483  DARRAY_PRINTF("ctor move1: this %s\n", get_info().c_str());
484  DARRAY_PRINTF("ctor move1: x %s\n", x.get_info().c_str());
485  // Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
486 #if 1
487  explicit_bzero((void*)&x, sizeof(x));
488 #else
489  x.begin_ = nullptr;
490  x.end_ = nullptr;
491  x.storage_end_ = nullptr;
492  x.growth_factor_ = 0.0;
493 #endif
494  }
495 
496  /**
497  * Like std::vector::operator=(&&), move.
498  */
499  constexpr darray& operator=(darray&& x) noexcept {
500  DARRAY_PRINTF("assignment move.0: this %s\n", get_info().c_str());
501  DARRAY_PRINTF("assignment move.0: x %s\n", x.get_info().c_str());
502  if( this != &x ) {
503  clear();
504  alloc_inst = std::move(x.alloc_inst);
505  begin_ = std::move(x.begin_);
506  end_ = std::move(x.end_);
507  storage_end_ = std::move(x.storage_end_);
508  growth_factor_ = std::move( x.growth_factor_ );
509 
510  // Moved source array has been taken over, flush sources' pointer to avoid value_type dtor releasing taken resources!
511  explicit_bzero((void*)&x, sizeof(x));
512  }
513  DARRAY_PRINTF("assignment move.X: this %s\n", get_info().c_str());
514  DARRAY_PRINTF("assignment move.X: x %s\n", x.get_info().c_str());
515  return *this;
516  }
517 
518  // ctor on const_iterator and foreign template iterator
519 
520  /**
521  * Creates a new instance with custom initial storage capacity,
522  * copying all elements from the given const_iterator value_type range [first, last).<br>
523  * Size will equal the range [first, last), i.e. <code>size_type(last-first)</code>.
524  * <p>
525  * Throws jau::IllegalArgumentException() if <code>_capacity < size_type(last - first)</code>.
526  * </p>
527  * @param _capacity custom initial storage capacity
528  * @param first const_iterator to first element of value_type range [first, last)
529  * @param last const_iterator to last element of value_type range [first, last)
530  * @param growth_factor custom growth factor
531  * @param alloc custom allocator_type instance
532  */
533  constexpr explicit darray(const size_type _capacity, const_iterator first, const_iterator last,
535  : alloc_inst( alloc ), begin_( clone_range_check(_capacity, first, last) ), end_(begin_ + size_type(last - first) ),
536  storage_end_( begin_ + _capacity ), growth_factor_( growth_factor ) {
537  DARRAY_PRINTF("ctor iters0: %s\n", get_info().c_str());
538  }
539 
540  /**
541  * Creates a new instance with custom initial storage capacity,
542  * copying all elements from the given template input-iterator value_type range [first, last).<br>
543  * Size will equal the range [first, last), i.e. <code>size_type(last-first)</code>.
544  * <p>
545  * Throws jau::IllegalArgumentException() if <code>_capacity < size_type(last - first)</code>.
546  * </p>
547  * @tparam InputIt template input-iterator custom type
548  * @param _capacity custom initial storage capacity
549  * @param first template input-iterator to first element of value_type range [first, last)
550  * @param last template input-iterator to last element of value_type range [first, last)
551  * @param growth_factor custom growth factor
552  * @param alloc custom allocator_type instance
553  */
554  template< class InputIt >
555  constexpr explicit darray(const size_type _capacity, InputIt first, InputIt last,
557  : alloc_inst( alloc ), begin_( clone_range_foreign(_capacity, first, last) ), end_(begin_ + size_type(last - first) ),
558  storage_end_( begin_ + _capacity ), growth_factor_( growth_factor ) {
559  DARRAY_PRINTF("ctor iters1: %s\n", get_info().c_str());
560  }
561 
562  /**
563  * Creates a new instance,
564  * copying all elements from the given template input-iterator value_type range [first, last).<br>
565  * Size will equal the range [first, last), i.e. <code>size_type(last-first)</code>.
566  * @tparam InputIt template input-iterator custom type
567  * @param first template input-iterator to first element of value_type range [first, last)
568  * @param last template input-iterator to last element of value_type range [first, last)
569  * @param alloc custom allocator_type instance
570  */
571  template< class InputIt >
572  constexpr darray(InputIt first, InputIt last, const allocator_type& alloc = allocator_type())
573  : alloc_inst( alloc ), begin_( clone_range_foreign(size_type(last - first), first, last) ), end_(begin_ + size_type(last - first) ),
574  storage_end_( begin_ + size_type(last - first) ), growth_factor_( DEFAULT_GROWTH_FACTOR ) {
575  DARRAY_PRINTF("ctor iters2: %s\n", get_info().c_str());
576  }
577 
578  /**
579  * Create a new instance from an initializer list.
580  *
581  * @param initlist initializer_list.
582  * @param alloc allocator
583  */
584  constexpr darray(std::initializer_list<value_type> initlist, const allocator_type& alloc = allocator_type())
585  : alloc_inst( alloc ), begin_( clone_range_foreign(initlist.size(), initlist.begin(), initlist.end()) ),
586  end_(begin_ + initlist.size() ), storage_end_( begin_ + initlist.size() ), growth_factor_( DEFAULT_GROWTH_FACTOR ) {
587  DARRAY_PRINTF("ctor initlist: %s\n", get_info().c_str());
588  }
589 
590  ~darray() noexcept {
591  DARRAY_PRINTF("dtor: %s\n", get_info().c_str());
592  clear();
593  }
594 
595  /**
596  * Returns <code>std::numeric_limits<difference_type>::max()</code> as the maximum array size.
597  * <p>
598  * We rely on the signed <code>difference_type</code> for pointer arithmetic,
599  * deducing ranges from iterator.
600  * </p>
601  */
602  constexpr size_type max_size() const noexcept { return DIFF_MAX; }
603 
604  // iterator
605 
606  constexpr iterator begin() noexcept { return begin_; }
607 
608  constexpr const_iterator begin() const noexcept { return begin_; }
609 
610  constexpr const_iterator cbegin() const noexcept { return begin_; }
611 
612  constexpr iterator end() noexcept { return end_; }
613 
614  constexpr const_iterator end() const noexcept { return end_; }
615 
616  constexpr const_iterator cend() const noexcept { return end_; }
617 
618 #if 0
619  constexpr iterator storage_end() noexcept { return storage_end_; }
620 
621  constexpr const_iterator storage_end() const noexcept { return storage_end_; }
622 
623  constexpr const_iterator cstorage_end() const noexcept { return storage_end_; }
624 #endif
625 
626  // read access
627 
628  const allocator_type& get_allocator_ref() const noexcept {
629  return alloc_inst;
630  }
631 
632  allocator_type get_allocator() const noexcept {
633  return allocator_type(alloc_inst);
634  }
635 
636  constexpr float growth_factor() const noexcept {
637  return growth_factor_;
638  }
639 
640  /**
641  * Return the current capacity.
642  */
643  constexpr size_type capacity() const noexcept { return size_type(storage_end_ - begin_); }
644 
645  /**
646  * Return the current capacity() multiplied by the growth factor, minimum is max(capacity()+1, 10).
647  */
648  constexpr size_type get_grown_capacity() const noexcept {
649  const size_type a_capacity = capacity();
650  return std::max<size_type>( std::max<size_type>( MIN_SIZE_AT_GROW, a_capacity+1 ),
651  static_cast<size_type>(a_capacity * growth_factor_ + 0.5f) );
652  }
653 
654  /**
655  * Like std::vector::empty().
656  */
657  constexpr bool empty() const noexcept { return begin_ == end_; }
658 
659  /**
660  * Returns true if capacity has been reached and the next push_back()
661  * will grow the storage and invalidates all iterators and references.
662  */
663  constexpr bool capacity_reached() const noexcept { return end_ >= storage_end_; }
664 
665  /**
666  * Like std::vector::size().
667  */
668  constexpr size_type size() const noexcept { return size_type(end_ - begin_); }
669 
670  // mixed mutable/immutable element access
671 
672  /**
673  * Like std::vector::front(), mutable access.
674  */
675  constexpr reference front() { return *begin_; }
676 
677  /**
678  * Like std::vector::front(), immutable access.
679  */
680  constexpr const_reference front() const { return *begin_; }
681 
682  /**
683  * Like std::vector::back(), mutable access.
684  */
685  constexpr reference back() { return *(end_-1); }
686 
687  /**
688  * Like std::vector::back(), immutable access.
689  */
690  constexpr const_reference back() const { return *(end_-1); }
691 
692  /**
693  * Like std::vector::data(), const immutable pointer
694  */
695  constexpr const_pointer data() const noexcept { return begin_; }
696 
697  /**
698  * Like std::vector::data(), mutable pointer
699  */
700  constexpr pointer data() noexcept { return begin_; }
701 
702  /**
703  * Like std::vector::operator[](size_type), immutable reference.
704  */
706  return *(begin_+i);
707  }
708 
709  /**
710  * Like std::vector::operator[](size_type), mutable reference.
711  */
713  return *(begin_+i);
714  }
715 
716  /**
717  * Like std::vector::at(size_type), immutable reference.
718  */
720  if( 0 <= i && i < size() ) {
721  return *(begin_+i);
722  }
724  }
725 
726  /**
727  * Like std::vector::at(size_type), mutable reference.
728  */
730  if( 0 <= i && i < size() ) {
731  return *(begin_+i);
732  }
734  }
735 
736  // write access, mutable array operations
737 
738  /**
739  * Like std::vector::reserve(), increases this instance's capacity to <code>new_capacity</code>.
740  * <p>
741  * Only creates a new storage and invalidates iterators if <code>new_capacity</code>
742  * is greater than the current jau::darray::capacity().
743  * </p>
744  */
745  void reserve(size_type new_capacity) {
746  const size_type capacity_ = capacity();
747  if( new_capacity > capacity_ ) {
748  grow_storage_move(new_capacity);
749  }
750  }
751 
752  /**
753  * Like std::vector::assign()
754  * @tparam InputIt foreign input-iterator to range of value_type [first, last)
755  * @param first first foreign input-iterator to range of value_type [first, last)
756  * @param last last foreign input-iterator to range of value_type [first, last)
757  */
758  template< class InputIt >
759  constexpr void assign( InputIt first, InputIt last ) {
760  const size_type size_ = size();
761  const size_type capacity_ = capacity();
762  const size_type x_size_ = size_type(last - first);
763  dtor_range(begin_, end_);
764  if( x_size_ > capacity_ ) {
765  freeStore();
766  begin_ = clone_range_foreign(x_size_, first, last);
767  set_iterator(x_size_, x_size_);
768  } else {
769  ctor_copy_range_foreign(begin_, first, last);
770  set_iterator(x_size_, capacity_);
771  }
772  }
773  /**
774  * Like std::vector::assign(), but non-template overload using const_iterator.
775  * @param first first const_iterator to range of value_type [first, last)
776  * @param last last const_iterator to range of value_type [first, last)
777  */
778  constexpr void assign( const_iterator first, const_iterator last ) {
779  const size_type size_ = size();
780  const size_type capacity_ = capacity();
781  const size_type x_size_ = size_type(last - first);
782  dtor_range(begin_, end_);
783  if( x_size_ > capacity_ ) {
784  freeStore();
785  begin_ = clone_range_check(x_size_, first, last);
786  set_iterator(x_size_, x_size_);
787  } else {
788  ctor_copy_range_check(begin_, first, last);
789  set_iterator(x_size_, capacity_);
790  }
791  }
792 
793  /**
794  * Like std::vector::clear(), but ending with zero capacity.
795  */
796  constexpr void clear() noexcept {
797  dtor_range(begin_, end_);
798  freeStore();
799  begin_ = nullptr;
800  end_ = nullptr;
801  storage_end_ = nullptr;
802  }
803 
804  /**
805  * Like std::vector::swap().
806  */
807  constexpr void swap(darray& x) noexcept {
808  DARRAY_PRINTF("swap.0: this %s\n", get_info().c_str());
809  DARRAY_PRINTF("swap.0: x %s\n", x.get_info().c_str());
810  std::swap(alloc_inst, x.alloc_inst);
811  std::swap(begin_, x.begin_);
812  std::swap(end_, x.end_);
813  std::swap(storage_end_, x.storage_end_);
814  std::swap(growth_factor_, x.growth_factor_);
815  DARRAY_PRINTF("swap.X: this %s\n", get_info().c_str());
816  DARRAY_PRINTF("swap.X: x %s\n", x.get_info().c_str());
817  }
818 
819  /**
820  * Like std::vector::pop_back().
821  */
822  constexpr void pop_back() noexcept {
823  if( begin_ != end_ ) {
824  dtor_one( --end_ );
825  }
826  }
827 
828  /**
829  * Like std::vector::erase(), removes the elements at pos.
830  * @return iterator following the last removed element.
831  */
832  constexpr iterator erase (const_iterator pos) {
833  if( begin_ <= pos && pos < end_ ) {
834  dtor_one( const_cast<value_type*>( pos ) );
835  const difference_type right_count = end_ - ( pos + 1 ); // pos is exclusive
836  if( 0 < right_count ) {
837  move_elements(const_cast<value_type*>(pos), pos+1, right_count); // move right elems one left
838  }
839  --end_;
840  }
841  return begin_ <= const_cast<iterator>(pos) && const_cast<iterator>(pos) <= end_ ? const_cast<iterator>(pos) : end_;
842  }
843 
844  /**
845  * Like std::vector::erase(), removes the elements in the range [first, last).
846  * @return iterator following the last removed element.
847  */
848  constexpr iterator erase (iterator first, const_iterator last) {
849  const size_type count = dtor_range(first, last);
850  if( count > 0 ) {
851  const difference_type right_count = end_ - last; // last is exclusive
852  if( 0 < right_count ) {
853  move_elements(first, last, right_count); // move right elems count left
854  }
855  end_ -= count;
856  }
857  return begin_ <= const_cast<iterator>(first) && const_cast<iterator>(first) <= end_ ? const_cast<iterator>(first) : end_;
858  }
859 
860  /**
861  * Like std::vector::insert(), copy
862  * <p>
863  * Inserts the element before pos
864  * and moves all elements from there to the right beforehand.
865  * </p>
866  * <p>
867  * size will be increased by one.
868  * </p>
869  * @param pos iterator before which the content will be inserted. pos may be the end() iterator
870  * @param x element value to insert
871  */
872  constexpr iterator insert(const_iterator pos, const value_type& x) {
873  if( begin_ <= pos && pos <= end_ ) {
874  const size_type pos_idx = pos - begin_;
875  if( end_ == storage_end_ ) {
876  grow_storage_move();
877  }
878  iterator pos_new = begin_ + pos_idx;
879  const difference_type right_count = end_ - pos_new; // include original element at 'pos_new'
880  if( 0 < right_count ) {
881  move_elements(pos_new+1, pos_new, right_count); // move elems one right
882  }
883  new (pos_new) value_type( x ); // placement new
884  ++end_;
885 
886  return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
887  } else {
889  }
890  }
891 
892  /**
893  * Like std::vector::insert(), move
894  * <p>
895  * Inserts the element before the given position
896  * and moves all elements from there to the right beforehand.
897  * </p>
898  * <p>
899  * size will be increased by one.
900  * </p>
901  * @param pos iterator before which the content will be inserted. pos may be the end() iterator
902  * @param x element value to be moved into
903  */
904  constexpr iterator insert(const_iterator pos, value_type&& x) {
905  if( begin_ <= pos && pos <= end_ ) {
906  const size_type pos_idx = pos - begin_;
907  if( end_ == storage_end_ ) {
908  grow_storage_move();
909  }
910  iterator pos_new = begin_ + pos_idx;
911  const difference_type right_count = end_ - pos_new; // include original element at 'pos_new'
912  if( 0 < right_count ) {
913  move_elements(pos_new+1, pos_new, right_count); // move elems one right
914  }
915  new (pos_new) value_type( std::move( x ) ); // placement new
916  ++end_;
917 
918  return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
919  } else {
921  }
922  }
923 
924  /**
925  * Like std::vector::emplace(), construct a new element in place.
926  * <p>
927  * Constructs the element before the given position using placement new
928  * and moves all elements from there to the right beforehand.
929  * </p>
930  * <p>
931  * size will be increased by one.
932  * </p>
933  * @param pos iterator before which the content will be inserted. pos may be the end() iterator
934  * @param args arguments to forward to the constructor of the element
935  */
936  template<typename... Args>
937  constexpr iterator emplace(const_iterator pos, Args&&... args) {
938  if( begin_ <= pos && pos <= end_ ) {
939  const size_type pos_idx = pos - begin_;
940  if( end_ == storage_end_ ) {
941  grow_storage_move();
942  }
943  iterator pos_new = begin_ + pos_idx;
944  const difference_type right_count = end_ - pos_new; // include original element at 'pos_new'
945  if( 0 < right_count ) {
946  move_elements(pos_new+1, pos_new, right_count); // move elems one right
947  }
948  new (pos_new) value_type( std::forward<Args>(args)... ); // placement new, construct in-place
949  ++end_;
950 
951  return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
952  } else {
954  }
955  }
956 
957  /**
958  * Like std::vector::insert(), inserting the value_type range [first, last).
959  * @tparam InputIt foreign input-iterator to range of value_type [first, last)
960  * @param pos iterator before which the content will be inserted. pos may be the end() iterator
961  * @param first first foreign input-iterator to range of value_type [first, last)
962  * @param last last foreign input-iterator to range of value_type [first, last)
963  * @return Iterator pointing to the first element inserted, or pos if first==last.
964  */
965  template< class InputIt >
966  constexpr iterator insert( const_iterator pos, InputIt first, InputIt last ) {
967  if( begin_ <= pos && pos <= end_ ) {
968  const size_type new_elem_count = size_type(last - first);
969  const size_type pos_idx = pos - begin_;
970  if( end_ + new_elem_count >= storage_end_ ) {
971  grow_storage_move(size() + new_elem_count);
972  }
973  iterator pos_new = begin_ + pos_idx;
974  const difference_type right_count = end_ - pos_new; // include original element at 'pos_new'
975  if( 0 < right_count ) {
976  move_elements(pos_new + new_elem_count, pos_new, right_count); // move elems count right
977  }
978  ctor_copy_range_foreign(pos_new, first, last);
979  end_ += new_elem_count;
980 
981  return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
982  } else {
984  }
985  }
986 
987  /**
988  * Like std::vector::push_back(), copy
989  * @param x the value to be added at the tail.
990  */
991  constexpr void push_back(const value_type& x) {
992  if( end_ == storage_end_ ) {
993  grow_storage_move();
994  }
995  new (end_) value_type( x ); // placement new
996  ++end_;
997  }
998 
999  /**
1000  * Like std::vector::push_back(), move
1001  * @param x the value to be added at the tail.
1002  */
1003  constexpr void push_back(value_type&& x) {
1004  if( end_ == storage_end_ ) {
1005  grow_storage_move();
1006  }
1007  new (end_) value_type( std::move(x) ); // placement new, just one element - no optimization
1008  ++end_;
1009  }
1010 
1011  /**
1012  * Like std::vector::emplace_back(), construct a new element in place at the end().
1013  * <p>
1014  * Constructs the element at the end() using placement new.
1015  * </p>
1016  * <p>
1017  * size will be increased by one.
1018  * </p>
1019  * @param args arguments to forward to the constructor of the element
1020  */
1021  template<typename... Args>
1022  constexpr reference emplace_back(Args&&... args) {
1023  if( end_ == storage_end_ ) {
1024  grow_storage_move();
1025  }
1026  new (end_) value_type( std::forward<Args>(args)... ); // placement new, construct in-place
1027  reference res = *end_;
1028  ++end_;
1029  return res;
1030  }
1031 
1032  /**
1033  * Like std::vector::push_back(), but appends the value_type range [first, last).
1034  * @tparam InputIt foreign input-iterator to range of value_type [first, last)
1035  * @param first first foreign input-iterator to range of value_type [first, last)
1036  * @param last last foreign input-iterator to range of value_type [first, last)
1037  */
1038  template< class InputIt >
1039  constexpr void push_back( InputIt first, InputIt last ) {
1040  const size_type count = size_type(last - first);
1041 
1042  if( end_ + count >= storage_end_ ) {
1043  grow_storage_move(size() + count);
1044  }
1045  ctor_copy_range_foreign(end_, first, last);
1046  end_ += count;
1047  }
1048 
1049  /**
1050  * Generic value_type equal comparator to be user defined for e.g. jau::darray::push_back_unique().
1051  * @param a one element of the equality test.
1052  * @param b the other element of the equality test.
1053  * @return true if both are equal
1054  */
1055  typedef bool(*equal_comparator)(const value_type& a, const value_type& b);
1056 
1057  /**
1058  * Like std::vector::push_back(), but only if the newly added element does not yet exist.
1059  * <p>
1060  * Examples
1061  * <pre>
1062  * static jau::darray<Thing>::equal_comparator thingEqComparator =
1063  * [](const Thing &a, const Thing &b) -> bool { return a == b; };
1064  * ...
1065  * jau::darray<Thing> list;
1066  *
1067  * bool added = list.push_back_unique(new_element, thingEqComparator);
1068  * ...
1069  * darray<std::shared_ptr<Thing>> listOfRefs;
1070  * bool added = listOfRefs.push_back_unique(new_element,
1071  * [](const std::shared_ptr<Thing> &a, const std::shared_ptr<Thing> &b) -> bool { return *a == *b; });
1072  * </pre>
1073  * </p>
1074  * @param x the value to be added at the tail, if not existing yet.
1075  * @param comparator the equal comparator to return true if both given elements are equal
1076  * @return true if the element has been uniquely added, otherwise false
1077  */
1078  constexpr bool push_back_unique(const value_type& x, equal_comparator comparator) {
1079  for(auto it = begin_; it != end_; ) {
1080  if( comparator( *it, x ) ) {
1081  return false; // already included
1082  } else {
1083  ++it;
1084  }
1085  }
1086  push_back(x);
1087  return true;
1088  }
1089 
1090  /**
1091  * Erase either the first matching element or all matching elements.
1092  * <p>
1093  * Examples
1094  * <pre>
1095  * darray<Thing> list;
1096  * int count = list.erase_matching(element, true,
1097  * [](const Thing &a, const Thing &b) -> bool { return a == b; });
1098  * ...
1099  * static jau::darray<Thing>::equal_comparator thingRefEqComparator =
1100  * [](const std::shared_ptr<Thing> &a, const std::shared_ptr<Thing> &b) -> bool { return *a == *b; };
1101  * ...
1102  * darray<std::shared_ptr<Thing>> listOfRefs;
1103  * int count = listOfRefs.erase_matching(element, false, thingRefEqComparator);
1104  * </pre>
1105  * </p>
1106  * @param x the value to be added at the tail, if not existing yet.
1107  * @param all_matching if true, erase all matching elements, otherwise only the first matching element.
1108  * @param comparator the equal comparator to return true if both given elements are equal
1109  * @return number of erased elements
1110  */
1111  constexpr int erase_matching(const value_type& x, const bool all_matching, equal_comparator comparator) {
1112  int count = 0;
1113  for(auto it = end_-1; begin_ <= it; --it) {
1114  if( comparator( *it, x ) ) {
1115  erase(it);
1116  ++count;
1117  if( !all_matching ) {
1118  break;
1119  }
1120  }
1121  }
1122  return count;
1123  }
1124 
1125  constexpr_cxx20 std::string toString() const noexcept {
1126  std::string res("{ " + std::to_string( size() ) + ": ");
1127  int i=0;
1128  jau::for_each_const(*this, [&res, &i](const value_type & e) {
1129  if( 1 < ++i ) { res.append(", "); }
1130  res.append( jau::to_string(e) );
1131  } );
1132  res.append(" }");
1133  return res;
1134  }
1135 
1136  constexpr_cxx20 std::string get_info() const noexcept {
1137  difference_type cap_ = (storage_end_-begin_);
1138  difference_type size_ = (end_-begin_);
1139  std::string res("darray[this "+jau::to_hexstring(this)+
1140  ", size "+std::to_string(size_)+"/"+std::to_string(cap_)+
1141  ", growth "+std::to_string(growth_factor_)+
1142  ", uses[mmm "+std::to_string(uses_memmove)+
1143  ", ralloc "+std::to_string(uses_realloc)+
1144  ", smem "+std::to_string(sec_mem)+
1145  "], begin "+jau::to_hexstring(begin_)+
1146  ", end "+jau::to_hexstring(end_)+
1147  ", send "+jau::to_hexstring(storage_end_)+
1148  "]");
1149  return res;
1150  }
1151  };
1152 
1153  /****************************************************************************************
1154  ****************************************************************************************/
1155 
1156  template<typename Value_type, typename Alloc_type>
1157  std::ostream & operator << (std::ostream &out, const darray<Value_type, Alloc_type> &c) {
1158  out << c.toString();
1159  return out;
1160  }
1161 
1162  /****************************************************************************************
1163  ****************************************************************************************/
1164 
1165  template<typename Value_type, typename Alloc_type>
1167  if( &rhs == &lhs ) {
1168  return true;
1169  }
1170  return (rhs.size() == lhs.size() && std::equal(rhs.cbegin(), rhs.cend(), lhs.cbegin()));
1171  }
1172  template<typename Value_type, typename Alloc_type>
1174  return !(rhs==lhs);
1175  }
1176 
1177  template<typename Value_type, typename Alloc_type>
1179  { return std::lexicographical_compare(rhs.cbegin(), rhs.cend(), lhs.cbegin(), lhs.cend()); }
1180 
1181  template<typename Value_type, typename Alloc_type>
1183  { return lhs < rhs; }
1184 
1185  template<typename Value_type, typename Alloc_type>
1187  { return !(lhs < rhs); }
1188 
1189  template<typename Value_type, typename Alloc_type>
1191  { return !(rhs < lhs); }
1192 
1193  template<typename Value_type, typename Alloc_type>
1195  { rhs.swap(lhs); }
1196 
1197  /****************************************************************************************
1198  ****************************************************************************************/
1199 
1200  /**
1201  * <code>template< class T > is_darray_type<T>::value</code> compile-time Type Trait,
1202  * determining whether the given template class is a - or has a darray type, e.g. jau::cow_darray,
1203  * jau::darray.
1204  */
1205  template< class, class = void >
1206  struct is_darray_type : std::false_type { };
1207 
1208  /**
1209  * <code>template< class T > is_darray_type<T>::value</code> compile-time Type Trait,
1210  * determining whether the given template class is a - or has a darray type, e.g. jau::cow_darray,
1211  * jau::darray.
1212  */
1213  template< class T >
1214  struct is_darray_type<T, std::void_t<typename T::darray_tag>> : std::true_type { };
1215 
1216 } /* namespace jau */
1217 
1218 #endif /* JAU_DYN_ARRAY_HPP_ */
jau::darray< Payload >::back
constexpr const_reference back() const
Like std::vector::back(), immutable access.
Definition: darray.hpp:690
jau::darray< Payload >::darray
constexpr darray(darray &&x) noexcept
Definition: darray.hpp:469
constexpr_cxx20
#define constexpr_cxx20
constexpr qualifier replacement for C++20 constexpr.
Definition: cpp_lang_util.hpp:95
callocator.hpp
jau::darray< Payload >::at
const_reference at(size_type i) const
Like std::vector::at(size_type), immutable reference.
Definition: darray.hpp:719
jau::darray< Payload >::difference_type
std::make_signed< size_type >::type difference_type
Definition: darray.hpp:121
jau::darray< Payload >::operator=
constexpr darray & operator=(darray &&x) noexcept
Like std::vector::operator=(&&), move.
Definition: darray.hpp:499
jau::darray< Payload >::front
constexpr const_reference front() const
Like std::vector::front(), immutable access.
Definition: darray.hpp:680
jau::darray< Payload >::darray
constexpr darray(size_type capacity, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creating an empty instance with initial capacity and other (default) properties.
Definition: darray.hpp:390
basic_algos.hpp
jau::darray< Payload >::insert
constexpr iterator insert(const_iterator pos, const value_type &x)
Like std::vector::insert(), copy.
Definition: darray.hpp:872
jau::darray::uses_realloc
constexpr static const bool uses_realloc
Definition: darray.hpp:108
jau::operator<<
std::ostream & operator<<(std::ostream &out, const cow_darray< Value_type, Alloc_type > &c)
Definition: cow_darray.hpp:1029
jau::IllegalArgumentException
Definition: basic_types.hpp:111
jau::darray< Payload >::back
constexpr reference back()
Like std::vector::back(), mutable access.
Definition: darray.hpp:685
jau::is_darray_type
template< class T > is_darray_type<T>::value compile-time Type Trait, determining whether the given t...
Definition: darray.hpp:1206
jau::darray::capacity
constexpr size_type capacity() const noexcept
Return the current capacity.
Definition: darray.hpp:643
jau::darray< Payload >::swap
constexpr void swap(darray &x) noexcept
Like std::vector::swap().
Definition: darray.hpp:807
jau::IndexOutOfBoundsException
Definition: basic_types.hpp:129
jau::darray< Payload >::~darray
~darray() noexcept
Definition: darray.hpp:590
jau::darray::growth_factor
constexpr float growth_factor() const noexcept
Definition: darray.hpp:636
jau::darray< Payload >::get_allocator
allocator_type get_allocator() const noexcept
Definition: darray.hpp:632
jau::darray< Payload >::emplace
constexpr iterator emplace(const_iterator pos, Args &&... args)
Like std::vector::emplace(), construct a new element in place.
Definition: darray.hpp:937
jau::darray< Payload >::cbegin
constexpr const_iterator cbegin() const noexcept
Definition: darray.hpp:610
jau::darray< Payload >::allocator_type
jau::callocator< Payload > allocator_type
Definition: darray.hpp:124
jau::darray< Payload >::darray
constexpr darray(InputIt first, InputIt last, const allocator_type &alloc=allocator_type())
Creates a new instance, copying all elements from the given template input-iterator value_type range ...
Definition: darray.hpp:572
jau::darray< Payload >::empty
constexpr bool empty() const noexcept
Like std::vector::empty().
Definition: darray.hpp:657
jau
Definition: basic_algos.hpp:34
jau::darray< Payload >::insert
constexpr iterator insert(const_iterator pos, value_type &&x)
Like std::vector::insert(), move.
Definition: darray.hpp:904
jau::darray< Payload >::assign
constexpr void assign(InputIt first, InputIt last)
Like std::vector::assign()
Definition: darray.hpp:759
jau::darray::equal_comparator
bool(* equal_comparator)(const value_type &a, const value_type &b)
Generic value_type equal comparator to be user defined for e.g.
Definition: darray.hpp:1055
jau::darray< Payload >::reference
value_type & reference
Definition: darray.hpp:116
jau::to_string
PRAGMA_DISABLE_WARNING_POP constexpr_cxx20 std::string to_string(const endian &v) noexcept
Return std::string representation of the given jau::endian.
Definition: byte_util.hpp:198
jau::darray::uses_secmem
constexpr static const bool uses_secmem
Definition: darray.hpp:109
jau::darray< Payload >::operator[]
reference operator[](size_type i) noexcept
Like std::vector::operator[](size_type), mutable reference.
Definition: darray.hpp:712
jau::darray< Payload >::operator=
constexpr darray & operator=(const darray &x)
Like std::vector::operator=(&), assignment.
Definition: darray.hpp:445
jau::darray< Payload >::darray
constexpr darray(const darray &x, const float growth_factor, const allocator_type &alloc)
Creates a new instance, copying all elements from the given darray.
Definition: darray.hpp:417
jau::swap
void swap(darray< Value_type, Alloc_type > &rhs, darray< Value_type, Alloc_type > &lhs) noexcept
Definition: darray.hpp:1194
jau::darray< Payload >::pop_back
constexpr void pop_back() noexcept
Like std::vector::pop_back().
Definition: darray.hpp:822
ordered_atomic.hpp
jau::callocator::reallocate
constexpr value_type * reallocate(value_type *p, std::size_t old_size, std::size_t new_size)
Definition: callocator.hpp:105
E_FILE_LINE
#define E_FILE_LINE
Definition: basic_types.hpp:64
jau::darray
Implementation of a dynamic linear array storage, aka vector.
Definition: darray.hpp:102
jau::darray< Payload >::push_back
constexpr void push_back(const value_type &x)
Like std::vector::push_back(), copy.
Definition: darray.hpp:991
jau::darray< Payload >::emplace_back
constexpr reference emplace_back(Args &&... args)
Like std::vector::emplace_back(), construct a new element in place at the end().
Definition: darray.hpp:1022
jau::darray< Payload >::pointer
value_type * pointer
Definition: darray.hpp:114
jau::darray< Payload >::push_back
constexpr void push_back(InputIt first, InputIt last)
Like std::vector::push_back(), but appends the value_type range [first, last).
Definition: darray.hpp:1039
jau::darray< Payload >::erase
constexpr iterator erase(iterator first, const_iterator last)
Like std::vector::erase(), removes the elements in the range [first, last).
Definition: darray.hpp:848
jau::swap
void swap(cow_darray< Value_type, Alloc_type > &rhs, cow_darray< Value_type, Alloc_type > &lhs) noexcept
Definition: cow_darray.hpp:1073
jau::darray< Payload >::darray
constexpr darray(const darray &x)
Creates a new instance, copying all elements from the given darray.
Definition: darray.hpp:403
jau::darray< Payload >::at
reference at(size_type i)
Like std::vector::at(size_type), mutable reference.
Definition: darray.hpp:729
jau::darray< Payload >::toString
constexpr_cxx20 std::string toString() const noexcept
Definition: darray.hpp:1125
jau::darray< Payload >::value_type
Payload value_type
Definition: darray.hpp:113
jau::callocator::deallocate
void deallocate(value_type *p, std::size_t n)
Definition: callocator.hpp:117
jau::darray::begin
constexpr iterator begin() noexcept
Definition: darray.hpp:606
jau::darray< Payload >::front
constexpr reference front()
Like std::vector::front(), mutable access.
Definition: darray.hpp:675
jau::darray::size
constexpr size_type size() const noexcept
Like std::vector::size().
Definition: darray.hpp:668
jau::darray< Payload >::iterator
value_type * iterator
Definition: darray.hpp:118
jau::darray< Payload >::const_iterator
const value_type * const_iterator
Definition: darray.hpp:119
jau::darray< Payload >::darray
constexpr darray(std::initializer_list< value_type > initlist, const allocator_type &alloc=allocator_type())
Create a new instance from an initializer list.
Definition: darray.hpp:584
jau::darray< Payload >::begin
constexpr const_iterator begin() const noexcept
Definition: darray.hpp:608
jau::darray::end
constexpr iterator end() noexcept
Definition: darray.hpp:612
jau::darray< Payload >::darray_tag
bool darray_tag
Used to determine whether this type is a darray or has a darray, see ::is_darray_type<T>
Definition: darray.hpp:127
jau::for_each_const
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
Definition: basic_algos.hpp:323
jau::darray::get_grown_capacity
constexpr size_type get_grown_capacity() const noexcept
Return the current capacity() multiplied by the growth factor, minimum is max(capacity()+1,...
Definition: darray.hpp:648
jau::operator<=
bool operator<=(const cow_darray< Value_type, Alloc_type > &rhs, const cow_darray< Value_type, Alloc_type > &lhs)
Definition: cow_darray.hpp:1065
debug.hpp
jau::darray< Payload >::const_reference
const value_type & const_reference
Definition: darray.hpp:117
jau::darray< Payload >::assign
constexpr void assign(const_iterator first, const_iterator last)
Like std::vector::assign(), but non-template overload using const_iterator.
Definition: darray.hpp:778
jau::darray< Payload >::darray
constexpr darray() noexcept
Default constructor, giving zero capacity and zero memory footprint.
Definition: darray.hpp:378
jau::darray< Payload >::get_allocator_ref
const allocator_type & get_allocator_ref() const noexcept
Definition: darray.hpp:628
jau::operator>
bool operator>(const cow_darray< Value_type, Alloc_type > &rhs, const cow_darray< Value_type, Alloc_type > &lhs)
Definition: cow_darray.hpp:1061
jau::darray< Payload >::erase_matching
constexpr int erase_matching(const value_type &x, const bool all_matching, equal_comparator comparator)
Erase either the first matching element or all matching elements.
Definition: darray.hpp:1111
jau::to_hexstring
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
Definition: string_util.hpp:104
jau::darray< Payload >::max_size
constexpr size_type max_size() const noexcept
Returns std::numeric_limits<difference_type>::max() as the maximum array size.
Definition: darray.hpp:602
jau::darray::get_info
constexpr_cxx20 std::string get_info() const noexcept
Definition: darray.hpp:1136
jau::OutOfMemoryError
Definition: basic_types.hpp:99
jau::darray::DEFAULT_GROWTH_FACTOR
constexpr static const float DEFAULT_GROWTH_FACTOR
Default growth factor using the golden ratio 1.618.
Definition: darray.hpp:105
jau::callocator< Payload >
jau::darray< Payload >::darray
constexpr darray(const size_type _capacity, InputIt first, InputIt last, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creates a new instance with custom initial storage capacity, copying all elements from the given temp...
Definition: darray.hpp:555
jau::darray< Payload >::darray
constexpr darray(darray &&x, const float growth_factor, const allocator_type &alloc) noexcept
Definition: darray.hpp:479
jau::operator!=
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:155
basic_types.hpp
jau::darray< Payload >::darray
constexpr darray(const darray &x, const size_type _capacity, const float growth_factor, const allocator_type &alloc)
Creates a new instance with custom initial storage capacity, copying all elements from the given darr...
Definition: darray.hpp:435
jau::darray< Payload >::size_type
jau::nsize_t size_type
Definition: darray.hpp:120
jau::darray< Payload >::end
constexpr const_iterator end() const noexcept
Definition: darray.hpp:614
jau::UnsupportedOperationException
Definition: basic_types.hpp:123
jau::darray< Payload >::reserve
void reserve(size_type new_capacity)
Like std::vector::reserve(), increases this instance's capacity to new_capacity.
Definition: darray.hpp:745
jau::darray< Payload >::const_pointer
const value_type * const_pointer
Definition: darray.hpp:115
jau::darray< Payload >::operator[]
const_reference operator[](size_type i) const noexcept
Like std::vector::operator[](size_type), immutable reference.
Definition: darray.hpp:705
jau::operator>=
bool operator>=(const cow_darray< Value_type, Alloc_type > &rhs, const cow_darray< Value_type, Alloc_type > &lhs)
Definition: cow_darray.hpp:1069
jau::darray< Payload >::darray
constexpr darray(const size_type _capacity, const_iterator first, const_iterator last, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creates a new instance with custom initial storage capacity, copying all elements from the given cons...
Definition: darray.hpp:533
jau::callocator::allocate
value_type * allocate(std::size_t n, const void *hint)
Definition: callocator.hpp:89
jau::darray< Payload >::erase
constexpr iterator erase(const_iterator pos)
Like std::vector::erase(), removes the elements at pos.
Definition: darray.hpp:832
jau::darray< Payload >::insert
constexpr iterator insert(const_iterator pos, InputIt first, InputIt last)
Like std::vector::insert(), inserting the value_type range [first, last).
Definition: darray.hpp:966
jau::darray::uses_memmove
constexpr static const bool uses_memmove
Definition: darray.hpp:107
jau::darray< Payload >::data
constexpr const_pointer data() const noexcept
Like std::vector::data(), const immutable pointer.
Definition: darray.hpp:695
jau::operator==
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
Definition: callocator.hpp:142
DARRAY_PRINTF
#define DARRAY_PRINTF(...)
Definition: darray.hpp:53
jau::darray< Payload >::cend
constexpr const_iterator cend() const noexcept
Definition: darray.hpp:616
jau::darray::clear
constexpr void clear() noexcept
Like std::vector::clear(), but ending with zero capacity.
Definition: darray.hpp:796
jau::operator<
bool operator<(const cow_darray< Value_type, Alloc_type > &rhs, const cow_darray< Value_type, Alloc_type > &lhs)
Definition: cow_darray.hpp:1052
jau::darray< Payload >::push_back_unique
constexpr bool push_back_unique(const value_type &x, equal_comparator comparator)
Like std::vector::push_back(), but only if the newly added element does not yet exist.
Definition: darray.hpp:1078
jau::darray< Payload >::push_back
constexpr void push_back(value_type &&x)
Like std::vector::push_back(), move.
Definition: darray.hpp:1003
jau::darray< Payload >::data
constexpr pointer data() noexcept
Like std::vector::data(), mutable pointer.
Definition: darray.hpp:700
jau::darray< Payload >::capacity_reached
constexpr bool capacity_reached() const noexcept
Returns true if capacity has been reached and the next push_back() will grow the storage and invalida...
Definition: darray.hpp:663