Turi Create  4.0
vector_internals.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_GL_VECTOR_INTERNALS_H_
7 #define TURI_GL_VECTOR_INTERNALS_H_
8 
9 #include <cstdint>
10 #include <cstdlib>
11 #include <algorithm>
12 #include <iterator>
13 #include <memory>
14 #include <exception>
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>
20 #include <utility>
21 
22 #ifdef NDEBUG
23 #define _VEC_NDEBUG_NOEXCEPT noexcept
24 #else
25 #define _VEC_NDEBUG_NOEXCEPT
26 #endif
27 
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
32 
33 #define _VEC_ENABLE_IF_CONVERTABLE(T1, T2) \
34  typename std::enable_if<std::is_convertible<T1, T2>::value>::type* = 0
35 
36 static_assert(std::is_convertible<
37  typename std::iterator_traits<int*>::value_type, int>::value, "");
38 
39 namespace turi { namespace gl_vector_internal {
40 
41 
42 // The main structure
43 template <typename T>
44 struct _vstruct {
45  size_t size;
46  size_t capacity;
47  T data[0];
48 };
49 
50 ////////////////////////////////////////////////////////////////////////////////
51 // Some default sizes
52 template <typename T>
53 static constexpr size_t _empty_gl_vector_element_size() {
54 
55  // Allocate it so that the entire struct fits in 64 bytes, and 64
56  // bytes is used.
57  return std::max<size_t>(1, (64 - sizeof(_vstruct<T>)) / std::max<size_t>(1, sizeof(T)));
58 }
59 
60 template <typename T>
62 static inline size_t _round_up_to_stride(size_t n) {
63 
64  switch(sizeof(T)) {
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;
69  default: return n;
70  }
71 
72  DASSERT_EQ( (n * sizeof(T)) % 16, 0);
73  return n;
74 }
75 
76 template <typename T>
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)));
79 }
80 
81 
82 ////////////////////////////////////////////////////////////////////////////////
83 // Allocation of the implementation
84 
85 template <typename T>
87 static inline _vstruct<T>* _allocate_vstruct(size_t n) {
88 
89  const bool allocate_with_calloc = std::is_trivial<T>::value;
90 
91  n = _round_up_to_stride<T>(n);
92 
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)));
96 
97  if(info == nullptr) throw std::bad_alloc();
98  info->capacity = n;
99  return info;
100 }
101 
102 
103 ////////////////////////////////////////////////////////////////////////////////
104 // Destruction
105 
106 template <typename T>
108 static inline void _destroy_element(T* ptr) {
109  if(!std::is_trivial<T>::value) {
110  ptr->~T();
111  }
112 }
113 
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);
120  }
121 }
122 
123 ////////////////////////////////////////////////////////////////////////////////
124 // Utilities
125 
126 template <typename T>
128 void uninitialized_move(T* first, T* last, T* dest) {
129  memmove(dest, first, sizeof(T) * (last - first) );
130 }
131 
132 template <typename T>
134 void uninitialized_move_backward(T* first, T* last, T* dest_last) {
135 
136  size_t n = last - first;
137  memmove(dest_last - n, first, sizeof(T) * n);
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 
142 template <typename T>
144 void uninitialized_construct(T* first, const T* last) {
145 
146  if(std::is_trivial<T>::value) {
147  memset(first, 0, (last - first) * sizeof(T));
148  } else {
149  for(;first != last; ++first) {
150  new (first) T ();
151  }
152  }
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 // Size
157 
158 template <typename T>
160 static inline size_t size (const _vstruct<T>* info ) noexcept {
161  return (info == nullptr) ? 0 : info->size;
162 }
163 
164 template <typename T>
166 static inline size_t capacity (const _vstruct<T>* info ) noexcept {
167  return (info == nullptr) ? 0 : info->capacity;
168 }
169 
170 template <typename T>
172 static inline T* begin (_vstruct<T>* info ) noexcept {
173  return (info == nullptr) ? nullptr : info->data;
174 }
175 
176 template <typename T>
178 static inline const T* cbegin (const _vstruct<T>* info ) noexcept {
179  return (info == nullptr) ? nullptr : info->data;
180 }
181 
182 template <typename T>
184 static inline T* end (_vstruct<T>* info ) noexcept {
185  return (info == nullptr) ? nullptr : info->data + info->size;
186 }
187 
188 template <typename T>
190 static inline const T* cend (const _vstruct<T>* info ) noexcept {
191  return (info == nullptr) ? nullptr : info->data + info->size;
192 }
193 
194 
195 template <typename T>
197 static inline void _check_pointer_valid(_vstruct<T>* info, const T* ptr, bool include_end_point) {
198 
199 #ifndef NDEBUG
200  if((info == nullptr && ptr != nullptr && !include_end_point)
201  || (info != nullptr
202  && (ptr < info->data
203  || std::distance((const T*)(info->data), ptr) > truncate_check<int64_t>(size(info))
204  || (!include_end_point && info->data + size(info) == ptr))))
205 
206  throw std::out_of_range("Position of iterator points outside valid range.");
207 #endif
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 // Reallocation
212 
213 template <typename T>
215 static inline void _extend_range(_vstruct<T>*& info, size_t n, bool extend_extra) {
216 
217  size_t new_capacity = std::max<size_t>(_empty_gl_vector_element_size<T>(), extend_extra ? (5 * n) / 4 : n);
218 
219  new_capacity = _round_up_to_stride<T>(new_capacity);
220 
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();
224  info->size = 0;
225  } else {
226  info = (_vstruct<T>*) realloc(info, sizeof(_vstruct<T>) + new_capacity*sizeof(T));
227  if(UNLIKELY(info == nullptr)) throw std::bad_alloc();
228  }
229 
230  info->capacity = new_capacity;
231 }
232 
233 ////////////////////////////////////////////////////////////////////////////////
234 //
235 // The implementations of the member functions
236 //
237 ////////////////////////////////////////////////////////////////////////////////
238 
239 
240 ////////////////////////////////////////////////////////////////////////////////
241 // Construction routines
242 
243 template <typename T>
245 static inline _vstruct<T>* construct() {
246  return nullptr;
247 }
248 
249 ////////////////////////////////////////////////////////////
250 
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);
256  info->size = n;
257  std::uninitialized_fill(info->data, info->data + n, val);
258  return info;
259 }
260 
261 
262 template <typename T>
264 static inline _vstruct<T>* construct_uninitialized(size_t capacity) {
265  _vstruct<T>* info = _allocate_vstruct<T>(capacity);
266  info->size = 0;
267  return info;
268 }
269 
270 
271 ////////////////////////////////////////////////////////////
272 
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);
278  info->size = n;
279  new (&(info->data[0]))T[n];
280  return info;
281 }
282 
283 ////////////////////////////////////////////////////////////
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);
289  DASSERT_TRUE(ln >= 0);
290  size_t n = ln;
291 
292  if(n == 0) return nullptr;
293 
294  _vstruct<T>* info = _allocate_vstruct<T>(n);
295 
296  info->size = n;
297  std::uninitialized_copy(first, last, info->data);
298 
299  return info;
300 }
301 
302 ////////////////////////////////////////////////////////////////////////////////
303 // Destruction routines
304 
305 template <typename T>
307 static inline void destroy(_vstruct<T>*& info) {
308  if(info == nullptr)
309  return;
310 
311  _destroy_range(info->data, info->data + info->size);
312  free(info);
313  info = nullptr;
314 }
315 
316 ////////////////////////////////////////////////////////////////////////////////
317 // Resizing routines
318 
319 template <typename T>
320 static inline void resize (_vstruct<T>*& info, size_t n) {
321  if(info == nullptr) {
322  info = construct<T>(n);
323  return;
324  }
325 
326  if(info->size == n)
327  return;
328 
329  if(n < info->size) {
330  _destroy_range(info->data + n, info->data + info->size);
331  } else {
332  if(n > info->capacity) {
333  _extend_range(info, n, false);
334  }
335  uninitialized_construct(info->data + info->size, info->data + n);
336  }
337 
338  info->size = n;
339 }
340 
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);
346  return;
347  }
348 
349  if(info->size == n)
350  return;
351 
352  if(n < info->size) {
353  _destroy_range(info->data + n, info->data + info->size);
354  } else {
355  if(n > info->capacity) {
356  _extend_range(info, n, false);
357  }
358  std::uninitialized_fill(info->data + info->size, info->data + n, val);
359  }
360 
361  info->size = n;
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 // Element access routines
366 
367 template <typename T>
369 static inline T& get_element(_vstruct<T>* info, size_t idx) _VEC_NDEBUG_NOEXCEPT {
370 #ifndef NDEBUG
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)) + "].");
374 #endif
375 
376  return info->data[idx];
377 }
378 
379 ////////////////////////////////////////////////////////////////////////////////
380 // Reserve capacity
381 
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);
387 }
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 // Assignment operators
391 
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);
397  return;
398  }
399 
400  _destroy_range(info->data, info->data + info->size);
401  size_t n = std::distance(first, last);
402 
403  if(n > info->capacity)
404  _extend_range(info, n, false);
405 
406  std::uninitialized_copy(first, last, info->data);
407  info->size = n;
408 }
409 
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);
415  return;
416  }
417 
418  _destroy_range(info->data, info->data + info->size);
419 
420  if(n > info->capacity)
421  _extend_range(info, n, false);
422 
423  info->size = n;
424  std::uninitialized_fill(info->data, info->data + info->size, val);
425 }
426 
427 template <typename T>
429 static inline void assign(_vstruct<T>*& info, std::initializer_list<T> il) {
430  assign(info, il.begin(), il.end());
431 }
432 
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);
438  info = other_info;
439  other_info = nullptr;
440  }
441 }
442 
443 ////////////////////////////////////////////////////////////////////////////////
444 // Push back
445 
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);
452 
453  new (&info->data[info->size]) T (val);
454  ++info->size;
455 }
456 
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);
464  }
465 
466  new (&info->data[info->size]) T (std::forward<T>(val));
467  ++info->size;
468 }
469 
470 ////////////////////////////////////////////////////////////////////////////////
471 // pop back
472 
473 template <typename T>
475 static inline void pop_back(_vstruct<T>*& info) {
476 
477 #ifndef NDEBUG
478  if(size(info) == 0)
479  throw std::out_of_range("pop_back called on empty gl_vector.");
480 #endif
481 
482  --info->size;
483  _destroy_element(&info->data[info->size]);
484 }
485 
486 ////////////////////////////////////////////////////////////////////////////////
487 // emplace
488 
489 template <typename T, class... Args>
491 T* emplace (_vstruct<T>*& info, const T* position, Args&&... args) {
492 
493  _check_pointer_valid(info, position, true);
494 
495  size_t idx;
496 
497  if(info == nullptr) {
498  info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
499  idx = 0;
500  } else {
501  idx = std::distance((const T*)(info->data), position);
502 
503  if(info->capacity == info->size)
504  _extend_range(info, info->size + 1, true);
505  }
506 
507  T* ptr = info->data + idx;
508 
509  uninitialized_move_backward(ptr, info->data + info->size, info->data + info->size + 1);
510  ++info->size;
511 
512  new (ptr) T (args...);
513 
514  return ptr;
515 }
516 
517 ////////////////////////////////////////////////////////////////////////////////
518 // emplace back
519 
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);
527  }
528 
529  T* ptr = &(info->data[info->size]);
530  ++info->size;
531  new (ptr) T (args...);
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 // Insertion
536 
537 template <typename T, typename U>
539 T* insert (_vstruct<T>*& info, const T* position, U&& val) {
540 
541  _check_pointer_valid(info, position, true);
542 
543  if(info == nullptr) {
544  info = construct_uninitialized<T>(_empty_gl_vector_element_size<T>());
545  info->size = 1;
546  new (&info->data[0]) T (std::forward<U>(val));
547  return info->data;
548  }
549 
550  size_t idx = std::distance((const T*)(info->data), position);
551 
552  if(info->capacity == info->size) {
553  _extend_range(info, info->size + 1, true);
554  }
555 
556  ++(info->size);
557  T* ptr = info->data + idx;
558 
559  if(position != info->data + info->size)
560  uninitialized_move_backward(ptr, info->data + info->size - 1, info->data + info->size);
561 
562  new (ptr) T (std::forward<U>(val));
563 
564  return ptr;
565 }
566 
567 ////////////////////////////////////////////////////////////
568 
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);
573 
574  if(info == nullptr) {
575  assign(info, n, val);
576  return (UNLIKELY(info == nullptr)) ? nullptr : info->data;
577  }
578 
579  size_t idx = std::distance((const T*)(info->data), position);
580 
581  if(n == 0)
582  return info->data + idx;
583 
584  // if(info->capacity < info->size + n)
585  if(info->size + n > info->capacity)
586  _extend_range(info, info->size + n, true);
587 
588  T* ptr = info->data + idx;
589 
590  if(position != info->data + info->size)
591  uninitialized_move_backward(ptr, info->data + info->size, info->data + info->size + n);
592 
593  std::uninitialized_fill(ptr, ptr + n, val);
594 
595  info->size += n;
596 
597  return ptr;
598 }
599 
600 ////////////////////////////////////////////////////////////
601 
602 // Do this to properly handle, e.g. x + x in the string case.
603 template <typename T, class InputIterator>
605 T* insert (_vstruct<T>*& info, const T* position,
606  const T* start, const T* end) {
607 
608  if(info != nullptr
609  && UNLIKELY(info->data <= start && start <= info->data + info->size)) {
610 
611  std::vector<T> tmp(start, end);
612  return _insert(info, position, tmp.begin(), tmp.end());
613  }
614 
615  return _insert(info, position, start, end);
616 }
617 
618 // The general case.
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);
625 }
626 
627 template <typename T, class InputIterator>
628 static inline
630 bool _contains_iterator(_vstruct<T>*& info, const InputIterator& it) {
631  return false;
632 }
633 
634 template <typename T>
636 static inline
637 bool _contains_iterator(
638  _vstruct<T>*& info, const T* it) {
639  ptrdiff_t delta = std::distance(cbegin(info), it);
640  return (
641  (delta >= 0) && (static_cast<int64_t>(delta) < static_cast<int64_t>(capacity(info))));
642 }
643 
644 template <typename T, class InputIterator>
645 GL_HOT_NOINLINE
646 static T* _insert_with_overlapping_source_iterator
647 (_vstruct<T>*& info, const T* position,
648  InputIterator start, InputIterator end) {
649 
650  // The specialization below should be the only one that's actually called.
651  DASSERT_TRUE(false);
652  return nullptr;
653 }
654 
655 template <typename T>
656 GL_HOT_NOINLINE
657 static T* _insert_with_overlapping_source_iterator
658 (_vstruct<T>*& info, const T* position, const T* start, const T* end) {
659 
660  // Add in these checks to make sure that we're using
661  // this function appropriately
662 #ifndef NDEBUG
663  DASSERT_TRUE(info != nullptr);
664  _check_pointer_valid(info, position, true);
665  _check_pointer_valid(info, start, true);
666  _check_pointer_valid(info, start, true);
667 #endif
668 
669  _vstruct<T>* temp = nullptr;
670  assign(temp, start, end);
671  return _insert(info, position, cbegin(temp), cend(temp));
672 }
673 
674 // The base case.
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)) {
680 
681  _check_pointer_valid(info, position, true);
682 
683  if(info == nullptr) {
684  assign(info, start, end);
685  return (UNLIKELY(info == nullptr)) ? nullptr : info->data;
686  }
687 
688  size_t idx = std::distance((const T*)(info->data), position);
689 
690  if(start == end)
691  return info->data + idx;
692 
693  size_t n = std::distance(start, end);
694 
695  if(info->size + n > capacity(info)) {
696  // Need to check that extending the range
697  // does not invalidate the iterators for start and end.
698  if(UNLIKELY(_contains_iterator(info, start))) {
699  return _insert_with_overlapping_source_iterator(
700  info, position, start, end);
701  }
702 
703  _extend_range(info, info->size + n, true);
704  }
705 
706 
707  if(position != info->data + info->size)
708  uninitialized_move_backward(info->data + idx, info->data + info->size, info->data + info->size + n);
709 
710  std::uninitialized_copy(start, end, info->data + idx);
711 
712  info->size += n;
713 
714  return info->data + idx;
715 }
716 
717 ////////////////////////////////////////////////////////////
718 
719 template <typename T>
721 T* erase (_vstruct<T>*& info, const T* position) {
722 
723  _check_pointer_valid(info, position, false);
724 
725  size_t idx = std::distance((const T*)(info->data), position);
726 
727  _destroy_element(position);
728 
729  T* ptr = info->data + idx;
730  uninitialized_move(ptr + 1, info->data + info->size, ptr);
731  --info->size;
732 
733  return ptr;
734 }
735 
736 ////////////////////////////////////////////////////////////
737 
738 template <typename T>
740 static inline T* erase(_vstruct<T>*& info, const T* start, const T* end) {
741 
742  _check_pointer_valid(info, start, true);
743  _check_pointer_valid(info, end, true);
744  if(UNLIKELY(info == nullptr)) return nullptr;
745 
746  if(start > end)
747  throw std::out_of_range("Start and ending iterators out of order.");
748 
749  size_t n = std::distance(start, end);
750 
751  size_t start_idx = std::distance((const T*)(info->data), start);
752  size_t end_idx = std::distance((const T*)(info->data), end);
753 
754  if(start == end)
755  return info->data + start_idx;
756 
757  _destroy_range(info->data + start_idx, info->data + end_idx);
758 
759  uninitialized_move(info->data + end_idx,
760  info->data + info->size,
761  info->data + start_idx);
762 
763  info->size -= n;
764 
765  return info->data + start_idx;
766 }
767 
768 // Creates an empty space of size n, replacing everything from
769 // idx_start to idx_end. idx_start to idx_start + n will then be free
770 // and uninitialized.
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) {
775 
776  DASSERT_LT(idx_start, idx_end);
777 
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;
780 
781  _destroy_range(info->data + idx_start, info->data + idx_end);
782 
783  if(extend_amount > 0) {
784  if(new_size > capacity(info)) {
785  _extend_range(info, new_size, true);
786  }
787 
788  if(idx_end != info->size) {
789  uninitialized_move_backward(info->data + idx_end, info->data + info->size, info->data + new_size);
790  }
791 
792  } else if(extend_amount < 0) {
793 
794  DASSERT_TRUE(idx_end + extend_amount >= 0);
795 
796  uninitialized_move(info->data + idx_end,
797  info->data + info->size,
798  info->data + idx_end + extend_amount);
799  }
800 
801  info->size = new_size;
802 }
803 
804 template <typename T, class InputIterator>
806 static inline void replace (_vstruct<T>*& info,
807  const T* position_start,
808  const T* position_end,
809  InputIterator start,
810  InputIterator end,
811  _VEC_ENABLE_IF_ITERATOR(InputIterator, T)) {
812 
813  _check_pointer_valid(info, position_start, true);
814  _check_pointer_valid(info, position_end, true);
815  DASSERT_TRUE(position_start <= position_end);
816 
817  if(UNLIKELY(info == nullptr)) {
818  DASSERT_TRUE(position_start == nullptr);
819  DASSERT_TRUE(position_end == nullptr);
820  assign(info, start, end);
821  return;
822  }
823 
824  if(UNLIKELY(position_start == position_end)) {
825  insert(info, position_start, start, end);
826  return;
827  }
828 
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);
832 
833  _make_uninitialized_section(info, idx_start, idx_end, n);
834 
835  std::uninitialized_copy(start, end, info->data + idx_start);
836 }
837 
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) {
844 
845  _check_pointer_valid(info, position_start, true);
846  _check_pointer_valid(info, position_end, true);
847  DASSERT_TRUE(position_start <= position_end);
848 
849  if(UNLIKELY(info == nullptr)) {
850  DASSERT_TRUE(position_start == nullptr);
851  DASSERT_TRUE(position_end == nullptr);
852  assign(info, n, val);
853  return;
854  }
855 
856  if(UNLIKELY(position_start == position_end)) {
857  insert(info, position_start, n, val);
858  return;
859  }
860 
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);
863 
864  _make_uninitialized_section(info, idx_start, idx_end, ptrdiff_t(n));
865 
866  std::uninitialized_fill(info->data + idx_start, info->data + idx_start + n, val);
867 }
868 
869 ////////////////////////////////////////////////////////////
870 
871 template <typename T>
872 void clear(_vstruct<T>*& info) noexcept {
873  if(size(info) == 0)
874  return;
875 
876  _destroy_range(info->data, info->data + info->size);
877  info->size = 0;
878 }
879 
880 
881 
882 }}
883 
884 
885 #endif /* TURI_VECTOR_INTERNALS_H_ */
#define GL_HOT_INLINE
#define GL_HOT_INLINE_FLATTEN
#define DASSERT_TRUE(cond)
Definition: assertions.hpp:364