72 #ifndef VECTOR_REALLOC_H 73 #define VECTOR_REALLOC_H 78 #include <type_traits> 84 #if __cplusplus >= 201703L 85 #define CONSTEXPR constexpr 96 constexpr
static bool value =
97 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::forward_iterator_tag >::value ||
98 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::bidirectional_iterator_tag >::value ||
99 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::random_access_iterator_tag >::value
100 #if __cplusplus >= 202000L 101 || std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::contiguous_iterator_tag >::value
109 std::is_same< typename std::iterator_traits<It>::iterator_category,
typename std::input_iterator_tag >::value;
122 static_assert(std::is_trivially_copyable<T>::value,
"Element type must be trivially copyable for realloc_vector::vector!\n");
128 static constexpr
size_t p_max_capacity = std::numeric_limits<size_t>::max() /
sizeof(T);
133 T* tmp = (T*)realloc(start,new_size*
sizeof(T));
134 if(!tmp)
return false;
136 p_capacity = new_size;
143 if(minimum_size > p_max_capacity)
return false;
144 size_t grow_capacity = p_capacity;
145 if(!grow_capacity) grow_capacity = 1;
146 if(grow_capacity > max_grow) grow_capacity = max_grow;
147 if(grow_capacity > p_max_capacity) grow_capacity = p_max_capacity;
148 if(p_max_capacity - grow_capacity < p_capacity) grow_capacity = p_max_capacity - p_capacity;
149 if(!grow_capacity)
return false;
150 size_t new_size = p_capacity + grow_capacity;
151 if(new_size < minimum_size) new_size = minimum_size;
152 return change_size(new_size);
158 typedef T value_type;
159 typedef size_t size_type;
160 typedef ssize_t difference_type;
161 typedef T& reference;
162 typedef const T& const_reference;
164 typedef const T* const_pointer;
169 vector() noexcept : start(
nullptr),p_size(0),p_capacity(0),max_grow(131072) { }
171 explicit vector(
size_t count,
const T& value = T(),
size_t max_grow_ = 131072);
173 template<class It, typename std::enable_if<at_least_input_iterator<It>::value,
int>::type = 0>
174 vector(It first, It last,
size_t max_grow_ = 131072);
187 if(p_size) resize(0);
188 if(start) free(start);
195 size_t size()
const {
return p_size; }
203 bool empty()
const {
return p_size == 0; }
208 if(max_grow_ == 0) max_grow = 131072;
209 else max_grow = max_grow_;
219 const T*
data()
const {
return start; }
226 T&
at(
size_t i) {
if(i < p_size)
return start[i];
throw std::out_of_range(
"vector::at(): index out of range!\n"); }
228 const T&
at(
size_t i)
const {
if(i < p_size)
return start[i];
throw std::out_of_range(
"vector::at(): index out of range!\n"); }
232 const T&
front()
const {
return start[0]; }
234 T&
back() {
return start[p_size - 1]; }
236 const T&
back()
const {
return start[p_size - 1]; }
240 bool reserve_nothrow(
size_t n);
242 void reserve(
size_t n) {
if(!reserve_nothrow(n))
throw std::bad_alloc(); }
244 void shrink_to_fit(
size_t new_capacity = 0);
249 void push_back(
const T& x);
251 void push_back(T&& x);
253 template<
class... Args> T& emplace_back(Args&&... args);
258 bool push_back_nothrow(
const T& x);
260 bool push_back_nothrow(T&& x);
262 template<
class... Args>
bool emplace_back_nothrow(Args&&... args);
266 void clear() {
while(p_size) start[--p_size].~T(); }
268 void pop_back() {
if(p_size) start[--p_size].~T(); }
272 bool resize_nothrow(
size_t count);
275 bool resize_nothrow(
size_t count,
const T& x);
278 void resize(
size_t count) {
if(!resize_nothrow(count))
throw std::bad_alloc(); }
281 void resize(
size_t count,
const T& x) {
if(!resize_nothrow(count,x))
throw std::bad_alloc(); }
289 bool insert_helper(
size_t pos,
size_t new_pos);
292 iterator
begin() {
return iterator(start); }
293 const_iterator
begin()
const {
return const_iterator(start); }
294 const_iterator
cbegin()
const {
return const_iterator(start); }
295 iterator
end() {
return iterator(start + p_size); }
296 const_iterator
end()
const {
return const_iterator(start + p_size); }
297 const_iterator
cend()
const {
return const_iterator(start + p_size); }
299 iterator erase(const_iterator pos);
300 iterator erase(const_iterator first, const_iterator last);
311 bool insert_nothrow(const_iterator pos, iterator& res,
const T& x);
316 bool insert_nothrow(const_iterator pos, iterator& res, T&& x);
321 bool insert_nothrow(const_iterator pos, iterator& res,
size_t count,
const T& x);
326 template<class InputIt, typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type = 0>
327 bool insert_nothrow(const_iterator pos, iterator& res, InputIt first, InputIt last);
330 iterator
insert(const_iterator pos,
const T& x) {
332 if(insert_nothrow(pos,res,x))
return res;
333 else throw std::bad_alloc();
336 iterator
insert(const_iterator pos, T&& x) {
338 if(insert_nothrow(pos,res,std::forward<T>(x)))
return res;
339 else throw std::bad_alloc();
342 iterator
insert(const_iterator pos,
size_t count,
const T& x) {
344 if(insert_nothrow(pos,res,count,x))
return res;
345 else throw std::bad_alloc();
348 template<class InputIt, typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type = 0>
349 iterator
insert(const_iterator pos, InputIt first, InputIt last) {
351 if(insert_nothrow(pos,res,first,last))
return res;
352 else throw std::bad_alloc();
362 start(nullptr),p_size(0),p_capacity(0),max_grow(max_grow_) {
364 if CONSTEXPR(std::is_nothrow_constructible<T>::value) {
366 for(
size_t i = 0; i<count; i++)
new(start + i) T(value);
368 else for(;p_size < count; ++p_size)
new(start + p_size) T(value);
371 template<
class T> template<class It, typename std::enable_if< at_least_input_iterator<It>::value,
int>::type >
373 start(nullptr),p_size(0),p_capacity(0),max_grow(max_grow_) {
374 for(; first != last; ++first) push_back(*first);
380 memcpy(start, v.
start,
sizeof(T)*(v.
size()));
387 swap(start, v.
start);
402 memcpy(start, v.
start,
sizeof(T)*(v.
size()));
410 if(start) free(start);
417 if(n > p_max_capacity)
return false;
418 if(n <= p_capacity)
return true;
419 return change_size(n);
424 if(new_capacity < p_size) new_capacity = p_size;
425 if(new_capacity > p_capacity)
return;
426 if(!change_size(new_capacity))
throw std::bad_alloc();
434 if(!push_back_nothrow(x))
throw std::bad_alloc();
438 if(!push_back_nothrow(std::forward<T>(x)))
throw std::bad_alloc();
440 template<
class T>
template<
class... Args>
442 if(!emplace_back_nothrow(std::forward<Args>(args)...))
throw std::bad_alloc();
447 if(p_size == p_capacity)
if(!grow_vector())
return false;
448 new(start + p_size) T(x);
454 if(p_size == p_capacity)
if(!grow_vector())
return false;
455 new(start + p_size) T(std::forward<T>(x));
459 template<
class T>
template<
class... Args>
461 if(p_size == p_capacity)
if(!grow_vector())
return false;
462 new(start + p_size) T(std::forward<Args>(args)...);
471 if(count == p_size)
return true;
472 if(!count) { clear();
return true; }
474 do { pop_back(); }
while(p_size > count);
478 if(count > p_capacity)
if(!grow_vector(count))
return false;
479 if CONSTEXPR(std::is_nothrow_constructible<T>::value) {
480 for(
size_t i = p_size; i<count; i++)
new(start + i) T();
483 else for(; p_size < count; p_size++)
new(start + p_size) T();
488 if(count == p_size)
return true;
489 if(!count) { clear();
return true; }
491 do { pop_back(); }
while(p_size > count);
495 if(count > p_capacity)
if(!grow_vector(count))
return false;
496 if CONSTEXPR(std::is_nothrow_copy_constructible<T>::value) {
497 for(
size_t i = p_size; i<count; i++)
new(start + i) T(x);
500 else for(; p_size < count; p_size++)
new(start + p_size) T(x);
507 size_t p2 = pos - start;
508 if(p2 >= p_size)
throw std::out_of_range(
"vector::erase(): iterator out of bounds!\n");
510 size_t remaining = (p_size - p2) - 1;
512 if(remaining) memmove(start + p2, start + p2 + 1, remaining*
sizeof(T));
518 ssize_t dist = last - first;
521 size_t p2 = first.data - start;
522 size_t p3 = last.
data - start;
523 if(p2 >= p_size || p3 > p_size)
throw std::out_of_range(
"vector::erase(): iterator out of bounds!\n");
524 for(
size_t i = p2; i < p3; i++) start[i].~T();
526 size_t remaining = (p_size - p3) - 1;
527 if(remaining) memmove(start + p2, start + p3, remaining*
sizeof(T));
538 size_t diff = new_pos - pos;
539 if(p_size > p_max_capacity - diff || !reserve_nothrow(p_size + diff))
return false;
541 size_t remaining = p_size - pos;
542 memmove(start + new_pos, start + pos, remaining*
sizeof(T));
550 if(pos == cend())
return push_back_nothrow(x);
551 size_t p2 = pos - start;
552 if(!insert_helper(p2,p2+1))
return false;
553 if CONSTEXPR(std::is_nothrow_copy_constructible<T>::value)
new(start + p2) T(x);
558 try {
new(start + p2) T(x); }
560 insert_helper(p2+1,p2);
571 if(pos == cend())
return push_back_nothrow(std::forward<T>(x));
572 size_t p2 = pos - start;
573 if(!insert_helper(p2,p2+1))
return false;
575 new(start + p2) T(std::forward<T>(x));
584 size_t p2 = pos - start;
586 if(!resize_nothrow(p_size + count, x))
return false;
591 if(!insert_helper(p2,p2+count))
return false;
592 if CONSTEXPR(std::is_nothrow_copy_constructible<T>::value)
for(
size_t i = 0; i < count; i++)
new(start + p2 + i) T(x);
599 for(; i < count; i++)
new(start + p2 + i) T(x);
608 insert_helper(p2+count,p2);
618 template<
class T>
template<
class InputIt,
619 typename std::enable_if<at_least_input_iterator<InputIt>::value,
int>::type >
621 size_t p2 = pos - start;
624 ssize_t dist = std::distance(first,last);
625 if(dist < 0)
return false;
628 if(!reserve_nothrow(p_size + dist))
return false;
629 for(; first != last; ++first) push_back(*first);
634 if(!insert_helper(p2,p2+dist))
return false;
635 if CONSTEXPR(std::is_nothrow_copy_constructible<T>::value) {
637 for(; first != last; ++first, p3++)
new(start + p3) T(*first);
645 for(; first != last; ++first, p3++)
new(start + p3) T(*first);
652 insert_helper(p2+dist,p2);
659 for(
size_t p3 = p2;first != last; ++first, p3++)
size_t max_grow
grow memory by maximum this many elements at a time
Definition: vector_realloc.h:127
helper to distinguish iterators
Definition: vector_realloc.h:95
bool empty() const
Returns true if the vector is empty.
Definition: vector_realloc.h:203
const T & at(size_t i) const
Access the ith element with bounds checking, throws an exception if i >= size()
Definition: vector_realloc.h:228
const_iterator cend() const
Iterator to the end.
Definition: vector_realloc.h:297
size_t p_size
number of elements in vector
Definition: vector_realloc.h:125
T * data()
Access the underlying array.
Definition: vector_realloc.h:217
iterator insert(const_iterator pos, T &&x)
Inserts x at pos. Can throw an exception if out of memory.
Definition: vector_realloc.h:336
T & back()
Access the last element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_realloc.h:234
T * iterator
Iterators are simple pointers to the data.
Definition: vector_realloc.h:284
void pop_back()
Removes the last element; does not free up memory, use shrink_to_fit() for that.
Definition: vector_realloc.h:268
const T * data() const
Access the underlying array.
Definition: vector_realloc.h:219
size_t get_max_grow() const
Get the maximum growth size. Memory is grown by this amount maximally.
Definition: vector_realloc.h:205
T * start
pointer to elements
Definition: vector_realloc.h:122
size_t p_capacity
current capacity of vector
Definition: vector_realloc.h:126
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_realloc.h:281
const T * const_iterator
Iterators are simple pointers to the data.
Definition: vector_realloc.h:286
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_realloc.h:330
iterator begin()
Iterator to the beginning.
Definition: vector_realloc.h:292
void reserve(size_t n)
Reserve memory for at least n elements. Throws an exception if memory allocation is not successful...
Definition: vector_realloc.h:242
bool grow_vector(size_t minimum_size=0)
Attempt to grow vector either to the given minimum size or by doubling the current size unless growth...
Definition: vector_realloc.h:142
T & front()
Access the first element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_realloc.h:230
bool change_size(size_t new_size)
Reallocate memory to the given new size.
Definition: vector_realloc.h:132
const T & front() const
Access the first element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_realloc.h:232
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_realloc.h:342
vector() noexcept
default constructor, creates empty vector, maximum growth is 128k elements
Definition: vector_realloc.h:169
const_iterator cbegin() const
Iterator to the beginning.
Definition: vector_realloc.h:294
size_t size() const
Current size, i.e. the number of elements stored in this vector.
Definition: vector_realloc.h:195
T & operator[](size_t i)
Access the ith element. It is undefined behavior to if i >= size()
Definition: vector_realloc.h:222
const T & back() const
Access the last element. It is undefined behavior if this function is called on an empty vector...
Definition: vector_realloc.h:236
const T & operator[](size_t i) const
Access the ith element. It is undefined behavior to if i >= size()
Definition: vector_realloc.h:224
iterator end()
Iterator to the end.
Definition: vector_realloc.h:295
size_t max_size() const
Maximum size to avoid overflow when calculating memory size.
Definition: vector_realloc.h:199
void set_max_grow(size_t max_grow_)
Set the maximum growth size. Memory is grown by this amount maximally.
Definition: vector_realloc.h:207
const_iterator end() const
Iterator to the end.
Definition: vector_realloc.h:296
Definition: vector_realloc.h:91
const_iterator begin() const
Iterator to the beginning.
Definition: vector_realloc.h:293
C++ vector-like container for trivially moveable types, using realloc() for growing memory...
Definition: vector_realloc.h:115
size_t capacity() const
Current capacity, i.e. the number of elements that can be stored without allocating more memory...
Definition: vector_realloc.h:197
void clear()
Removes all elements; does not free up memory, use shrink_to_fit() for that.
Definition: vector_realloc.h:266
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_realloc.h:349
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_realloc.h:278
size_t max_capacity() const
Maximum capacity to avoid overflow when calculating memory size.
Definition: vector_realloc.h:201
T & at(size_t i)
Access the ith element with bounds checking, throws an exception if i >= size()
Definition: vector_realloc.h:226