82 #ifndef VECTOR_STACKED_H 83 #define VECTOR_STACKED_H 89 #include <type_traits> 96 #if __cplusplus >= 201703L 97 #define CONSTEXPR constexpr 103 #include "libdivide.h" 112 libdivide::divider<size_t> div;
114 explicit divider(
size_t x):n(x),div(x) { }
116 bool operator == (
size_t x)
const {
return n == x; }
117 bool operator != (
size_t x)
const {
return n != x; }
118 bool operator < (
size_t x)
const {
return n < x; }
119 bool operator <= (
size_t x)
const {
return n <= x; }
120 bool operator > (
size_t x)
const {
return n > x; }
121 bool operator >= (
size_t x)
const {
return n >= x; }
124 size_t operator / (
size_t x,
const divider& d) {
return x / d.div; }
125 size_t& operator /= (
size_t& x,
const divider& d) { x /= d.div;
return x; }
126 size_t operator * (
size_t x,
const divider& d) {
return x * d.n; }
127 size_t& operator *= (
size_t& x,
const divider& d) { x *= d.n;
return x; }
129 size_t operator + (
size_t x,
const divider& d) {
return x + d.n; }
130 size_t& operator += (
size_t& x,
const divider& d) { x += d.n;
return x; }
131 size_t operator - (
size_t x,
const divider& d) {
return x - d.n; }
132 size_t& operator -= (
size_t& x,
const divider& d) { x -= d.n;
return x; }
134 bool operator == (
size_t x,
const divider& d) {
return d == x; }
135 bool operator != (
size_t x,
const divider& d) {
return d != x; }
136 bool operator > (
size_t x,
const divider& d) {
return d < x; }
137 bool operator >= (
size_t x,
const divider& d) {
return d <= x; }
138 bool operator < (
size_t x,
const divider& d) {
return d > x; }
139 bool operator <= (
size_t x,
const divider& d) {
return d >= x; }
150 constexpr
static bool value =
151 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::forward_iterator_tag >::value ||
152 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::bidirectional_iterator_tag >::value ||
153 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::random_access_iterator_tag >::value
154 #if __cplusplus >= 202000L 155 || std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::contiguous_iterator_tag >::value
163 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::input_iterator_tag >::value;
168 using std_vector_wrapper = std::vector<T>;
170 template <
class T,
template<
class>
class vector_type = std_vector_wrapper>
173 vector_type<T*> stack;
183 static constexpr
size_t p_max_capacity = std::numeric_limits<size_t>::max() /
sizeof(T);
188 template<
class U = T>
190 typename std::enable_if< std::is_nothrow_move_constructible<U>::value >::type* = 0) {
192 for(i=0;i<p_size;i++) {
193 if(i<new_size)
new(target + i) U(std::move(stack[0][i]));
198 template<
class U = T>
199 bool copy_or_move(U* target,
size_t new_size,
200 typename std::enable_if< ! std::is_nothrow_move_constructible<U>::value >::type* = 0) {
201 size_t copy_size = p_size < new_size ? p_size : new_size;
202 U* tmp = std::uninitialized_copy(stack[0], stack[0] + copy_size, target);
203 if(tmp != target + copy_size)
return false;
204 for(
size_t i=0;i<p_size;i++) stack[0][i].~U();
211 if(new_size > max_grow)
return false;
212 if(new_size == p_stack_size)
return true;
213 T* new_array = (T*)malloc(
sizeof(T)*new_size);
214 if(!new_array)
return false;
215 if(stack.size() == 0) {
217 stack.push_back(new_array);
219 catch(std::bad_alloc& x) {
225 if(!copy_or_move<T>(new_array,new_size)) {
230 stack[0] = new_array;
232 p_capacity = new_size;
233 p_stack_size = new_size;
234 if(new_size < p_size) p_size = new_size;
242 size_t new_size = minimum_size;
244 if(p_stack_size == max_grow)
return grow_one();
245 new_size = p_stack_size*2UL;
246 if(!new_size) new_size = 1UL;
248 if(new_size > max_grow)
250 new_size = max_grow.n;
254 if(!change_size(new_size))
return false;
255 while(minimum_size > p_capacity)
if(!grow_one())
return false;
262 size_t max_stack_size = std::numeric_limits<size_t>::max() / p_stack_size;
263 if(stack.size() >= max_stack_size)
return false;
264 T* new_array = (T*)malloc(
sizeof(T)*p_stack_size);
265 if(!new_array)
return false;
267 stack.push_back(new_array);
269 catch(std::bad_alloc& x) {
273 p_capacity += p_stack_size;
280 size_t i1 = i / max_grow;
281 size_t i2 = (i - i1*max_grow);
283 size_t i1 = i / max_grow;
284 size_t i2 = i % max_grow;
286 return std::pair<size_t,size_t>(i1,i2);
291 T*
get_addr(
size_t i) {
auto x = get_indices(i);
return stack[x.first] + x.second; }
294 const T*
get_addr(
size_t i)
const {
auto x = get_indices(i);
return stack[x.first] + x.second; }
297 T&
get_ref(
size_t i) {
auto x = get_indices(i);
return stack[x.first][x.second]; }
300 const T&
get_ref(
size_t i)
const {
auto x = get_indices(i);
return stack[x.first][x.second]; }
304 typedef T value_type;
305 typedef size_t size_type;
306 typedef ssize_t difference_type;
307 typedef T& reference;
308 typedef const T& const_reference;
310 typedef const T* const_pointer;
315 vector() noexcept : p_size(0),p_capacity(0),p_stack_size(0),max_grow(131072) { }
317 explicit vector(
size_t count,
const T& value = T(),
size_t max_grow_ = 131072);
319 template<class It, typename std::enable_if<at_least_input_iterator<It>::value,
int>::type = 0>
320 vector(It first, It last,
size_t max_grow_ = 131072);
333 if(p_size) resize(0);
334 for(
auto x : stack) free(x);
341 size_t size()
const {
return p_size; }
349 bool empty()
const {
return p_size == 0; }
370 T&
at(
size_t i) {
if(i < p_size)
return get_ref(i);
throw std::out_of_range(
"vector::at(): index out of range!\n"); }
372 const T&
at(
size_t i)
const {
if(i < p_size)
return get_ref(i);
throw std::out_of_range(
"vector::at(): index out of range!\n"); }
376 const T&
front()
const {
return stack[0][0]; }
378 T&
back() {
return get_ref(p_size-1); }
380 const T&
back()
const {
return get_ref(p_size-1); }
384 bool reserve_nothrow(
size_t n);
386 void reserve(
size_t n) {
if(!reserve_nothrow(n))
throw std::bad_alloc(); }
388 void shrink_to_fit(
size_t new_capacity = 0);
393 void push_back(
const T& x);
395 void push_back(T&& x);
397 template<
class... Args> T& emplace_back(Args&&... args);
402 bool push_back_nothrow(
const T& x);
404 bool push_back_nothrow(T&& x);
406 template<
class... Args>
bool emplace_back_nothrow(Args&&... args);
410 void clear() {
while(p_size) pop_back(); }
415 get_ref(p_size).~T();
421 bool resize_nothrow(
size_t count);
424 bool resize_nothrow(
size_t count,
const T& x);
427 void resize(
size_t count) {
if(!resize_nothrow(count))
throw std::bad_alloc(); }
430 void resize(
size_t count,
const T& x) {
if(!resize_nothrow(count,x))
throw std::bad_alloc(); }
434 template<
bool is_const>
437 typedef std::random_access_iterator_tag iterator_category;
438 typedef T value_type;
440 typedef T& reference;
441 typedef ssize_t difference_type;
451 friend class vector<T,vector_type>;
454 typedef typename std::conditional<is_const, const vector, vector>::type vector_type1;
464 explicit iterator_base(vector_type1& v_,
size_t pos_ = 0):v(&v_),pos(pos_) { }
465 explicit iterator_base(vector_type1* v_,
size_t pos_ = 0):v(v_),pos(pos_) { }
471 template<
bool is_const_ = is_const>
477 reference operator * () {
481 pointer operator -> () {
494 template<
bool is_const2>
bool operator < (const iterator_base<is_const2>& i)
const {
return pos < i.pos; }
498 template<
bool is_const2>
bool operator <= (const iterator_base<is_const2>& i)
const {
return pos <= i.pos; }
503 iterator_base& operator ++() { ++pos;
return *
this; }
507 iterator_base& operator --() { --pos;
return *
this; }
512 iterator_base& operator +=(ssize_t i) { pos += i;
return *
this; }
514 iterator_base& operator -=(ssize_t i) { pos -= i;
return *
this; }
520 return ((ssize_t)pos) - ((ssize_t)(i.pos));
523 typename std::conditional<is_const, const reference, reference>::type operator [] (ssize_t i) {
return (*v)[pos+i]; }
528 bool insert_helper(
size_t pos,
size_t new_pos);
541 iterator
begin() {
return iterator(*
this,0); }
542 const_iterator
begin()
const {
return const_iterator(*
this,0); }
543 const_iterator
cbegin()
const {
return const_iterator(*
this,0); }
544 iterator
end() {
return iterator(*
this,p_size); }
545 const_iterator
end()
const {
return const_iterator(*
this,p_size); }
546 const_iterator
cend()
const {
return const_iterator(*
this,p_size); }
548 iterator erase(const_iterator pos);
549 iterator erase(const_iterator first, const_iterator last);
560 bool insert_nothrow(const_iterator pos, iterator& res,
const T& x);
565 bool insert_nothrow(const_iterator pos, iterator& res, T&& x);
570 bool insert_nothrow(const_iterator pos, iterator& res,
size_t count,
const T& x);
575 template<class InputIt, typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type = 0>
576 bool insert_nothrow(const_iterator pos, iterator& res, InputIt first, InputIt last);
579 iterator
insert(const_iterator pos,
const T& x) {
581 if(insert_nothrow(pos,res,x))
return res;
582 else throw std::bad_alloc();
585 iterator
insert(const_iterator pos, T&& x) {
587 if(insert_nothrow(pos,res,std::forward<T>(x)))
return res;
588 else throw std::bad_alloc();
591 iterator
insert(const_iterator pos,
size_t count,
const T& x) {
593 if(insert_nothrow(pos,res,count,x))
return res;
594 else throw std::bad_alloc();
597 template<class InputIt, typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type = 0>
598 iterator
insert(const_iterator pos, InputIt first, InputIt last) {
600 if(insert_nothrow(pos,res,first,last))
return res;
601 else throw std::bad_alloc();
606 template <
class T,
template<
class>
class vector_type>
613 template <
class T,
template<
class>
class vector_type>
623 template <
class T,
template<
class>
class vt>
625 p_size(0),p_capacity(0),p_stack_size(0),max_grow(max_grow_) {
630 template <
class T,
template<
class>
class vt>
template<
class It,
631 typename std::enable_if< at_least_input_iterator<It>::value,
int>::type >
634 for(; first != last; ++first)
push_back(*first);
637 template <
class T,
template<
class>
class vt>
643 template <
class T,
template<
class>
class vt>
646 swap(stack, v.stack);
653 template <
class T,
template<
class>
class vt>
658 template <
class T,
template<
class>
class vt>
667 template <
class T,
template<
class>
class vt>
670 for(
auto x : stack) free(x);
675 template <
class T,
template<
class>
class vt>
682 template <
class T,
template<
class>
class vt>
688 size_t tmp = new_capacity /
max_grow;
691 if(new_capacity % max_grow) new_capacity +=
max_grow;
700 size_t new_stack_size = (new_capacity > 0)?1:0;
701 for(
size_t i = new_stack_size; i < stack.size(); i++) free(stack[i]);
702 stack.resize(new_stack_size);
705 stack.shrink_to_fit();
710 template <
class T,
template<
class>
class vt>
714 template <
class T,
template<
class>
class vt>
718 template<
class T,
template<
class>
class vt>
template<
class... Args>
723 template <
class T,
template<
class>
class vt>
730 template <
class T,
template<
class>
class vt>
737 template<
class T,
template<
class>
class vt>
template<
class... Args>
747 template <
class T,
template<
class>
class vt>
749 if(count ==
p_size)
return true;
750 if(!count) {
clear();
return true; }
760 template <
class T,
template<
class>
class vt>
762 if(count ==
p_size)
return true;
763 if(!count) {
clear();
return true; }
775 template <
class T,
template<
class>
class vt>
777 if(pos.pos >=
p_size)
throw std::out_of_range(
"vector::erase(): iterator out of bounds!\n");
783 template <
class T,
template<
class>
class vt>
785 if(first.pos >=
p_size)
throw std::out_of_range(
"vector::erase(): iterator out of bounds!\n");
786 ssize_t dist = last - first;
788 if(dist < 0)
throw std::out_of_range(
"vector::erase(): invalid iterators!\n");
791 size_t new_size =
p_size - dist;
800 template <
class T,
template<
class>
class vt>
802 size_t diff = new_pos - pos;
804 size_t remaining =
p_size - pos;
806 for(
size_t i = 0; i < diff; i++) {
810 for(
size_t i =
p_size - diff; i > pos; i--)
get_ref(i - 1UL + diff) = std::move(
get_ref(i - 1UL));
817 template <
class T,
template<
class>
class vt>
826 template <
class T,
template<
class>
class vt>
831 get_ref(pos.pos) = std::move(x);
836 template <
class T,
template<
class>
class vt>
841 for(
size_t i = 0; i < count; i++)
get_ref(pos.pos + i) = x;
846 template <
class T,
template<
class>
class vt>
template<
class InputIt,
847 typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type >
852 ssize_t dist = std::distance(first,last);
853 if(dist < 0)
return false;
857 for(; first != last; ++first)
push_back(*first);
862 for(
size_t i = pos.pos; first != last; ++first, i++)
get_ref(i) = *first;
866 for(
size_t i = pos.pos; first != last; ++first, i++)
bool emplace_back_nothrow(Args &&... args)
Construct an element at the end of the vector. Does not throw exception, return value indicates if in...
Definition: vector_stacked.h:738
vector() noexcept
default constructor, creates empty vector, maximum growth is 128k elements
Definition: vector_stacked.h:315
size_t p_size
number of elements in vector
Definition: vector_stacked.h:174
const_iterator end() const
Iterator to the end.
Definition: vector_stacked.h:545
iterator_base< false > make_iterator(iterator_base< true > pos)
Helper to make a non-const copy of a const iterator – only possible if this class is not const...
Definition: vector_stacked.h:533
void pop_back()
Removes the last element; does not free up memory, use shrink_to_fit() for that.
Definition: vector_stacked.h:412
const_iterator cbegin() const
Iterator to the beginning.
Definition: vector_stacked.h:543
size_t p_capacity
current capacity of vector
Definition: vector_stacked.h:175
const_iterator begin() const
Iterator to the beginning.
Definition: vector_stacked.h:542
iterator_base< true > make_iterator(size_t pos) const
Helper to create an iterator based on a position.
Definition: vector_stacked.h:535
iterator_base< false > make_iterator(size_t pos)
Helper to create an iterator based on a position.
Definition: vector_stacked.h:531
void push_back(const T &x)
Insert element at the end of the vector. Can throw an exception if memory allocation fails...
Definition: vector_stacked.h:711
bool push_back_nothrow(const T &x)
Insert element at the end of the vector. Does not throw exception, return value indicates if insert w...
Definition: vector_stacked.h:724
bool grow_one()
Add one element to the stack.
Definition: vector_stacked.h:260
void reserve(size_t n)
Reserve memory for at least n elements. Throws an exception if memory allocation is not successful...
Definition: vector_stacked.h:386
bool insert_nothrow(const_iterator pos, iterator &res, const T &x)
Inserts a copy of x at the given position. Does not throw an exception on memory allocation failure...
bool insert_helper(size_t pos, size_t new_pos)
Helper for the insert functions – moves elements starting from pos to new_pos, allocating memory if ...
Definition: vector_stacked.h:801
Iterators store a reference to this class and a position.
Definition: vector_stacked.h:435
void resize(size_t count)
Resize vector. If new size is larger than current size, new elements are default constructed. Can throw an exception on memory allocation error.
Definition: vector_stacked.h:427
T & emplace_back(Args &&... args)
Construct an element at the end of the vector. Can throw an exception if memory allocation fails...
Definition: vector_stacked.h:719
bool reserve_nothrow(size_t n)
Reserve memory for at least n elements. Returns true if allocation was successfull, false otherwise.
Definition: vector_stacked.h:676
bool empty() const
Returns true if the vector is empty.
Definition: vector_stacked.h:349
T & operator[](size_t i)
Access the ith element. It is undefined behavior to if i >= size()
Definition: vector_stacked.h:366
size_t max_size() const
Maximum size to avoid overflow when calculating memory size.
Definition: vector_stacked.h:345
bool change_size(size_t new_size)
Reallocate memory in the first stack element to the given new size, moving / copying elements to the ...
Definition: vector_stacked.h:210
iterator begin()
Iterator to the beginning.
Definition: vector_stacked.h:541
bool copy_or_move(U *target, size_t new_size, typename std::enable_if< std::is_nothrow_move_constructible< U >::value >::type *=0)
Helper function to copy or move values to new array, selecting copy or move based on SFINAE...
Definition: vector_stacked.h:189
iterator end()
Iterator to the end.
Definition: vector_stacked.h:544
const_iterator cend() const
Iterator to the end.
Definition: vector_stacked.h:546
std::pair< size_t, size_t > get_indices(size_t i) const
Helper to get internal indices (which stack + position in stack) based on item index.
Definition: vector_stacked.h:278
size_t max_capacity() const
Maximum capacity to avoid overflow when calculating memory size.
Definition: vector_stacked.h:347
void resize(size_t count, const T &x)
Resize vector. If new size is larger than current size, new elements are inserted as copies of x...
Definition: vector_stacked.h:430
bool resize_nothrow(size_t count)
Resize vector. If new size is larger than current size, new elements are default constructed. Does not throw exception on memory allocation error, return value indicates if resize was successful.
Definition: vector_stacked.h:748
void shrink_to_fit(size_t new_capacity=0)
Free up unused memory, keeping at least the given new_capacity (if new_capacity > size())...
Definition: vector_stacked.h:683
size_t get_stack_array_size() const
Get the maximum growth size. Separate arrays are allocated by this amount.
Definition: vector_stacked.h:351
const T & operator[](size_t i) const
Access the ith element. It is undefined behavior to if i >= size()
Definition: vector_stacked.h:368
iterator insert(const_iterator pos, size_t count, const T &x)
Inserts count copies of x at pos. Can throw an exception if out of memory.
Definition: vector_stacked.h:591
const T & front() const
Access the first element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_stacked.h:376
T & front()
Access the first element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_stacked.h:374
size_t max_grow
grow memory by maximum this many elements at a time, i.e. maximum value for p_stack_size. Does not change, but not const to allow for swapping / copying / moving vectors with different value.
Definition: vector_stacked.h:181
iterator erase(const_iterator pos)
Erase element at the given position.
T & at(size_t i)
Access the ith element with bounds checking, throws an exception if i >= size()
Definition: vector_stacked.h:370
const T & get_ref(size_t i) const
Helper to get reference of element at index. Does not check if index is in range, it is undefined beh...
Definition: vector_stacked.h:300
iterator insert(const_iterator pos, const T &x)
Inserts a copy of x at pos. Can throw an exception if out of memory.
Definition: vector_stacked.h:579
T & back()
Access the last element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_stacked.h:378
size_t capacity() const
Current capacity, i.e. the number of elements that can be stored without allocating more memory...
Definition: vector_stacked.h:343
const T & at(size_t i) const
Access the ith element with bounds checking, throws an exception if i >= size()
Definition: vector_stacked.h:372
T * get_addr(size_t i)
Helper to get memory address of element at index. Does not check if index is in range, it is undefined behavior to call this function with i >= size().
Definition: vector_stacked.h:291
static constexpr size_t p_max_capacity
maximum safe capacity to avoid overflow
Definition: vector_stacked.h:184
size_t size() const
Current size, i.e. the number of elements stored in this vector.
Definition: vector_stacked.h:341
Definition: vector_stacked.h:145
C++ vector-like container that internally maintains a "stack" of vectors instead of having one large ...
Definition: vector_stacked.h:171
T & get_ref(size_t i)
Helper to get reference of element at index. Does not check if index is in range, it is undefined beh...
Definition: vector_stacked.h:297
helper to distinguish iterators
Definition: vector_stacked.h:149
iterator insert(const_iterator pos, InputIt first, InputIt last)
Inserts the elements in the range [first,last) at pos. Can throw an exception if out of memory...
Definition: vector_stacked.h:598
iterator insert(const_iterator pos, T &&x)
Inserts x at pos. Can throw an exception if out of memory.
Definition: vector_stacked.h:585
const T & back() const
Access the last element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_stacked.h:380
size_t p_stack_size
size of one array in the stack
Definition: vector_stacked.h:176
bool grow_vector(size_t minimum_size=0)
Attempt to grow vector either to the given minimum size or using the default strategy, i.e. doubling size until the first element in the stack is full and after allocating max_grow elements at a time.
Definition: vector_stacked.h:241
const T * get_addr(size_t i) const
Helper to get memory address of element at index. Does not check if index is in range, it is undefined behavior to call this function with i >= size().
Definition: vector_stacked.h:294
void clear()
Removes all elements; does not free up memory, use shrink_to_fit() for that.
Definition: vector_stacked.h:410