aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/internal/copy_help.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/internal/copy_help.h')
-rw-r--r--include/EASTL/internal/copy_help.h221
1 files changed, 0 insertions, 221 deletions
diff --git a/include/EASTL/internal/copy_help.h b/include/EASTL/internal/copy_help.h
deleted file mode 100644
index 0b2c1b8..0000000
--- a/include/EASTL/internal/copy_help.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/////////////////////////////////////////////////////////////////////////////
-// Copyright (c) Electronic Arts Inc. All rights reserved.
-/////////////////////////////////////////////////////////////////////////////
-
-
-#ifndef EASTL_INTERNAL_COPY_HELP_H
-#define EASTL_INTERNAL_COPY_HELP_H
-
-#include <EASTL/internal/config.h>
-
-#if defined(EA_PRAGMA_ONCE_SUPPORTED)
- #pragma once
-#endif
-
-#include <EASTL/type_traits.h>
-#include <EASTL/iterator.h>
-#include <string.h> // memcpy, memcmp, memmove
-
-
-namespace eastl
-{
- /// move / move_n / move_backward
- /// copy / copy_n / copy_backward
- ///
- /// We want to optimize move, move_n, move_backward, copy, copy_backward, copy_n to do memmove operations
- /// when possible.
- ///
- /// We could possibly use memcpy, though it has stricter overlap requirements than the move and copy
- /// algorithms and would require a runtime if/else to choose it over memmove. In particular, memcpy
- /// allows no range overlap at all, whereas move/copy allow output end overlap and move_backward/copy_backward
- /// allow output begin overlap. Despite this it might be useful to use memcpy for any platforms where
- /// memcpy is significantly faster than memmove, and since in most cases the copy/move operation in fact
- /// doesn't target overlapping memory and so memcpy would be usable.
- ///
- /// We can use memmove/memcpy if the following hold true:
- /// InputIterator and OutputIterator are of the same type.
- /// InputIterator and OutputIterator are of type contiguous_iterator_tag or simply are pointers (the two are virtually synonymous).
- /// is_trivially_copyable<T>::value is true. i.e. the constructor T(const T& t) (or T(T&& t) if present) can be replaced by memmove(this, &t, sizeof(T))
- ///
- /// copy normally differs from move, but there is a case where copy is the same as move: when copy is
- /// used with a move_iterator. We handle that case here by detecting that copy is being done with a
- /// move_iterator and redirect it to move (which can take advantage of memmove/memcpy).
- ///
- /// The generic_iterator class is typically used for wrapping raw memory pointers so they can act like
- /// formal iterators. Since pointers provide an opportunity for memmove/memcpy operations, we can
- /// detect a generic iterator and use it's wrapped type as a pointer if it happens to be one.
-
- // Implementation moving copying both trivial and non-trivial data via a lesser iterator than random-access.
- template <typename /*InputIteratorCategory*/, bool /*isMove*/, bool /*canMemmove*/>
- struct move_and_copy_helper
- {
- template <typename InputIterator, typename OutputIterator>
- static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
- {
- for(; first != last; ++result, ++first)
- *result = *first;
- return result;
- }
- };
-
- // 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.
- // 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,
- // 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.
- template <>
- struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, false, false>
- {
- template <typename InputIterator, typename OutputIterator>
- static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
- {
- typedef typename eastl::iterator_traits<InputIterator>::difference_type difference_type;
-
- for(difference_type n = (last - first); n > 0; --n, ++first, ++result)
- *result = *first;
-
- return result;
- }
- };
-
- // Specialization for moving non-trivial data via a lesser iterator than random-access.
- template <typename InputIteratorCategory>
- struct move_and_copy_helper<InputIteratorCategory, true, false>
- {
- template <typename InputIterator, typename OutputIterator>
- static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
- {
- for(; first != last; ++result, ++first)
- *result = eastl::move(*first);
- return result;
- }
- };
-
- // 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.
- template <>
- struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, true, false>
- {
- template <typename InputIterator, typename OutputIterator>
- static OutputIterator move_or_copy(InputIterator first, InputIterator last, OutputIterator result)
- {
- typedef typename eastl::iterator_traits<InputIterator>::difference_type difference_type;
-
- for(difference_type n = (last - first); n > 0; --n, ++first, ++result)
- *result = eastl::move(*first);
-
- return result;
- }
- };
-
- // Specialization for when we can use memmove/memcpy. See the notes above for what conditions allow this.
- template <bool isMove>
- struct move_and_copy_helper<EASTL_ITC_NS::random_access_iterator_tag, isMove, true>
- {
- template <typename T>
- static T* move_or_copy(const T* first, const T* last, T* result)
- {
- if (EASTL_UNLIKELY(first == last))
- return result;
-
- // We could use memcpy here if there's no range overlap, but memcpy is rarely much faster than memmove.
- return (T*)memmove(result, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first);
- }
- };
-
-
- namespace internal {
- // This exists to handle the case when EASTL_ITC_NS is `std`
- // and the C++ version is older than C++20, in this case
- // std::contiguous_iterator_tag does not exist so we can't use
- // is_same<> directly.
- #if !EASTL_STD_ITERATOR_CATEGORY_ENABLED || defined(EA_COMPILER_CPP20_ENABLED)
- template <typename IC>
- using is_contiguous_iterator_helper = eastl::is_same<IC, EASTL_ITC_NS::contiguous_iterator_tag>;
- #else
- template <typename IC>
- using is_contiguous_iterator_helper = eastl::false_type;
- #endif
-
- template <typename InputIterator, typename OutputIterator>
- struct can_be_memmoved_helper {
- using IIC = typename eastl::iterator_traits<InputIterator>::iterator_category;
- using OIC = typename eastl::iterator_traits<OutputIterator>::iterator_category;
- using value_type_input = typename eastl::iterator_traits<InputIterator>::value_type;
- using value_type_output = typename eastl::iterator_traits<OutputIterator>::value_type;
-
- static constexpr bool value = eastl::is_trivially_copyable<value_type_output>::value &&
- eastl::is_same<value_type_input, value_type_output>::value &&
- (eastl::is_pointer<InputIterator>::value || is_contiguous_iterator_helper<IIC>::value) &&
- (eastl::is_pointer<OutputIterator>::value || is_contiguous_iterator_helper<OIC>::value);
-
- };
- }
-
- template <bool isMove, typename InputIterator, typename OutputIterator>
- inline OutputIterator move_and_copy_chooser(InputIterator first, InputIterator last, OutputIterator result)
- {
- typedef typename eastl::iterator_traits<InputIterator>::iterator_category IIC;
-
- const bool canBeMemmoved = internal::can_be_memmoved_helper<InputIterator, OutputIterator>::value;
-
- 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.
- }
-
-
- // 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).
- template <bool isMove, typename InputIterator, typename OutputIterator>
- inline OutputIterator move_and_copy_unwrapper(InputIterator first, InputIterator last, OutputIterator result)
- {
- 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 unwrap_iterator(result) could be a T*
- }
-
-
- /// move
- ///
- /// After this operation the elements in the moved-from range will still contain valid values of the
- /// appropriate type, but not necessarily the same values as before the move.
- /// Returns the end of the result range.
- /// Note: When moving between containers, the dest range must be valid; this function doesn't resize containers.
- /// Note: if result is within [first, last), move_backward must be used instead of move.
- ///
- /// Example usage:
- /// eastl::move(myArray.begin(), myArray.end(), myDestArray.begin());
- ///
- /// Reference implementation:
- /// template <typename InputIterator, typename OutputIterator>
- /// OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
- /// {
- /// while(first != last)
- /// *result++ = eastl::move(*first++);
- /// return result;
- /// }
-
- template <typename InputIterator, typename OutputIterator>
- inline OutputIterator move(InputIterator first, InputIterator last, OutputIterator result)
- {
- return eastl::move_and_copy_unwrapper<true>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result);
- }
-
-
- /// copy
- ///
- /// Effects: Copies elements in the range [first, last) into the range [result, result + (last - first))
- /// starting from first and proceeding to last. For each nonnegative integer n < (last - first),
- /// performs *(result + n) = *(first + n).
- ///
- /// Returns: result + (last - first). That is, returns the end of the result. Note that this
- /// is different from how memmove/memcpy work, as they return the beginning of the result.
- ///
- /// Requires: result shall not be in the range [first, last). But the end of the result range
- /// may in fact be within the input rante.
- ///
- /// Complexity: Exactly 'last - first' assignments.
- ///
- template <typename InputIterator, typename OutputIterator>
- inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
- {
- const bool isMove = eastl::is_move_iterator<InputIterator>::value; EA_UNUSED(isMove);
-
- return eastl::move_and_copy_unwrapper<isMove>(eastl::unwrap_iterator(first), eastl::unwrap_iterator(last), result);
- }
-} // namespace eastl
-
-#endif // EASTL_INTERNAL_COPY_HELP_H