diff options
Diffstat (limited to 'include/EASTL/internal/copy_help.h')
-rw-r--r-- | include/EASTL/internal/copy_help.h | 221 |
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 |