6 #ifndef TURI_GL_VECTOR_INTERNALS_H_ 7 #define TURI_GL_VECTOR_INTERNALS_H_ 15 #include <type_traits> 16 #include <initializer_list> 17 #include <core/util/basic_types.hpp> 18 #include <core/logging/assertions.hpp> 19 #include <core/util/basic_types.hpp> 23 #define _VEC_NDEBUG_NOEXCEPT noexcept 25 #define _VEC_NDEBUG_NOEXCEPT 28 #define _VEC_ENABLE_IF_ITERATOR(InputIterator, T) \ 29 typename std::enable_if<std::is_convertible< \ 30 typename std::iterator_traits< \ 31 InputIterator>::value_type, T>::value>::type* = 0 33 #define _VEC_ENABLE_IF_CONVERTABLE(T1, T2) \ 34 typename std::enable_if<std::is_convertible<T1, T2>::value>::type* = 0 36 static_assert(std::is_convertible<
37 typename std::iterator_traits<int*>::value_type,
int>::value,
"");
39 namespace turi {
namespace gl_vector_internal {
53 static constexpr
size_t _empty_gl_vector_element_size() {
57 return std::max<size_t>(1, (64 -
sizeof(_vstruct<T>)) / std::max<size_t>(1,
sizeof(T)));
62 static inline size_t _round_up_to_stride(
size_t n) {
65 case 1: n = (n + 15) & ~
size_t(15);
break;
66 case 2: n = (n + 7) & ~
size_t(7);
break;
67 case 4: n = (n + 3) & ~
size_t(3);
break;
68 case 8: n = (n + 1) & ~
size_t(1);
break;
72 DASSERT_EQ( (n *
sizeof(T)) % 16, 0);
77 static inline bool has_excess_storage(
const _vstruct<T>* info) {
78 return (capacity(info) > gl_vector_internal::_round_up_to_stride<T>(size(info)));
87 static inline _vstruct<T>* _allocate_vstruct(
size_t n) {
89 const bool allocate_with_calloc = std::is_trivial<T>::value;
91 n = _round_up_to_stride<T>(n);
93 _vstruct<T>* info = (allocate_with_calloc
94 ? (_vstruct<T>*) calloc(
sizeof(_vstruct<T>) + n*
sizeof(T), 1)
95 : (_vstruct<T>*) malloc(sizeof(_vstruct<T>) + n*sizeof(T)));
97 if(info ==
nullptr)
throw std::bad_alloc();
106 template <
typename T>
108 static inline void _destroy_element(T* ptr) {
109 if(!std::is_trivial<T>::value) {
114 template <
typename T>
116 static inline void _destroy_range(T* start, T* end) {
117 if(!std::is_trivial<T>::value) {
118 for(
auto ptr = start; ptr != end; ++ptr)
119 _destroy_element(ptr);
126 template <
typename T>
128 void uninitialized_move(T* first, T* last, T* dest) {
129 memmove(dest, first,
sizeof(T) * (last - first) );
132 template <
typename T>
134 void uninitialized_move_backward(T* first, T* last, T* dest_last) {
136 size_t n = last - first;
137 memmove(dest_last - n, first,
sizeof(T) * n);
142 template <
typename T>
144 void uninitialized_construct(T* first,
const T* last) {
146 if(std::is_trivial<T>::value) {
147 memset(first, 0, (last - first) *
sizeof(T));
149 for(;first != last; ++first) {
158 template <
typename T>
160 static inline size_t size (
const _vstruct<T>* info ) noexcept {
161 return (info ==
nullptr) ? 0 : info->size;
164 template <
typename T>
166 static inline size_t capacity (
const _vstruct<T>* info ) noexcept {
167 return (info ==
nullptr) ? 0 : info->capacity;
170 template <
typename T>
172 static inline T* begin (_vstruct<T>* info ) noexcept {
173 return (info ==
nullptr) ? nullptr : info->data;
176 template <
typename T>
178 static inline const T* cbegin (
const _vstruct<T>* info ) noexcept {
179 return (info ==
nullptr) ? nullptr : info->data;
182 template <
typename T>
184 static inline T* end (_vstruct<T>* info ) noexcept {
185 return (info ==
nullptr) ? nullptr : info->data + info->size;
188 template <
typename T>
190 static inline const T* cend (
const _vstruct<T>* info ) noexcept {
191 return (info ==
nullptr) ? nullptr : info->data + info->size;
195 template <
typename T>
197 static inline void _check_pointer_valid(_vstruct<T>* info,
const T* ptr,
bool include_end_point) {
200 if((info ==
nullptr && ptr !=
nullptr && !include_end_point)
203 || std::distance((
const T*)(info->data), ptr) > truncate_check<int64_t>(size(info))
204 || (!include_end_point && info->data + size(info) == ptr))))
206 throw std::out_of_range(
"Position of iterator points outside valid range.");
213 template <
typename T>
215 static inline void _extend_range(_vstruct<T>*& info,
size_t n,
bool extend_extra) {
217 size_t new_capacity = std::max<size_t>(_empty_gl_vector_element_size<T>(), extend_extra ? (5 * n) / 4 : n);
219 new_capacity = _round_up_to_stride<T>(new_capacity);
221 if(info ==
nullptr) {
222 info = (_vstruct<T>*) malloc(
sizeof(_vstruct<T>) + new_capacity*
sizeof(T));
223 if(UNLIKELY(info ==
nullptr))
throw std::bad_alloc();
226 info = (_vstruct<T>*) realloc(info,
sizeof(_vstruct<T>) + new_capacity*
sizeof(T));
227 if(UNLIKELY(info ==
nullptr))
throw std::bad_alloc();
230 info->capacity = new_capacity;
243 template <
typename T>
245 static inline _vstruct<T>* construct() {
251 template <
typename T>
253 static inline _vstruct<T>* construct(
size_t n,
const T& val) {
254 if(n == 0)
return nullptr;
255 _vstruct<T>* info = _allocate_vstruct<T>(n);
257 std::uninitialized_fill(info->data, info->data + n, val);
262 template <
typename T>
264 static inline _vstruct<T>* construct_uninitialized(
size_t capacity) {
265 _vstruct<T>* info = _allocate_vstruct<T>(capacity);
273 template <
typename T>
275 static inline _vstruct<T>* construct(
size_t n) {
276 size_t reserve_size = std::max(n, _empty_gl_vector_element_size<T>());
277 _vstruct<T>* info = _allocate_vstruct<T>(reserve_size);
279 new (&(info->data[0]))T[n];
284 template <
typename T,
typename InputIterator>
286 static inline _vstruct<T>* construct(
const InputIterator& first,
const InputIterator& last,
287 _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
288 long ln = std::distance(first, last);
292 if(n == 0)
return nullptr;
294 _vstruct<T>* info = _allocate_vstruct<T>(n);
297 std::uninitialized_copy(first, last, info->data);
305 template <
typename T>
307 static inline void destroy(_vstruct<T>*& info) {
311 _destroy_range(info->data, info->data + info->size);
319 template <
typename T>
320 static inline void resize (_vstruct<T>*& info,
size_t n) {
321 if(info ==
nullptr) {
322 info = construct<T>(n);
330 _destroy_range(info->data + n, info->data + info->size);
332 if(n > info->capacity) {
333 _extend_range(info, n,
false);
335 uninitialized_construct(info->data + info->size, info->data + n);
341 template <
typename T>
343 static inline void resize (_vstruct<T>*& info,
size_t n,
const T& val) {
344 if(info ==
nullptr) {
345 info = construct<T>(n, val);
353 _destroy_range(info->data + n, info->data + info->size);
355 if(n > info->capacity) {
356 _extend_range(info, n,
false);
358 std::uninitialized_fill(info->data + info->size, info->data + n, val);
367 template <
typename T>
369 static inline T& get_element(_vstruct<T>* info,
size_t idx) _VEC_NDEBUG_NOEXCEPT {
371 if(idx >= size(info))
372 throw std::out_of_range(std::string(
"Index ") + std::to_string(idx)
373 +
" outside of range (0, " + std::to_string(size(info)) +
"].");
376 return info->data[idx];
382 template <
typename T>
384 static inline void reserve (_vstruct<T>*& info,
size_t n) {
385 if(n > capacity(info))
386 _extend_range(info, n,
false);
392 template <
typename T,
class InputIterator>
393 static inline void assign (_vstruct<T>*& info, InputIterator first, InputIterator last,
394 _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
395 if(info ==
nullptr) {
396 info = construct<T>(first, last);
400 _destroy_range(info->data, info->data + info->size);
401 size_t n = std::distance(first, last);
403 if(n > info->capacity)
404 _extend_range(info, n,
false);
406 std::uninitialized_copy(first, last, info->data);
410 template <
typename T>
412 static inline void assign(_vstruct<T>*& info,
size_t n,
const T& val) {
413 if(info ==
nullptr) {
414 info = construct(n, val);
418 _destroy_range(info->data, info->data + info->size);
420 if(n > info->capacity)
421 _extend_range(info, n,
false);
424 std::uninitialized_fill(info->data, info->data + info->size, val);
427 template <
typename T>
429 static inline void assign(_vstruct<T>*& info, std::initializer_list<T> il) {
430 assign(info, il.begin(), il.end());
433 template <
typename T>
435 static inline void assign_move(_vstruct<T>*& info, _vstruct<T>*& other_info) {
436 if(other_info != info) {
437 gl_vector_internal::destroy(info);
439 other_info =
nullptr;
446 template <
typename T>
448 static inline void push_back(_vstruct<T>*& info,
const T& val) {
449 size_t s = size(info);
450 if(s == capacity(info))
451 _extend_range(info, s+1,
true);
453 new (&info->data[info->size]) T (val);
457 template <
typename T>
459 static inline void push_back(_vstruct<T>*& info, T&& val) {
460 if(info ==
nullptr) {
461 info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
462 }
else if(info->size == info->capacity) {
463 _extend_range(info, info->size + 1,
true);
466 new (&info->data[info->size]) T (std::forward<T>(val));
473 template <
typename T>
475 static inline void pop_back(_vstruct<T>*& info) {
479 throw std::out_of_range(
"pop_back called on empty gl_vector.");
483 _destroy_element(&info->data[info->size]);
489 template <
typename T,
class... Args>
491 T* emplace (_vstruct<T>*& info,
const T* position, Args&&... args) {
493 _check_pointer_valid(info, position,
true);
497 if(info ==
nullptr) {
498 info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
501 idx = std::distance((
const T*)(info->data), position);
503 if(info->capacity == info->size)
504 _extend_range(info, info->size + 1,
true);
507 T* ptr = info->data + idx;
509 uninitialized_move_backward(ptr, info->data + info->size, info->data + info->size + 1);
512 new (ptr) T (args...);
520 template <
typename T,
class... Args>
522 static inline void emplace_back (_vstruct<T>*& info, Args&&... args) {
523 if(info ==
nullptr) {
524 info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
525 }
else if(info->size == info->capacity) {
526 _extend_range(info, info->size + 1,
true);
529 T* ptr = &(info->data[info->size]);
531 new (ptr) T (args...);
537 template <
typename T,
typename U>
539 T* insert (_vstruct<T>*& info,
const T* position, U&& val) {
541 _check_pointer_valid(info, position,
true);
543 if(info ==
nullptr) {
544 info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
546 new (&info->data[0]) T (std::forward<U>(val));
550 size_t idx = std::distance((
const T*)(info->data), position);
552 if(info->capacity == info->size) {
553 _extend_range(info, info->size + 1,
true);
557 T* ptr = info->data + idx;
559 if(position != info->data + info->size)
560 uninitialized_move_backward(ptr, info->data + info->size - 1, info->data + info->size);
562 new (ptr) T (std::forward<U>(val));
569 template <
typename T>
571 T* insert (_vstruct<T>*& info,
const T* position,
size_t n,
const T& val) {
572 _check_pointer_valid(info, position,
true);
574 if(info ==
nullptr) {
575 assign(info, n, val);
576 return (UNLIKELY(info ==
nullptr)) ? nullptr : info->data;
579 size_t idx = std::distance((
const T*)(info->data), position);
582 return info->data + idx;
585 if(info->size + n > info->capacity)
586 _extend_range(info, info->size + n,
true);
588 T* ptr = info->data + idx;
590 if(position != info->data + info->size)
591 uninitialized_move_backward(ptr, info->data + info->size, info->data + info->size + n);
593 std::uninitialized_fill(ptr, ptr + n, val);
603 template <
typename T,
class InputIterator>
605 T* insert (_vstruct<T>*& info,
const T* position,
606 const T* start,
const T* end) {
609 && UNLIKELY(info->data <= start && start <= info->data + info->size)) {
611 std::vector<T> tmp(start, end);
612 return _insert(info, position, tmp.begin(), tmp.end());
615 return _insert(info, position, start, end);
619 template <
typename T,
class InputIterator>
621 T* insert (_vstruct<T>*& info,
const T* position,
622 InputIterator start, InputIterator end,
623 _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
624 return _insert(info, position, start, end);
627 template <
typename T,
class InputIterator>
630 bool _contains_iterator(_vstruct<T>*& info,
const InputIterator& it) {
634 template <
typename T>
637 bool _contains_iterator(
638 _vstruct<T>*& info,
const T* it) {
639 ptrdiff_t delta = std::distance(cbegin(info), it);
641 (delta >= 0) && (static_cast<int64_t>(delta) < static_cast<int64_t>(capacity(info))));
644 template <
typename T,
class InputIterator>
646 static T* _insert_with_overlapping_source_iterator
647 (_vstruct<T>*& info,
const T* position,
648 InputIterator start, InputIterator end) {
655 template <
typename T>
657 static T* _insert_with_overlapping_source_iterator
658 (_vstruct<T>*& info,
const T* position,
const T* start,
const T* end) {
664 _check_pointer_valid(info, position,
true);
665 _check_pointer_valid(info, start,
true);
666 _check_pointer_valid(info, start,
true);
669 _vstruct<T>* temp =
nullptr;
670 assign(temp, start, end);
671 return _insert(info, position, cbegin(temp), cend(temp));
675 template <
typename T,
class InputIterator>
677 T* _insert (_vstruct<T>*& info,
const T* position,
678 InputIterator start, InputIterator end,
679 _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
681 _check_pointer_valid(info, position,
true);
683 if(info ==
nullptr) {
684 assign(info, start, end);
685 return (UNLIKELY(info ==
nullptr)) ? nullptr : info->data;
688 size_t idx = std::distance((
const T*)(info->data), position);
691 return info->data + idx;
693 size_t n = std::distance(start, end);
695 if(info->size + n > capacity(info)) {
698 if(UNLIKELY(_contains_iterator(info, start))) {
699 return _insert_with_overlapping_source_iterator(
700 info, position, start, end);
703 _extend_range(info, info->size + n,
true);
707 if(position != info->data + info->size)
708 uninitialized_move_backward(info->data + idx, info->data + info->size, info->data + info->size + n);
710 std::uninitialized_copy(start, end, info->data + idx);
714 return info->data + idx;
719 template <
typename T>
721 T* erase (_vstruct<T>*& info,
const T* position) {
723 _check_pointer_valid(info, position,
false);
725 size_t idx = std::distance((
const T*)(info->data), position);
727 _destroy_element(position);
729 T* ptr = info->data + idx;
730 uninitialized_move(ptr + 1, info->data + info->size, ptr);
738 template <
typename T>
740 static inline T* erase(_vstruct<T>*& info,
const T* start,
const T* end) {
742 _check_pointer_valid(info, start,
true);
743 _check_pointer_valid(info, end,
true);
744 if(UNLIKELY(info ==
nullptr))
return nullptr;
747 throw std::out_of_range(
"Start and ending iterators out of order.");
749 size_t n = std::distance(start, end);
751 size_t start_idx = std::distance((
const T*)(info->data), start);
752 size_t end_idx = std::distance((
const T*)(info->data), end);
755 return info->data + start_idx;
757 _destroy_range(info->data + start_idx, info->data + end_idx);
759 uninitialized_move(info->data + end_idx,
760 info->data + info->size,
761 info->data + start_idx);
765 return info->data + start_idx;
771 template <
typename T>
773 static inline void _make_uninitialized_section (
774 _vstruct<T>*& info,
size_t idx_start,
size_t idx_end, ptrdiff_t n) {
776 DASSERT_LT(idx_start, idx_end);
778 ptrdiff_t extend_amount = (ptrdiff_t(n) - (ptrdiff_t(idx_end) - ptrdiff_t(idx_start)));
779 size_t new_size = size(info) + extend_amount;
781 _destroy_range(info->data + idx_start, info->data + idx_end);
783 if(extend_amount > 0) {
784 if(new_size > capacity(info)) {
785 _extend_range(info, new_size,
true);
788 if(idx_end != info->size) {
789 uninitialized_move_backward(info->data + idx_end, info->data + info->size, info->data + new_size);
792 }
else if(extend_amount < 0) {
796 uninitialized_move(info->data + idx_end,
797 info->data + info->size,
798 info->data + idx_end + extend_amount);
801 info->size = new_size;
804 template <
typename T,
class InputIterator>
806 static inline void replace (_vstruct<T>*& info,
807 const T* position_start,
808 const T* position_end,
811 _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
813 _check_pointer_valid(info, position_start,
true);
814 _check_pointer_valid(info, position_end,
true);
817 if(UNLIKELY(info ==
nullptr)) {
820 assign(info, start, end);
824 if(UNLIKELY(position_start == position_end)) {
825 insert(info, position_start, start, end);
829 size_t idx_start = std::distance((
const T*)(info->data), position_start);
830 size_t idx_end = std::distance((
const T*)(info->data), position_end);
831 ptrdiff_t n = std::distance(start, end);
833 _make_uninitialized_section(info, idx_start, idx_end, n);
835 std::uninitialized_copy(start, end, info->data + idx_start);
838 template <
typename T>
840 static inline void replace (_vstruct<T>*& info,
841 const T* position_start,
842 const T* position_end,
843 size_t n,
const T& val) {
845 _check_pointer_valid(info, position_start,
true);
846 _check_pointer_valid(info, position_end,
true);
849 if(UNLIKELY(info ==
nullptr)) {
852 assign(info, n, val);
856 if(UNLIKELY(position_start == position_end)) {
857 insert(info, position_start, n, val);
861 size_t idx_start = std::distance((
const T*)(info->data), position_start);
862 size_t idx_end = std::distance((
const T*)(info->data), position_end);
864 _make_uninitialized_section(info, idx_start, idx_end, ptrdiff_t(n));
866 std::uninitialized_fill(info->data + idx_start, info->data + idx_start + n, val);
871 template <
typename T>
872 void clear(_vstruct<T>*& info) noexcept {
876 _destroy_range(info->data, info->data + info->size);
#define GL_HOT_INLINE_FLATTEN
#define DASSERT_TRUE(cond)