Nugget
copy_help.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
5 
6 #ifndef EASTL_INTERNAL_COPY_HELP_H
7 #define EASTL_INTERNAL_COPY_HELP_H
8 
9 #include <EASTL/internal/config.h>
10 
11 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
12  #pragma once
13 #endif
14 
15 #include <EASTL/type_traits.h>
16 #include <EASTL/iterator.h>
17 
18 
19 namespace eastl
20 {
46 
47  // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access.
48  template <typename /*InputIteratorCategory*/, bool /*isMove*/, bool /*canMemmove*/>
50  {
51  template <typename InputIterator, typename OutputIterator>
52  static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
53  {
54  for(; first != last; ++result, ++first)
55  *result = *first;
56  return result;
57  }
58  };
59 
60  // Specialization for copying non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const.
61  // This specialization converts the random access InputIterator last-first to an integral type. There's simple way for us to take advantage of a random access output iterator,
62  // as the range is specified by the input instead of the output, and distance(first, last) for a non-random-access iterator is potentially slow.
63  template <>
64  struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, false, false>
65  {
66  template <typename InputIterator, typename OutputIterator>
67  static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
68  {
69  typedef typename eastl::iterator_traits<InputIterator>::difference_type difference_type;
70 
71  for(difference_type n = (last - first); n > 0; --n, ++first, ++result)
72  *result = *first;
73 
74  return result;
75  }
76  };
77 
78  // Specialization for moving non-trivial data via a lesser iterator than random-access.
79  template <typename InputIteratorCategory>
80  struct move_and_copy_helper<InputIteratorCategory, true, false>
81  {
82  template <typename InputIterator, typename OutputIterator>
83  static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
84  {
85  for(; first != last; ++result, ++first)
86  *result = eastl::move(*first);
87  return result;
88  }
89  };
90 
91  // Specialization for moving non-trivial data via a random-access iterator. It's theoretically faster because the compiler can see the count when its a compile-time const.
92  template <>
93  struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, true, false>
94  {
95  template <typename InputIterator, typename OutputIterator>
96  static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
97  {
98  typedef typename eastl::iterator_traits<InputIterator>::difference_type difference_type;
99 
100  for(difference_type n = (last - first); n > 0; --n, ++first, ++result)
101  *result = eastl::move(*first);
102 
103  return result;
104  }
105  };
106 
107  // Specialization for when we can use memmove/memcpy. See the notes above for what conditions allow this.
108  template <bool isMove>
109  struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, isMove, true>
110  {
111  template <typename T>
112  static T* move_or_copy(const T* first, const T* last, T* result)
113  {
114  if (EASTL_UNLIKELY(first == last))
115  return result;
116 
117  // We could use memcpy here if there's no range overlap, but memcpy is rarely much faster than memmove.
118  return (T*)__builtin_memmove(result, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first);
119  }
120  };
121 
122 
123 
124  template <bool isMove, typename InputIterator, typename OutputIterator>
125  inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result)
126  {
127  typedef typename eastl::iterator_traits<InputIterator>::iterator_category IIC;
128  typedef typename eastl::iterator_traits<OutputIterator>::iterator_category OIC;
129  typedef typename eastl::iterator_traits<InputIterator>::value_type value_type_input;
130  typedef typename eastl::iterator_traits<OutputIterator>::value_type value_type_output;
131 
132  const bool canBeMemmoved = eastl::is_trivially_copyable<value_type_output>::value &&
136 
137  return eastl::move_and_copy_helper<IIC, isMove, canBeMemmoved>::move_or_copy(first, last, result); // Need to chose based on the input iterator tag and not the output iterator tag, because containers accept input ranges of iterator types different than self.
138  }
139 
140 
141  // We have a second layer of unwrap_iterator calls because the original iterator might be something like move_iterator<generic_iterator<int*> > (i.e. doubly-wrapped).
142  template <bool isMove, typename InputIterator, typename OutputIterator>
143  inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result)
144  {
145  return OutputIterator(eastl::move_and_copy_chooser<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), eastl::unwrap_iterator(result))); // Have to convert to OutputIterator because result.base() could be a T*
146  }
147 
148 
168 
169  template <typename InputIterator, typename OutputIterator>
170  inline OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
171  {
172  return eastl::move_and_copy_unwrapper<true>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result);
173  }
174 
175 
190  template <typename InputIterator, typename OutputIterator>
191  inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
192  {
193  const bool isMove = eastl::is_move_iterator<InputIterator>::value; EA_UNUSED(isMove);
194 
195  return eastl::move_and_copy_unwrapper<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result);
196  }
197 } // namespace eastl
198 
199 #endif // EASTL_INTERNAL_COPY_HELP_H
EA Standard Template Library.
Definition: algorithm.h:288
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:191
OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
Definition: copy_help.h:170
Definition: iterator.h:583
Definition: type_compound.h:258
Definition: type_traits.h:604
Definition: type_pod.h:708
Definition: copy_help.h:50
Definition: iterator.h:77