chunkedseq
container library for large in-memory data sets
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
fixedcapacitybase.hpp
Go to the documentation of this file.
1 
13 #include <assert.h>
14 #include <memory>
15 #include <cstring>
16 #include <type_traits>
17 #include <algorithm>
18 
19 #include "segment.hpp"
20 
21 #ifndef _PASL_DATA_FIXEDCAPACITYBASE_H_
22 #define _PASL_DATA_FIXEDCAPACITYBASE_H_
23 
24 namespace pasl {
25 namespace data {
26 namespace fixedcapacity {
27 namespace base {
28 
29 /***********************************************************************/
30 
31 /*---------------------------------------------------------------------*/
32 /* Array allocation */
33 
34 template <class Item, int Capacity>
36 private:
37 
38  class Deleter {
39  public:
40  void operator()(Item* items) {
41  free(items);
42  }
43  };
44 
45  std::unique_ptr<Item[], Deleter> items;
46 
47  // to disable copying
48  heap_allocator(const heap_allocator& other);
49  heap_allocator& operator=(const heap_allocator& other);
50 
51 public:
52 
53  using value_type = Item;
55 
56  static constexpr int capacity = Capacity;
57 
59  Item* p = (value_type*)malloc(sizeof(value_type) * capacity);
60  assert(p != NULL);
61  items.reset(p);
62  }
63 
64  // move assignment operator
65  heap_allocator(self_type&& x) = default;
66  self_type& operator=(self_type&& a) = default;
67 
68  value_type& operator[](int i) const {
69  assert(items != NULL);
70  assert(i >= 0);
71  return items[i];
72  }
73 
74  void swap(heap_allocator& other) {
75  std::swap(items, other.items);
76  }
77 
78 };
79 
80 template <class Item, int Capacity>
82 private:
83 
84  mutable Item items[Capacity];
85 
86 public:
87 
88  typedef Item value_type;
89 
90  static constexpr int capacity = Capacity;
91 
92  value_type& operator[](int n) const {
93  assert(n >= 0);
94  assert(n < capacity);
95  return items[n];
96  }
97 
98  void swap(inline_allocator& other) {
99  value_type tmp_items[capacity];
100  for (int i = 0; i < capacity; i++)
101  tmp_items[i] = items[i];
102  for (int i = 0; i < capacity; i++)
103  items[i] = other.items[i];
104  for (int i = 0; i < capacity; i++)
105  other.items[i] = tmp_items[i];
106  }
107 
108 };
109 
110 /*---------------------------------------------------------------------*/
111 /* Data movement */
112 
126 template <class Alloc>
127 void copy(typename Alloc::pointer destination,
128  typename Alloc::const_pointer source,
129  typename Alloc::size_type num) {
130  /* Taken from STL documentation:
131  When copying overlapping ranges, std::copy is appropriate
132  when copying to the left (beginning of the destination
133  range is outside the source range) while std::copy_backward
134  is appropriate when copying to the right (end of the destination
135  range is outside the source range).
136  */
137  if (destination < source || destination >= source+num)
138  std::copy(source, source+num, destination);
139  else
140  std::copy_backward(source, source+num, destination+num);
141 }
142 
143 template <class Alloc>
144 void pblit(typename Alloc::const_pointer t1, int i1,
145  typename Alloc::pointer t2, int i2,
146  int nb) {
147  copy<Alloc>(t2 + i2, t1 + i1, nb);
148 }
149 
150 template <class Alloc>
151 void destroy_items(typename Alloc::pointer t, int i, int nb) {
152  typedef typename Alloc::size_type size_type;
153  Alloc alloc;
154  for (size_type k = 0; k < nb; k++)
155  alloc.destroy(&t[k + i]);
156 }
157 
158 template <class Alloc>
159 void destroy_items(typename Alloc::pointer t, int nb) {
160  destroy_items<Alloc>(t, 0, nb);
161 }
162 
181 template <class Alloc>
182 void pshiftn(typename Alloc::pointer t,
183  typename Alloc::size_type num,
184  int shift_by) {
185  copy<Alloc>(t + shift_by, t, num);
186 }
187 
193 template <class Alloc>
194 void pfill(typename Alloc::pointer first,
195  typename Alloc::pointer last,
196  typename Alloc::const_reference val) {
197  std::fill(first, last, val);
198 }
199 
200 /*---------------------------------------------------------------------*/
201 /* Data movement for fixed-capacity arrays with possible wraparound */
202 
203 /* copy n elements from an array t1 of size capacity,
204  * starting at index i1 and possibly wrapping around, into an
205  * array t2 starting at index i2 and not wrapping around.
206  */
207 template <class Alloc, int capacity>
208 void copy_data_wrap_src(typename Alloc::const_pointer t1, int i1,
209  typename Alloc::pointer t2, int i2,
210  int nb) {
211  int j1 = i1 + nb;
212  if (j1 <= capacity) {
213  pblit<Alloc>(t1, i1, t2, i2, nb);
214  } else {
215  int na = capacity - i1;
216  int i2_n = (i2 + na) % capacity;
217  pblit<Alloc>(t1, i1, t2, i2, na);
218  pblit<Alloc>(t1, 0, t2, i2_n, nb - na);
219  }
220 }
221 
222 /* copy n elements from an array t1 starting at index i1
223  * and not wrapping around, into an array t2 of size capacity,
224  * starting at index i2 and possibly wrapping around.
225  */
226 template <class Alloc, int capacity>
227 void copy_data_wrap_dst(typename Alloc::const_pointer t1, int i1,
228  typename Alloc::pointer t2, int i2,
229  int nb) {
230  int j2 = i2 + nb;
231  if (j2 <= capacity) {
232  pblit<Alloc>(t1, i1, t2, i2, nb);
233  } else {
234  int na = capacity - i2;
235  int i1_n = (i1 + na) % capacity;
236  pblit<Alloc>(t1, i1, t2, i2, na);
237  pblit<Alloc>(t1, i1_n, t2, 0, nb - na);
238  }
239 }
240 
241 /* copy n elements from an array t1 starting at index i1
242  * and possibly wrapping around, into an array t2 starting at index
243  * i2 and possibly wrapping around. Both arrays are assumed to be
244  * of size capacity.
245  */
246 template <class Alloc, int capacity>
247 void copy_data_wrap_src_and_dst(typename Alloc::const_pointer t1, int i1,
248  typename Alloc::pointer t2, int i2,
249  int nb) {
250  int j1 = i1 + nb;
251  if (j1 <= capacity) {
252  copy_data_wrap_dst<Alloc, capacity>(t1, i1, t2, i2, nb);
253  } else {
254  int na = capacity - i1;
255  int i2_n = (i2 + na) % capacity;
256  copy_data_wrap_dst<Alloc, capacity>(t1, i1, t2, i2, na);
257  copy_data_wrap_src_and_dst<Alloc, capacity>(t1, 0, t2, i2_n, nb - na);
258  }
259 }
260 
261 /* calls the destructor of the first nb items starting at position i
262  * in the circular buffer pointed to by t, possibly wrapping around.
263  */
264 template <class Alloc, int capacity>
265 void destroy_items_wrap_target(typename Alloc::pointer t, int i, int nb) {
266  int j = i + nb;
267  if (j <= capacity) {
268  destroy_items<Alloc>(t, i, nb);
269  } else {
270  int na = capacity - i;
271  destroy_items<Alloc>(t, i, na);
272  destroy_items<Alloc>(t, 0, nb - na);
273  }
274 }
275 
276 /*---------------------------------------------------------------------*/
277 /* Loops */
278 
286 template <class Alloc>
288 public:
289 
290  typedef Alloc allocator_type;
291  typedef typename Alloc::value_type value_type;
292  typedef typename Alloc::reference reference;
293  typedef typename Alloc::const_reference const_reference;
294  typedef typename Alloc::size_type size_type;
295 
296  value_type v;
297 
298  const_foreach_body(const_reference v) : v(v) { }
299 
300  void operator()(size_type i, reference dst) const {
301  dst = v;
302  }
303 
304 };
305 
312 template <class Alloc, class Body>
314 public:
315  typedef Alloc allocator_type;
316  typedef typename Alloc::size_type size_type;
317  typedef typename Alloc::reference reference;
318 
319  Body body;
320  size_type start;
321 
322  apply_foreach_body(const Body& body, size_type start = 0)
323  : body(body), start(start) { }
324 
325  void operator()(size_type i, reference dst) const {
326  body(dst);
327  }
328 
329 };
330 
344 template <class Body>
345 void papply(typename Body::allocator_type::pointer t,
346  typename Body::allocator_type::size_type num,
347  typename Body::allocator_type::size_type k,
348  const Body& body) {
349  typedef typename Body::allocator_type::size_type size_type;
350  for (size_type i = 0; i < num; i++)
351  body(k + i, t[i]);
352 }
353 
354 /* special case which more efficiently initializes the array with a
355  * constant value
356  */
357 template <class Body>
358 void papply(typename Body::allocator_type::pointer t,
359  typename Body::allocator_type::size_type num,
360  typename Body::allocator_type::size_type k,
363  value_type val;
364  body(0, val);
365  pfill<typename Body::allocator_type>(t, t + num, val);
366 }
367 
368 /* applies the client-supplied function to the first nb cells
369  * starting at index i, possibly wrapping around.
370  */
371 template <class Body, int capacity>
372 void papply_wrap_dst(typename Body::allocator_type::pointer t,
373  int i,
374  int nb,
375  typename Body::allocator_type::size_type k,
376  const Body& body) {
377  int j = i + nb;
378  if (j <= capacity) {
379  papply<Body>(t + i, nb, k, body);
380  } else {
381  int na = capacity - i;
382  papply<Body>(t + i, na, k, body);
383  papply<Body>(t, nb - na, na, body);
384  }
385 }
386 
387 template <class Body, int capacity>
388 void papply_wrap_dst(typename Body::allocator_type::pointer t,
389  int i,
390  int nb,
391  const Body& body) {
392  papply_wrap_dst<Body, capacity>(t, i, nb, 0, body);
393 }
394 
395 /*---------------------------------------------------------------------*/
396 /* Ring buffer based on indices */
397 
414 template <class Array_alloc,
415 class Item_alloc = std::allocator<typename Array_alloc::value_type> >
417 public:
418 
419  typedef int size_type;
421  typedef Item_alloc allocator_type;
423 
424  static constexpr int capacity = Array_alloc::capacity;
425 
426 private:
427 
428  int fr;
429  int sz;
430  Item_alloc alloc;
431  Array_alloc array;
432 
433 public:
434 
436  : fr(0), sz(0) {
437  }
438 
440  : fr(other.fr), sz(other.sz) {
441  copy_data_wrap_src_and_dst<Item_alloc, capacity>(&other.array[0], other.fr, &array[0], fr, other.sz);
442  }
443 
444  ringbuffer_idx(size_type nb, const value_type& val) {
446  }
447 
449  clear();
450  }
451 
452  inline int size() const {
453  return sz;
454  }
455 
456  inline bool full() const {
457  return size() == capacity;
458  }
459 
460  inline bool empty() const {
461  return size() == 0;
462  }
463 
464  inline bool partial() const {
465  return !empty() && !full(); // TODO: could be optimized
466  }
467 
468  inline void push_front(const value_type& x) {
469  assert(! full());
470  fr--;
471  if (fr == -1)
472  fr += capacity;
473  sz++;
474  alloc.construct(&array[fr], x);
475  }
476 
477  inline void push_back(const value_type& x) {
478  assert(! full());
479  int bk = (fr + sz);
480  if (bk >= capacity)
481  bk -= capacity;
482  sz++;
483  alloc.construct(&array[bk], x);
484  }
485 
486  inline value_type& front() const {
487  assert(! empty());
488  return array[fr];
489  }
490 
491  inline value_type& back() const {
492  assert(! empty());
493  int bk = fr + sz - 1;
494  if (bk >= capacity)
495  bk -= capacity;
496  return array[bk];
497  }
498 
499  inline value_type pop_front() {
500  assert(! empty());
501  value_type v = front();
502  alloc.destroy(&(front()));
503  fr++;
504  if (fr == capacity)
505  fr = 0;
506  sz--;
507  return v;
508  }
509 
510  inline value_type pop_back() {
511  assert(! empty());
512  value_type v = back();
513  alloc.destroy(&(back()));
514  sz--;
515  return v;
516  }
517 
518  /* DEPRECATED: using modulo is too slow
519  inline void push_front(const value_type& x) {
520  assert(! full());
521  fr = (fr - 1 + capacity) % capacity;
522  sz++;
523  alloc.construct(&array[fr], x);
524  }
525 
526  inline void push_back(const value_type& x) {
527  assert(! full());
528  int bk = (fr + sz) % capacity;
529  sz++;
530  alloc.construct(&array[bk], x);
531  }
532 
533  inline value_type& front() const {
534  assert(! empty());
535  return array[fr];
536  }
537 
538  inline value_type& back() const {
539  assert(! empty());
540  int bk = (fr + sz - 1) % capacity;
541  return array[bk];
542  }
543 
544  inline value_type pop_front() {
545  assert(! empty());
546  value_type v = front();
547  alloc.destroy(&(front()));
548  fr = (fr + 1) % capacity;
549  sz--;
550  return v;
551  }
552 
553  inline value_type pop_back() {
554  assert(! empty());
555  value_type v = back();
556  alloc.destroy(&(back()));
557  sz--;
558  return v;
559  }
560  */
561 
563 
564  void frontn(value_type* dst, int nb) {
565  assert(size() >= nb);
566  copy_data_wrap_src<Item_alloc, capacity>(&array[0], fr, dst, 0, nb);
567  }
568 
569  void backn(value_type* dst, int nb) {
570  assert(size() >= nb);
571  int i_new = (fr + sz - nb) % capacity;
572  copy_data_wrap_src<Item_alloc, capacity>(&array[0], i_new, dst, 0, nb);
573  }
574 
575  void pushn_front(const value_type* xs, int nb) {
576  assert(nb + size() <= capacity);
577  int fr_new = (fr - nb + capacity) % capacity;
578  copy_data_wrap_dst<Item_alloc, capacity>(xs, 0, &array[0], fr_new, nb);
579  fr = fr_new;
580  sz += nb;
581  }
582 
583  void pushn_back(const value_type* xs, int nb) {
584  assert(nb + size() <= capacity);
585  int i = (fr + sz) % capacity;
586  copy_data_wrap_dst<Item_alloc, capacity>(xs, 0, &array[0], i, nb);
587  sz += nb;
588  }
589 
590  void popn_front(int nb) {
591  assert(size() >= nb);
592  destroy_items_wrap_target<Item_alloc, capacity>(&array[0], fr, nb);
593  fr = (fr + nb) % capacity;
594  sz -= nb;
595  }
596 
597  template <class Body>
598  void pushn_back(const Body& body, int nb) {
599  assert(nb + size() <= capacity);
600  int i = (fr + sz) % capacity;
601  papply_wrap_dst<Body, capacity>(&array[0], i, nb, body);
602  sz += nb;
603  }
604 
605  void popn_back(int nb) {
606  assert(size() >= nb);
607  int i_new = (fr + sz - nb) % capacity;
608  destroy_items_wrap_target<Item_alloc, capacity>(&array[0], i_new, nb);
609  sz -= nb;
610  }
611 
612  void popn_front(value_type* dst, int nb) {
613  frontn(dst, nb);
614  popn_front(nb);
615  }
616 
617  void popn_back(value_type* dst, int nb) {
618  backn(dst, nb);
619  popn_back(nb);
620  }
621 
623  int i1 = (fr + sz - nb) % capacity;
624  int i2 = (target.fr - nb + capacity) % capacity;
625  copy_data_wrap_src_and_dst<Item_alloc, capacity>(&array[0], i1, &target.array[0], i2, nb);
626  sz -= nb;
627  target.sz += nb;
628  target.fr = i2;
629  }
630 
632  int i1 = fr;
633  int i2 = (target.fr + target.sz) % capacity;
634  copy_data_wrap_src_and_dst<Item_alloc, capacity>(&array[0], i1, &target.array[0], i2, nb);
635  sz -= nb;
636  target.sz += nb;
637  fr = (i1 + nb) % capacity;
638  }
639 
640 private:
641 
642  static value_type& subscript(value_type* array, int fr, int sz, int ix) {
643  assert(array != NULL);
644  assert(ix >= 0);
645  assert(ix < sz);
646  return array[(fr + ix) % capacity];
647  }
648 
649 public:
650 
651  value_type& operator[](int ix) const {
652  return subscript(&array[0], fr, size(), ix);
653  }
654 
655  value_type& operator[](size_t ix) const {
656  return subscript(&array[0], fr, size(), (int)ix);
657  }
658 
659  void clear() {
660  popn_back(size());
661  }
662 
663  void swap(ringbuffer_idx& other) {
664  std::swap(fr, other.fr);
665  std::swap(sz, other.sz);
666  array.swap(other.array);
667  }
668 
669  segment_type segment_by_index(int i) const {
670  assert(i >= 0);
671  assert(i < size());
672  value_type* p = subscript(&array[0], fr, size(), i);
673  value_type* fr_ptr = &front();
674  value_type& bk_ptr = &back();
675  return segment_of_ringbuffer(p, fr_ptr, bk_ptr, &array[0], capacity);
676  }
677 
678  int index_of_pointer(const value_type* p) const {
679  assert(p >= &array[0]);
680  assert(p <= &array[capacity-1]);
681  value_type* first = &array[fr];
682  if (p < first) { // wraparound
683  int nb1 = capacity - fr;
684  int nb2 = (int)(p - &array[0]);
685  return nb1 + nb2;
686  } else {
687  return (int)(p - first);
688  }
689  }
690 
691  template <class Body>
692  void for_each(const Body& body) const {
693  int bk = fr + sz;
694  if (bk <= capacity) {
695  for (int i = fr; i < bk; i++)
696  body(array[i]);
697  } else {
698  for (int i = fr; i < capacity; i++)
699  body(array[i]);
700  for (int i = 0; i < (bk - capacity); i++)
701  body(array[i]);
702  }
703  }
704 
705  template <class Body>
706  void for_each_segment(int lo, int hi, const Body& body) {
707  if (hi - lo <= 0 || hi < 1)
708  return;
709  segment_type seg1 = segment_by_index(int(lo));
710  segment_type seg2 = segment_by_index(int(hi - 1));
711  if (seg1.begin == seg2.begin) {
712  body(seg1.middle, seg2.middle + 1);
713  } else {
714  body(seg1.middle, seg1.end);
715  body(seg2.begin, seg2.middle + 1);
716  }
717  }
718 
719 };
720 
721 /*---------------------------------------------------------------------*/
722 /* Ring buffer based on pointers */
723 
745 template <class Array_alloc,
746 class Item_alloc = std::allocator<typename Array_alloc::value_type> >
748 public:
749 
751  static constexpr int capacity = Array_alloc::capacity - 1;
752  // max number of items that can be stored
753  // recall that at least one cell must be empty
754 
755 private:
756 
757  value_type* fr; // address of the cell storing the front item
758  value_type* bk; // address of the cell storing the back item
759  Item_alloc alloc;
760  Array_alloc array;
761 
762  // when container empty, bk is just one cell before back (up to wrap-around)
763  // when container is full, there is exactly one empty cell between bk and fr
764 
765  // number of cells in the array
766  static constexpr int nb_cells = Array_alloc::capacity;
767 
768  // address of the first cell of the array
769  inline value_type* beg() const {
770  return &array[0];
771  }
772 
773  // address of the last cell of the array
774  inline value_type* end() const {
775  return &array[nb_cells-1];
776  }
777 
778  inline void check() const {
779  assert(bk >= beg());
780  assert(fr >= beg());
781  assert(bk <= end());
782  assert(fr <= end());
783  }
784 
785  inline void init() {
786  fr = beg();
787  bk = end();
788  }
789 
790  inline value_type* next(value_type* p) const {
791  if (p == end())
792  return beg();
793  else
794  return p + 1;
795  }
796 
797  inline value_type* nextn(value_type* p, int nb) const {
798  assert(0 <= nb && nb <= nb_cells);
799  value_type* q = p + nb;
800  if (q <= end())
801  return q;
802  else
803  return q - nb_cells;
804  }
805 
806  inline value_type* prev(value_type* p) const {
807  if (p == beg())
808  return end();
809  else
810  return p - 1;
811  }
812 
813  inline value_type* prevn(value_type* p, int nb) const {
814  assert(0 <= nb && nb <= nb_cells);
815  value_type* q = p - nb;
816  if (q >= beg())
817  return q;
818  else
819  return q + nb_cells;
820  }
821 
822  // Remark: "ix" denotes an index in the array, whereas "i" is an index in the buffer
823  inline int array_index_of_pointer(const value_type* p) const {
824  assert(p >= beg());
825  assert(p <= end());
826  int ix = (int) (p - beg());
827  assert(0 <= ix);
828  assert (ix < nb_cells);
829  return ix;
830  }
831 
832 public:
833 
834  typedef int size_type;
835  typedef Item_alloc allocator_type;
838 
840  init();
841  }
842 
844  init();
845  int other_sz = other.size();
846  if (other_sz == 0)
847  return;
848  int other_ix = other.array_index_of_pointer(other.fr);
849  int ix = array_index_of_pointer(fr);
850  copy_data_wrap_src_and_dst<allocator_type, nb_cells>(other.beg(), other_ix, beg(), ix, other_sz);
851  bk = nextn(bk, other_sz);
852  check();
853  }
854 
855  ringbuffer_ptr(size_type nb, const value_type& val) {
856  init();
858  check();
859  }
860 
862  check();
863  clear();
864  check();
865  }
866 
867  // converts an index in the buffer into a pointer on a cell
868  inline value_type* pointer_of_index(int i) const {
869  assert(0 <= i && i < size());
870  return nextn(fr, i);
871  }
872 
873  // converts a pointer on a cell into an index in the buffer;
874  // remark: if the array is empty, then the return value is unspecified
875  inline int index_of_pointer(const value_type* p) const {
876  assert(p >= beg());
877  assert(p <= end());
878  int i = int(p - fr);
879  if (i < 0)
880  i += nb_cells;
881  assert(0 <= i);
882  assert(i < nb_cells); // we purposely allow i >= size() here
883  assert(i <= size());
884  return i;
885  }
886 
887  inline int size() const {
888  int nb = int(bk - fr) + 1;
889  if (nb < 0)
890  nb += nb_cells;
891  if (nb == nb_cells)
892  return 0;
893  else
894  return nb;
895  }
896 
897  inline bool full() const {
898  return (bk + 2 == fr) || (bk + 2 - nb_cells == fr);
899  // very slow:
900  // return (size() == capacity);
901  // alternative:
902  // return (nextn(bk, 2) == fr);
903  }
904 
905  inline bool empty() const {
906  return (bk + 1 == fr) || (bk + 1 - nb_cells == fr);
907  // very slow:
908  // return (size() == 0);
909  // slow:
910  // int nb = bk - fr + 1;
911  // return (nb == 0) || (nb == nb_cells);
912  }
913 
914  inline bool partial() const {
915  return !empty() && !full(); // TODO: could be optimized
916  }
917 
918  inline value_type& front() const {
919  assert(! empty());
920  return *fr;
921  }
922 
923  inline value_type& back() const {
924  assert(! empty());
925  return *bk;
926  }
927 
928  inline void push_front(const value_type& x) {
929  assert(! full());
930  fr = prev(fr);
931  alloc.construct(fr, x);
932  }
933 
934  inline void push_back(const value_type& x) {
935  assert(! full());
936  bk = next(bk);
937  alloc.construct(bk, x);
938  }
939 
940  inline value_type pop_front() {
941  assert(! empty());
942  value_type v = *fr;
943  alloc.destroy(fr);
944  fr = next(fr);
945  return v;
946  }
947 
948  inline value_type pop_back() {
949  assert(! empty());
950  value_type v = *bk;
951  alloc.destroy(bk);
952  bk = prev(bk);
953  return v;
954  }
955 
956  void frontn(value_type* dst, int nb) const {
957  assert(0 <= nb && nb <= size());
958  int ix = array_index_of_pointer(fr);
959  copy_data_wrap_src<Item_alloc, nb_cells>(beg(), ix, dst, 0, nb);
960  }
961 
962  void backn(value_type* dst, int nb) const {
963  assert(0 <= nb && nb <= size());
964  if (nb == 0)
965  return;
966  value_type* p_start = prevn(bk, nb-1); // nb-1 because bk is inclusive
967  int ix = array_index_of_pointer(p_start);
968  copy_data_wrap_src<Item_alloc, nb_cells>(beg(), ix, dst, 0, nb);
969  }
970 
971  void pushn_front(const value_type* src, int nb) {
972  assert(0 <= nb && nb + size() <= capacity);
973  fr = prevn(fr, nb);
974  int ix = array_index_of_pointer(fr);
975  copy_data_wrap_dst<Item_alloc, nb_cells>(src, 0, beg(), ix, nb);
976  }
977 
978  void pushn_back(const value_type* src, int nb) {
979  assert(0 <= nb && nb + size() <= capacity);
980  int ix = array_index_of_pointer(next(bk)); // next(bk) because bk is inclusive
981  copy_data_wrap_dst<Item_alloc, nb_cells>(src, 0, beg(), ix, nb);
982  bk = nextn(bk, nb);
983  }
984 
986  template <class Body>
987  void pushn_back(const Body& body, int nb) {
988  assert(0 <= nb && nb + size() <= capacity);
989  int ix = array_index_of_pointer(next(bk)); // next(bk) because bk is inclusive
990  papply_wrap_dst<Body, nb_cells>(beg(), ix, nb, body);
991  bk = nextn(bk, nb);
992  }
993 
994  void popn_front(int nb) {
995  assert(0 <= nb && nb <= size());
996  int ix = array_index_of_pointer(fr);
997  destroy_items_wrap_target<Item_alloc, nb_cells>(beg(), ix, nb);
998  fr = nextn(fr, nb);
999  }
1000 
1001  void popn_back(int nb) {
1002  assert(0 <= nb && nb <= size());
1003  bk = prevn(bk, nb);
1004  int ix = array_index_of_pointer(next(bk)); // next(bk) because bk is inclusive
1005  destroy_items_wrap_target<Item_alloc, nb_cells>(beg(), ix, nb);
1006  }
1007 
1008  void popn_front(value_type* dst, int nb) {
1009  frontn(dst, nb);
1010  popn_front(nb);
1011  }
1012 
1013  void popn_back(value_type* dst, int nb) {
1014  backn(dst, nb);
1015  popn_back(nb);
1016  }
1017 
1019  assert(0 <= nb && nb <= size());
1020  bk = prevn(bk, nb);
1021  target.fr = target.prevn(target.fr, nb);
1022  int i1 = array_index_of_pointer(next(bk));
1023  int i2 = target.array_index_of_pointer(target.fr);
1024  copy_data_wrap_src_and_dst<Item_alloc, nb_cells>(beg(), i1, target.beg(), i2, nb);
1025  check();
1026  target.check();
1027  }
1028 
1030  assert(0 <= nb && nb <= size());
1031  int i1 = array_index_of_pointer(fr);
1032  int i2 = target.array_index_of_pointer(target.next(target.bk));
1033  copy_data_wrap_src_and_dst<Item_alloc, nb_cells>(beg(), i1, target.beg(), i2, nb);
1034  fr = nextn(fr, nb);
1035  target.bk = target.nextn(target.bk, nb);
1036  check();
1037  target.check();
1038  }
1039 
1040  value_type& operator[](int i) const {
1041  return *(pointer_of_index(i));
1042  }
1043 
1044  value_type& operator[](size_t i) const {
1045  return (*this)[int(i)];
1046  }
1047 
1048  void clear() {
1049  popn_back(size());
1050  }
1051 
1052  void swap(ringbuffer_ptr& other) {
1053  std::swap(fr, other.fr);
1054  std::swap(bk, other.bk);
1055  array.swap(other.array);
1056  }
1057 
1058  segment_type segment_by_index(int i) const {
1059  assert(i >= 0);
1060  assert(i < size());
1061  value_type* p = pointer_of_index(i);
1062  return segment_of_ringbuffer(p, fr, bk, beg(), nb_cells);
1063  }
1064 
1066  template <class Body>
1067  void for_each(const Body& body) const {
1068  auto _body = apply_foreach_body<Item_alloc, Body>(body);
1069  int ix = array_index_of_pointer(fr);
1070  int sz = size();
1071  papply_wrap_dst<typeof(_body), nb_cells>(beg(), ix, sz, 0, _body);
1072  }
1073 
1075  template <class Body>
1076  void for_each_segment(int lo, int hi, const Body& body) const {
1077  /* new code --tofix:
1078  if (hi - lo <= 0 || hi < 1)
1079  return;
1080  assert(0 <= lo && lo < hi && hi <= size()); // correct if did not return above
1081  Size first = lo;
1082  Size last = hi-1;
1083  value_type* p_first = pointer_of_index(int(first));
1084  value_type* p_last = pointer_of_index(int(last));
1085  if (bk >= fr) {
1086  body(p_first, p_last + 1);
1087  } else {
1088  body(p_first, end() + 1);
1089  body(beg(), p_last + 1);
1090  }
1091  */
1092  if (hi - lo <= 0 || hi < 1)
1093  return;
1094  segment_type seg1 = segment_by_index(int(lo));
1095  segment_type seg2 = segment_by_index(int(hi - 1));
1096  if (seg1.begin == seg2.begin) {
1097  body(seg1.middle, seg2.middle + 1);
1098  } else {
1099  body(seg1.middle, seg1.end);
1100  body(seg2.begin, seg2.middle + 1);
1101  }
1102  }
1103 
1104 };
1105 
1106 /*---------------------------------------------------------------------*/
1107 /* Ring buffer based on pointers */
1108 
1130 template <class Array_alloc,
1131 class Item_alloc = std::allocator<typename Array_alloc::value_type> >
1133 public:
1134 
1136  static constexpr int capacity = Array_alloc::capacity - 1;
1137  // max number of items that can be stored
1138  // recall that at least one cell must be empty
1139 
1140 private:
1141 
1142  static constexpr int nbcells = Array_alloc::capacity; // number of cells
1143 
1144  value_type* fr; // empty cell before front item
1145  value_type* bk; // empty cell after back item
1146  Item_alloc alloc;
1147  Array_alloc array;
1148 
1149  // returns pointer to first allocated cell
1150  inline value_type* beg() const {
1151  return &array[0];
1152  }
1153 
1154  // returns pointer to last allocated cell
1155  inline value_type* end() const {
1156  return &array[nbcells-1];
1157  }
1158 
1159  void check(value_type* fr, value_type* bk) const {
1160  assert(bk >= beg());
1161  assert(fr >= beg());
1162  assert(bk <= end());
1163  assert(fr <= end());
1164  }
1165 
1166  void init() {
1167  fr = &array[nbcells-1];
1168  bk = &array[0];
1169  check(fr, bk);
1170  }
1171 
1172  int array_index_of_front(value_type* fr) const {
1173  return array_index_of_pointer(addr_of_front(fr));
1174  }
1175 
1176  int array_index_of_back(value_type* bk) const {
1177  return array_index_of_pointer(addr_of_back(bk));
1178  }
1179 
1180  int array_index_of_pointer(const value_type* p) const {
1181  assert(p >= beg());
1182  assert(p <= end());
1183  return (int)(p - beg());
1184  }
1185 
1186  value_type* addr_of_front(value_type* fr) const {
1187  value_type* addr;
1188  if (fr == end())
1189  addr = beg();
1190  else
1191  addr = fr + 1;
1192  return addr;
1193  }
1194 
1195  value_type* addr_of_back(value_type* bk) const {
1196  value_type* addr;
1197  if (bk == beg())
1198  addr = end();
1199  else
1200  addr = bk - 1;
1201  return addr;
1202  }
1203 
1204  inline value_type* alloc_front(value_type* fr) {
1205  check(fr, bk);
1206  if (fr == beg())
1207  fr = end();
1208  else
1209  fr--;
1210  check(fr, bk);
1211  return fr;
1212  }
1213 
1214  inline value_type* alloc_back(value_type* bk) const {
1215  check(fr, bk);
1216  if (bk == end())
1217  bk = beg();
1218  else
1219  bk++;
1220  check(fr, bk);
1221  return bk;
1222  }
1223 
1224  inline value_type* dealloc_front(value_type* fr) const {
1225  check(fr, bk);
1226  if (fr == end())
1227  fr = beg();
1228  else
1229  fr++;
1230  check(fr, bk);
1231  return fr;
1232  }
1233 
1234  inline value_type* dealloc_back(value_type* bk) {
1235  check(fr, bk);
1236  if (bk == beg())
1237  bk = end();
1238  else
1239  bk--;
1240  check(fr, bk);
1241  return bk;
1242  }
1243 
1244  inline value_type* allocn_front(value_type* fr, int nb) const {
1245  assert(nb + size() <= capacity);
1246  check(fr, bk);
1247  value_type* new_fr = fr - nb;
1248  if (new_fr < beg())
1249  new_fr = end() - (beg() - new_fr - 1);
1250  check(fr, bk);
1251  return new_fr;
1252  }
1253 
1254  inline value_type* allocn_back(value_type* bk, int nb) const {
1255  assert(nb + size() <= capacity);
1256  check(fr, bk);
1257  value_type* new_bk = bk + nb;
1258  if (new_bk > end())
1259  new_bk = beg() + (new_bk - end() - 1);
1260  check(fr, bk);
1261  return new_bk;
1262  }
1263 
1264  inline value_type* deallocn_front(value_type* fr, int nb) const {
1265  assert(size() >= nb);
1266  check(fr, bk);
1267  value_type* new_fr = fr + nb;
1268  if (new_fr > end())
1269  new_fr = beg() + (new_fr - end() - 1);
1270  check(fr, bk);
1271  return new_fr;
1272  }
1273 
1274  inline value_type* deallocn_back(value_type* bk, int nb) const {
1275  assert(size() >= nb);
1276  check(fr, bk);
1277  value_type* new_bk = bk - nb;
1278  if (new_bk < beg())
1279  new_bk = end() - (beg() - new_bk - 1);
1280  check(fr, bk);
1281  return new_bk;
1282  }
1283 
1284 public:
1285 
1286  typedef int size_type;
1287  typedef Item_alloc allocator_type;
1290 
1292  init();
1293  }
1294 
1295 #define DEBUG_RINGBUFFER 0
1296 
1298  init();
1299  int sz = other.size();
1300  int other_ix = other.array_index_of_front(other.fr);
1301 #if DEBUG_RINGBUFFER==0
1302  int ix = array_index_of_front(fr);
1303  bk = allocn_back(bk, sz);
1304 #else
1305  fr = beg() + other.array_index_of_pointer(other.fr);
1306  bk = beg() + other.array_index_of_pointer(other.bk);
1307  int ix = array_index_of_front(fr);
1308 #endif
1309  copy_data_wrap_src_and_dst<allocator_type, nbcells>(other.beg(), other_ix, beg(), ix, sz);
1310  check(fr, bk);
1311  }
1312 
1313  ringbuffer_ptrx(size_type nb, const value_type& val) {
1314  init();
1316  check(fr, bk);
1317  }
1318 
1320  check(fr, bk);
1321  clear();
1322  check(fr, bk);
1323  }
1324 
1325  inline int size() const {
1326  if (bk > fr)
1327  return int(bk-fr)-1;
1328  else
1329  return int(bk-(fr-nbcells))-1;
1330  }
1331 
1332  inline bool full() const {
1333  return bk == fr;
1334  }
1335 
1336  inline bool empty() const {
1337  return (bk-fr == 1) || (bk-(fr-nbcells) == 1);
1338  }
1339 
1340  inline void push_front(const value_type& x) {
1341  assert(! full());
1342  alloc.construct(fr, x);
1343  fr = alloc_front(fr);
1344  }
1345 
1346  inline void push_back(const value_type& x) {
1347  assert(! full());
1348  alloc.construct(bk, x);
1349  bk = alloc_back(bk);
1350  }
1351 
1352  inline value_type& front() const {
1353  assert(! empty());
1354  return *addr_of_front(fr);
1355  }
1356 
1357  inline value_type& back() const {
1358  assert(! empty());
1359  return *addr_of_back(bk);
1360  }
1361 
1362  inline value_type pop_front() {
1363  assert(! empty());
1364  fr = dealloc_front(fr);
1365  value_type v = *fr;
1366  alloc.destroy(fr);
1367  return v;
1368  }
1369 
1370  inline value_type pop_back() {
1371  assert(! empty());
1372  bk = dealloc_back(bk);
1373  value_type v = *bk;
1374  alloc.destroy(bk);
1375  return v;
1376  }
1377 
1378  void frontn(value_type* dst, int nb) const {
1379  assert(size() >= nb);
1380  int ix_fr = array_index_of_front(fr);
1381  copy_data_wrap_src<Item_alloc, nbcells>(beg(), ix_fr, dst, 0, nb);
1382  }
1383 
1384  void backn(value_type* dst, int nb) const {
1385  assert(size() >= nb);
1386  value_type* new_bk = deallocn_back(bk, nb);
1387  int ix_bk = array_index_of_pointer(new_bk);
1388  copy_data_wrap_src<Item_alloc, nbcells>(beg(), ix_bk, dst, 0, nb);
1389  }
1390 
1391  void pushn_front(const value_type* xs, int nb) {
1392  assert(nb + size() <= capacity);
1393  fr = allocn_front(fr, nb);
1394  int ix_fr = array_index_of_front(fr);
1395  copy_data_wrap_dst<Item_alloc, nbcells>(xs, 0, beg(), ix_fr, nb);
1396  }
1397 
1398  void pushn_back(const value_type* xs, int nb) {
1399  assert(nb + size() <= capacity);
1400  int ix_bk = array_index_of_pointer(bk);
1401  copy_data_wrap_dst<Item_alloc, nbcells>(xs, 0, beg(), ix_bk, nb);
1402  bk = allocn_back(bk, nb);
1403  }
1404 
1405  void popn_front(int nb) {
1406  assert(size() >= nb);
1407  int ix_fr = array_index_of_front(fr);
1408  destroy_items_wrap_target<Item_alloc, nbcells>(beg(), ix_fr, nb);
1409  fr = deallocn_front(fr, nb);
1410  }
1411 
1412  template <class Body>
1413  void pushn_back(const Body& body, int nb) {
1414  assert(nb + size() <= capacity);
1415  int ix_bk = array_index_of_pointer(bk);
1416  papply_wrap_dst<Body, nbcells>(beg(), ix_bk, nb, body);
1417  bk = allocn_back(bk, nb);
1418  }
1419 
1420  void popn_back(int nb) {
1421  assert(size() >= nb);
1422  bk = deallocn_back(bk, nb);
1423  int ix_bk = array_index_of_pointer(bk);
1424  destroy_items_wrap_target<Item_alloc, nbcells>(beg(), ix_bk, nb);
1425  }
1426 
1427  void popn_front(value_type* dst, int nb) {
1428  frontn(dst, nb);
1429  popn_front(nb);
1430  }
1431 
1432  void popn_back(value_type* dst, int nb) {
1433  backn(dst, nb);
1434  popn_back(nb);
1435  }
1436 
1438  bk = deallocn_back(bk, nb);
1439  target.fr = target.allocn_front(target.fr, nb);
1440  int i1 = array_index_of_pointer(bk);
1441  int i2 = target.array_index_of_front(target.fr);
1442  copy_data_wrap_src_and_dst<Item_alloc, nbcells>(beg(), i1, target.beg(), i2, nb);
1443  check(fr, bk);
1444  target.check(target.fr, target.bk);
1445  }
1446 
1448  int i1 = array_index_of_front(fr);
1449  int i2 = target.array_index_of_pointer(target.bk);
1450  copy_data_wrap_src_and_dst<Item_alloc, nbcells>(beg(), i1, target.beg(), i2, nb);
1451  fr = deallocn_front(fr, nb);
1452  target.bk = target.allocn_back(target.bk, nb);
1453  check(fr, bk);
1454  target.check(target.fr, target.bk);
1455  }
1456 
1457  value_type& operator[](int ix) const {
1458  return *(segment_by_index(ix).middle);
1459  }
1460 
1461  value_type& operator[](size_t ix) const {
1462  return (*this)[int(ix)];
1463  }
1464 
1465  void clear() {
1466  popn_back(size());
1467  }
1468 
1469  void swap(ringbuffer_ptrx& other) {
1470  std::swap(fr, other.fr);
1471  std::swap(bk, other.bk);
1472  array.swap(other.array);
1473  }
1474 
1475  int array_index_of_logical_index(int ix) const {
1476  value_type* on_front_item = addr_of_front(fr);
1477  value_type* proj_addr_of_ix = on_front_item + ix;
1478  int array_index_of_ix =
1479  (proj_addr_of_ix <= end())
1480  ? int(proj_addr_of_ix - beg())
1481  : ix - int(end() - fr);
1482  return array_index_of_ix;
1483  }
1484 
1485  segment_type segment_by_index(int ix) const {
1486  assert(ix >= 0);
1487  assert(ix < size());
1488  value_type* p = &array[array_index_of_logical_index(ix)];
1489  value_type* on_fr = addr_of_front(fr);
1490  value_type* on_bk = addr_of_back(bk);
1491  return segment_of_ringbuffer(p, on_fr, on_bk, beg(), nbcells);
1492  }
1493 
1494  int index_of_pointer(const value_type* p) const {
1495  assert(p >= beg());
1496  assert(p <= end());
1497  value_type* on_front_item = addr_of_front(fr);
1498  int ix;
1499  if (p >= on_front_item) {
1500  ix = int(p - on_front_item);
1501  } else { // wraparound
1502  int ix1 = int(end() - fr);
1503  int ix2 = int(p - beg());
1504  ix = ix1 + ix2;
1505  }
1506  assert(ix >= 0);
1507  // assert(ix < size());
1508  return ix;
1509  }
1510 
1511  template <class Body>
1512  void for_each(const Body& body) const {
1513  /* SIMPLE VERSION
1514  size_t nb = size();
1515  value_type* p = fr + 1;
1516  while (p != bk) {
1517  if (p == &array[nbcells])
1518  p = beg();
1519  body(*p);
1520  p++;
1521  }
1522  */
1523  auto _body = apply_foreach_body<Item_alloc, Body>(body);
1524  int ix_fr = array_index_of_front(fr);
1525  int sz = size();
1526  papply_wrap_dst<typeof(_body), nbcells>(beg(), ix_fr, sz, 0, _body);
1527  }
1528 
1529  template <class Body>
1530  void for_each_segment(int lo, int hi, const Body& body) const {
1531  /*
1532  if (hi - lo <= 0 || hi < 1)
1533  return;
1534  segment_type seg1 = segment_by_index(int(lo));
1535  segment_type seg2 = segment_by_index(int(hi));
1536  if (seg1.begin == seg2.begin) {
1537  body(seg1.middle, seg2.middle + 1);
1538  } else {
1539  body(seg1.middle, seg1.end);
1540  body(seg2.begin, seg2.middle + 1);
1541  }
1542  */
1543  if (hi - lo <= 0 || hi < 1)
1544  return;
1545  segment_type seg1 = segment_by_index(int(lo));
1546  segment_type seg2 = segment_by_index(int(hi - 1));
1547  if (seg1.begin == seg2.begin) {
1548  body(seg1.middle, seg2.middle + 1);
1549  } else {
1550  body(seg1.middle, seg1.end);
1551  body(seg2.begin, seg2.middle + 1);
1552  }
1553  }
1554 
1555 };
1556 
1557 /*---------------------------------------------------------------------*/
1558 /* Stack */
1559 
1561 
1579 template <class Array_alloc,
1580 class Item_alloc = std::allocator<typename Array_alloc::value_type> >
1581 class stack {
1582 public:
1583 
1584  using size_type = int;
1585  using value_type = typename Array_alloc::value_type;
1586  using allocator_type = Item_alloc;
1588 
1589  static constexpr int capacity = Array_alloc::capacity;
1590 
1591 private:
1592 
1593  size_type bk; // position of the last allocated cell
1594  Item_alloc alloc;
1595  Array_alloc array;
1596 
1597  static value_type& subscript(value_type* array, size_type bk, size_type ix) {
1598  assert(array != NULL);
1599  assert(ix >= 0);
1600  assert(ix <= bk);
1601  return array[ix];
1602  }
1603 
1604 public:
1605 
1607  : bk(-1) { }
1608 
1609  stack(const stack& other)
1610  : bk(-1) {
1611  if (other.size() == 0)
1612  return;
1613  const value_type* ptr = &other[0];
1614  pushn_back(ptr, other.size());
1615  }
1616 
1617  stack(size_type nb, const value_type& val) {
1619  }
1620 
1622  clear();
1623  }
1624 
1625  inline size_type size() const {
1626  return bk + 1;
1627  }
1628 
1629  inline bool full() const {
1630  return size() == capacity;
1631  }
1632 
1633  inline bool empty() const {
1634  return size() == 0;
1635  }
1636 
1637  inline bool partial() const {
1638  return !empty() && !full(); // TODO: could be optimized
1639  }
1640 
1641  inline void push_front(const value_type& x) {
1642  assert(! full());
1643  pshiftn<Item_alloc>(&array[0], size(), +1);
1644  alloc.construct(&array[0], x);
1645  bk++;
1646  }
1647 
1648  inline void push_back(const value_type& x) {
1649  assert(! full());
1650  bk++;
1651  alloc.construct(&array[bk], x);
1652  }
1653 
1654  inline value_type& front() const {
1655  assert(! empty());
1656  return array[0];
1657  }
1658 
1659  inline value_type& back() const {
1660  assert(! empty());
1661  return array[bk];
1662  }
1663 
1664  inline value_type pop_front() {
1665  assert(! empty());
1666  value_type v = front();
1667  alloc.destroy(&(front()));
1668  pshiftn<Item_alloc>(&array.operator[](1), size() - 1, -1);
1669  bk--;
1670  return v;
1671  }
1672 
1673  inline value_type pop_back() {
1674  assert(! empty());
1675  value_type v = back();
1676  alloc.destroy(&(back()));
1677  bk--;
1678  return v;
1679  }
1680 
1681  void frontn(value_type* dst, size_type nb) {
1682  assert(size() >= nb);
1683  copy<Item_alloc>(dst, &array[0], nb);
1684  }
1685 
1686  void backn(value_type* dst, size_type nb) {
1687  assert(size() >= nb);
1688  copy<Item_alloc>(dst, &array.operator[](size() - nb), nb);
1689  }
1690 
1691  void pushn_front(const value_type* xs, size_type nb) {
1692  assert(nb + size() <= capacity);
1693  pshiftn<Item_alloc>(&array[0], size(), +nb);
1694  copy<Item_alloc>(&array[0], xs, nb);
1695  bk += nb;
1696  }
1697 
1698  void pushn_back(const value_type* xs, size_type nb) {
1699  assert(nb + size() <= capacity);
1700  copy<Item_alloc>(&array.operator[](size()), xs, nb);
1701  bk += nb;
1702  }
1703 
1704  template <class Body>
1705  void pushn_back(const Body& body, size_type nb) {
1706  assert(nb + size() <= capacity);
1707  papply<Body>(&array[bk+1], nb, 0, body);
1708  bk += nb;
1709  }
1710 
1712  assert(size() >= nb);
1713  destroy_items<Item_alloc>(&array[0], nb);
1714  pshiftn<Item_alloc>(&array.operator[](nb), size() - nb, -nb);
1715  bk -= nb;
1716  }
1717 
1719  assert(size() >= nb);
1720  destroy_items<Item_alloc>(&array[0], size() - nb, nb);
1721  bk -= nb;
1722  }
1723 
1724  void popn_front(value_type* dst, size_type nb) {
1725  frontn(dst, nb);
1726  popn_front(nb);
1727  }
1728 
1729  void popn_back(value_type* dst, size_type nb) {
1730  backn(dst, nb);
1731  popn_back(nb);
1732  }
1733 
1735  assert(nb <= size());
1736  assert(target.size() + nb <= capacity);
1737  pshiftn<Item_alloc>(&target.array[0], target.size(), +nb);
1738  popn_back(&target.array[0], nb);
1739  target.bk += nb;
1740  }
1741 
1743  assert(nb <= size());
1744  assert(target.size() + nb <= capacity);
1745  popn_front(&target.array.operator[](target.size()), nb);
1746  target.bk += nb;
1747  }
1748 
1749  value_type& operator[](size_type ix) const {
1750  return subscript(&array[0], bk, ix);
1751  }
1752 
1753  value_type& operator[](size_t ix) const {
1754  return subscript(&array[0], bk, (size_type)ix);
1755  }
1756 
1757  void clear() {
1758  popn_back(size());
1759  }
1760 
1761  void swap(stack& other) {
1762  array.swap(other.array);
1763  std::swap(bk, other.bk);
1764  }
1765 
1767  size_type sz = size();
1768  return (sz > 0) ? sz - 1 : sz;
1769  }
1770 
1772  segment_type seg;
1773  seg.begin = &array[0];
1774  seg.middle = &array[ix];
1775  seg.end = &array[index_of_last_item()] + 1;
1776  return seg;
1777  }
1778 
1779  size_type index_of_pointer(const value_type* p) const {
1780  assert(p >= &array[0]);
1781  assert(p <= &array[index_of_last_item()] + 1);
1782  return (size_type)(p - &array[0]);
1783  }
1784 
1785  template <class Body>
1786  void for_each(const Body& body) const {
1787  for (size_type i = 0; i < size(); i++)
1788  body((*this)[i]);
1789  }
1790 
1791  template <class Body>
1792  void for_each_segment(size_type lo, size_type hi, const Body& body) const {
1793  body(&array[size_type(lo)], &array[size_type(hi)]);
1794  }
1795 
1796 };
1798 
1799 /***********************************************************************/
1800 
1801 } // end namespace
1802 } // end namespace
1803 } // end namespace
1804 } // end namespace
1805 
1806 #endif
value_type & operator[](size_t ix) const
void pshiftn(typename Alloc::pointer t, typename Alloc::size_type num, int shift_by)
Polymorphic shift by position.
void frontn(value_type *dst, int nb) const
void transfer_from_back_to_front(ringbuffer_idx &target, int nb)
value_type & operator[](size_type ix) const
ringbuffer_idx(size_type nb, const value_type &val)
pointer_type end
Definition: segment.hpp:44
void papply(typename Body::allocator_type::pointer t, typename Body::allocator_type::size_type num, typename Body::allocator_type::size_type k, const Body &body)
Polymorphic apply-to-each item.
int index_of_pointer(const value_type *p) const
Segment descriptor.
Definition: segment.hpp:34
void for_each_segment(size_type lo, size_type hi, const Body &body) const
segment< Pointer > segment_of_ringbuffer(Pointer p, Pointer fr, Pointer bk, Pointer a, int capacity)
[segment]
Definition: segment.hpp:66
Loop body for array-initialization by constant.
stack(size_type nb, const value_type &val)
void backn(value_type *dst, size_type nb)
void for_each_segment(int lo, int hi, const Body &body) const
void copy_data_wrap_src_and_dst(typename Alloc::const_pointer t1, int i1, typename Alloc::pointer t2, int i2, int nb)
void transfer_from_front_to_back(ringbuffer_idx &target, int nb)
void pushn_front(const value_type *xs, int nb)
Memory segment.
void destroy_items(typename Alloc::pointer t, int i, int nb)
ringbuffer_ptr(size_type nb, const value_type &val)
ringbuffer_ptrx(size_type nb, const value_type &val)
segment_type segment_by_index(size_type ix) const
void transfer_from_front_to_back(ringbuffer_ptr &target, int nb)
size_type index_of_pointer(const value_type *p) const
void copy(typename Alloc::pointer destination, typename Alloc::const_pointer source, typename Alloc::size_type num)
Polymorphic array copy.
void papply_wrap_dst(typename Body::allocator_type::pointer t, int i, int nb, typename Body::allocator_type::size_type k, const Body &body)
apply_foreach_body(const Body &body, size_type start=0)
void pushn_back(const Body &body, size_type nb)
Definition: algebra.hpp:18
void frontn(value_type *dst, size_type nb)
void copy_data_wrap_src(typename Alloc::const_pointer t1, int i1, typename Alloc::pointer t2, int i2, int nb)
void pushn_back(const value_type *xs, size_type nb)
void frontn(value_type *dst, int nb) const
void pushn_back(const value_type *xs, int nb)
void transfer_from_back_to_front(stack &target, size_type nb)
void pushn_front(const value_type *xs, int nb)
void pushn_front(const value_type *xs, size_type nb)
void popn_front(value_type *dst, size_type nb)
void popn_back(value_type *dst, size_type nb)
void pushn_front(const value_type *src, int nb)
void operator()(size_type i, reference dst) const
void for_each(const Body &body) const
void transfer_from_front_to_back(ringbuffer_ptrx &target, int nb)
void transfer_from_back_to_front(ringbuffer_ptrx &target, int nb)
void destroy_items_wrap_target(typename Alloc::pointer t, int i, int nb)
void pfill(typename Alloc::pointer first, typename Alloc::pointer last, typename Alloc::const_reference val)
Polymorphic fill range with value.
void for_each_segment(int lo, int hi, const Body &body)
void pblit(typename Alloc::const_pointer t1, int i1, typename Alloc::pointer t2, int i2, int nb)
pointer_type middle
Definition: segment.hpp:42
void backn(value_type *dst, int nb) const
void backn(value_type *dst, int nb) const
Fixed-capacity ring buffer, using indices.
void operator()(size_type i, reference dst) const
void transfer_from_back_to_front(ringbuffer_ptr &target, int nb)
void copy_data_wrap_dst(typename Alloc::const_pointer t1, int i1, typename Alloc::pointer t2, int i2, int nb)
void for_each_segment(int lo, int hi, const Body &body) const
int index_of_pointer(const value_type *p) const
void transfer_from_front_to_back(stack &target, size_type nb)
void pushn_back(const value_type *src, int nb)
bytes_8 Item
Definition: do_fifo.cpp:107
pointer_type begin
Definition: segment.hpp:40