diff options
Diffstat (limited to 'include/EASTL/bonus/tuple_vector.h')
-rw-r--r-- | include/EASTL/bonus/tuple_vector.h | 1598 |
1 files changed, 0 insertions, 1598 deletions
diff --git a/include/EASTL/bonus/tuple_vector.h b/include/EASTL/bonus/tuple_vector.h deleted file mode 100644 index 6ade75a..0000000 --- a/include/EASTL/bonus/tuple_vector.h +++ /dev/null @@ -1,1598 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// tuple_vector is a data container that is designed to abstract and simplify -// the handling of a "structure of arrays" layout of data in memory. In -// particular, it mimics the interface of vector, including functionality to do -// inserts, erases, push_backs, and random-access. It also provides a -// RandomAccessIterator and corresponding functionality, making it compatible -// with most STL (and STL-esque) algorithms such as ranged-for loops, find_if, -// remove_if, or sort. - -// When used or applied properly, this container can improve performance of -// some algorithms through cache-coherent data accesses or allowing for -// sensible SIMD programming, while keeping the structure of a single -// container, to permit a developer to continue to use existing algorithms in -// STL and the like. -// -// Consult doc/Bonus/tuple_vector_readme.md for more information. -/////////////////////////////////////////////////////////////////////////////// - -#ifndef EASTL_TUPLEVECTOR_H -#define EASTL_TUPLEVECTOR_H - -#include <EASTL/bonus/compressed_pair.h> -#include <EASTL/internal/config.h> -#include <EASTL/iterator.h> -#include <EASTL/memory.h> -#include <EASTL/tuple.h> -#include <EASTL/utility.h> - -#if defined(EA_PRAGMA_ONCE_SUPPORTED) - #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. -#endif - -EA_DISABLE_VC_WARNING(4244) // warning C4244: 'conversion from '___' to '___', possible loss of data -EA_DISABLE_VC_WARNING(4623) // warning C4623: default constructor was implicitly defined as deleted -EA_DISABLE_VC_WARNING(4625) // warning C4625: copy constructor was implicitly defined as deleted -EA_DISABLE_VC_WARNING(4510) // warning C4510: default constructor could not be generated - -namespace eastl -{ - /// EASTL_TUPLE_VECTOR_DEFAULT_NAME - /// - /// Defines a default container name in the absence of a user-provided name. - /// - #ifndef EASTL_TUPLE_VECTOR_DEFAULT_NAME - #define EASTL_TUPLE_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " tuple-vector" // Unless the user overrides something, this is "EASTL tuple-vector". - #endif - - - /// EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR - /// - #ifndef EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR - #define EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR allocator_type(EASTL_TUPLE_VECTOR_DEFAULT_NAME) - #endif - -namespace TupleVecInternal -{ - -// forward declarations -template <eastl_size_t I, typename... Ts> -struct tuplevec_element; - -template <eastl_size_t I, typename... Ts> -using tuplevec_element_t = typename tuplevec_element<I, Ts...>::type; - -template <typename... Ts> -struct TupleTypes {}; - -template <typename Allocator, typename Indices, typename... Ts> -class TupleVecImpl; - -template <typename... Ts> -struct TupleRecurser; - -template <eastl_size_t I, typename... Ts> -struct TupleIndexRecurser; - -template <eastl_size_t I, typename T> -struct TupleVecLeaf; - -template <typename Indices, typename... Ts> -struct TupleVecIter; - -// tuplevec_element helper to be able to isolate a type given an index -template <eastl_size_t I> -struct tuplevec_element<I> -{ - static_assert(I != I, "tuplevec_element index out of range"); -}; - -template <typename T, typename... Ts> -struct tuplevec_element<0, T, Ts...> -{ - tuplevec_element() = delete; // tuplevec_element should only be used for compile-time assistance, and never be instantiated - typedef T type; -}; - -template <eastl_size_t I, typename T, typename... Ts> -struct tuplevec_element<I, T, Ts...> -{ - typedef tuplevec_element_t<I - 1, Ts...> type; -}; - -// attempt to isolate index given a type -template <typename T, typename TupleVector> -struct tuplevec_index -{ -}; - -template <typename T> -struct tuplevec_index<T, TupleTypes<>> -{ - typedef void DuplicateTypeCheck; - tuplevec_index() = delete; // tuplevec_index should only be used for compile-time assistance, and never be instantiated - static const eastl_size_t index = 0; -}; - -template <typename T, typename... TsRest> -struct tuplevec_index<T, TupleTypes<T, TsRest...>> -{ - typedef int DuplicateTypeCheck; - static_assert(is_void<typename tuplevec_index<T, TupleTypes<TsRest...>>::DuplicateTypeCheck>::value, "duplicate type T in tuple_vector::get<T>(); unique types must be provided in declaration, or only use get<eastl_size_t>()"); - - static const eastl_size_t index = 0; -}; - -template <typename T, typename Ts, typename... TsRest> -struct tuplevec_index<T, TupleTypes<Ts, TsRest...>> -{ - typedef typename tuplevec_index<T, TupleTypes<TsRest...>>::DuplicateTypeCheck DuplicateTypeCheck; - static const eastl_size_t index = tuplevec_index<T, TupleTypes<TsRest...>>::index + 1; -}; - -template <typename Allocator, typename T, typename Indices, typename... Ts> -struct tuplevec_index<T, TupleVecImpl<Allocator, Indices, Ts...>> : public tuplevec_index<T, TupleTypes<Ts...>> -{ -}; - - -// helper to calculate the layout of the allocations for the tuple of types (esp. to take alignment into account) -template <> -struct TupleRecurser<> -{ - typedef eastl_size_t size_type; - - // This class should never be instantiated. This is just a helper for working with static functions when anonymous functions don't work - // and provide some other utilities - TupleRecurser() = delete; - - static EA_CONSTEXPR size_type GetTotalAlignment() - { - return 0; - } - - static EA_CONSTEXPR size_type GetTotalAllocationSize(size_type capacity, size_type offset) - { - EA_UNUSED(capacity); - return offset; - } - - template<typename Allocator, size_type I, typename Indices, typename... VecTypes> - static pair<void*, size_type> DoAllocate(TupleVecImpl<Allocator, Indices, VecTypes...> &vec, void** ppNewLeaf, size_type capacity, size_type offset) - { - EA_UNUSED(ppNewLeaf); - - // If n is zero, then we allocate no memory and just return NULL. - // This is fine, as our default ctor initializes with NULL pointers. - size_type alignment = TupleRecurser<VecTypes...>::GetTotalAlignment(); - void* ptr = capacity ? allocate_memory(vec.get_allocator(), offset, alignment, 0) : nullptr; - - #if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY((size_t)ptr & (alignment - 1)) != 0) - { - EASTL_FAIL_MSG("tuple_vector::DoAllocate -- memory not alignment at requested alignment"); - } - #endif - - return make_pair(ptr, offset); - } - - template<typename TupleVecImplType, size_type I> - static void SetNewData(TupleVecImplType &vec, void* pData, size_type capacity, size_type offset) - { - EA_UNUSED(vec); - EA_UNUSED(pData); - EA_UNUSED(capacity); - EA_UNUSED(offset); - } -}; - -template <typename T, typename... Ts> -struct TupleRecurser<T, Ts...> : TupleRecurser<Ts...> -{ - typedef eastl_size_t size_type; - - static EA_CONSTEXPR size_type GetTotalAlignment() - { - return max(static_cast<size_type>(alignof(T)), TupleRecurser<Ts...>::GetTotalAlignment()); - } - - static EA_CONSTEXPR size_type GetTotalAllocationSize(size_type capacity, size_type offset) - { - return TupleRecurser<Ts...>::GetTotalAllocationSize(capacity, CalculateAllocationSize(offset, capacity)); - } - - template<typename Allocator, size_type I, typename Indices, typename... VecTypes> - static pair<void*, size_type> DoAllocate(TupleVecImpl<Allocator, Indices, VecTypes...> &vec, void** ppNewLeaf, size_type capacity, size_type offset) - { - size_type allocationOffset = CalculatAllocationOffset(offset); - size_type allocationSize = CalculateAllocationSize(offset, capacity); - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<Allocator, I + 1, Indices, VecTypes...>( - vec, ppNewLeaf, capacity, allocationSize); - ppNewLeaf[I] = (void*)((uintptr_t)(allocation.first) + allocationOffset); - return allocation; - } - - template<typename TupleVecImplType, size_type I> - static void SetNewData(TupleVecImplType &vec, void* pData, size_type capacity, size_type offset) - { - size_type allocationOffset = CalculatAllocationOffset(offset); - size_type allocationSize = CalculateAllocationSize(offset, capacity); - vec.TupleVecLeaf<I, T>::mpData = (T*)((uintptr_t)pData + allocationOffset); - TupleRecurser<Ts...>::template SetNewData<TupleVecImplType, I + 1>(vec, pData, capacity, allocationSize); - } - -private: - static EA_CONSTEXPR size_type CalculateAllocationSize(size_type offset, size_type capacity) - { - return CalculatAllocationOffset(offset) + sizeof(T) * capacity; - } - - static EA_CONSTEXPR size_type CalculatAllocationOffset(size_type offset) { return (offset + alignof(T) - 1) & (~alignof(T) + 1); } -}; - -template <eastl_size_t I, typename T> -struct TupleVecLeaf -{ - typedef eastl_size_t size_type; - - void DoUninitializedMoveAndDestruct(const size_type begin, const size_type end, T* pDest) - { - T* pBegin = mpData + begin; - T* pEnd = mpData + end; - eastl::uninitialized_move_ptr_if_noexcept(pBegin, pEnd, pDest); - eastl::destruct(pBegin, pEnd); - } - - void DoInsertAndFill(size_type pos, size_type n, size_type numElements, const T& arg) - { - T* pDest = mpData + pos; - T* pDataEnd = mpData + numElements; - const T temp = arg; - const size_type nExtra = (numElements - pos); - if (n < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... - { - eastl::uninitialized_move_ptr(pDataEnd - n, pDataEnd, pDataEnd); - eastl::move_backward(pDest, pDataEnd - n, pDataEnd); // We need move_backward because of potential overlap issues. - eastl::fill(pDest, pDest + n, temp); - } - else - { - eastl::uninitialized_fill_n_ptr(pDataEnd, n - nExtra, temp); - eastl::uninitialized_move_ptr(pDest, pDataEnd, pDataEnd + n - nExtra); - eastl::fill(pDest, pDataEnd, temp); - } - } - - void DoInsertRange(T* pSrcBegin, T* pSrcEnd, T* pDestBegin, size_type numDataElements) - { - size_type pos = pDestBegin - mpData; - size_type n = pSrcEnd - pSrcBegin; - T* pDataEnd = mpData + numDataElements; - const size_type nExtra = numDataElements - pos; - if (n < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... - { - eastl::uninitialized_move_ptr(pDataEnd - n, pDataEnd, pDataEnd); - eastl::move_backward(pDestBegin, pDataEnd - n, pDataEnd); // We need move_backward because of potential overlap issues. - eastl::copy(pSrcBegin, pSrcEnd, pDestBegin); - } - else - { - eastl::uninitialized_copy(pSrcEnd - (n - nExtra), pSrcEnd, pDataEnd); - eastl::uninitialized_move_ptr(pDestBegin, pDataEnd, pDataEnd + n - nExtra); - eastl::copy(pSrcBegin, pSrcEnd - (n - nExtra), pDestBegin); - } - } - - void DoInsertValue(size_type pos, size_type numElements, T&& arg) - { - T* pDest = mpData + pos; - T* pDataEnd = mpData + numElements; - - eastl::uninitialized_move_ptr(pDataEnd - 1, pDataEnd, pDataEnd); - eastl::move_backward(pDest, pDataEnd - 1, pDataEnd); // We need move_backward because of potential overlap issues. - eastl::destruct(pDest); - ::new (pDest) T(eastl::forward<T>(arg)); - } - - T* mpData = nullptr; -}; - -// swallow allows for parameter pack expansion of arguments as means of expanding operations performed -// if a void function is used for operation expansion, it should be wrapped in (..., 0) so that the compiler -// thinks it has a parameter to pass into the function -template <typename... Ts> -void swallow(Ts&&...) { } - -inline bool variadicAnd(bool cond) { return cond; } - -inline bool variadicAnd(bool cond, bool conds...) { return cond && variadicAnd(conds); } - -// Helper struct to check for strict compatibility between two iterators, whilst still allowing for -// conversion between TupleVecImpl<Ts...>::iterator and TupleVecImpl<Ts...>::const_iterator. -template <bool IsSameSize, typename From, typename To> -struct TupleVecIterCompatibleImpl : public false_type { }; - -template<> -struct TupleVecIterCompatibleImpl<true, TupleTypes<>, TupleTypes<>> : public true_type { }; - -template <typename From, typename... FromRest, typename To, typename... ToRest> -struct TupleVecIterCompatibleImpl<true, TupleTypes<From, FromRest...>, TupleTypes<To, ToRest...>> : public integral_constant<bool, - TupleVecIterCompatibleImpl<true, TupleTypes<FromRest...>, TupleTypes<ToRest...>>::value && - is_same<typename remove_const<From>::type, typename remove_const<To>::type>::value > -{ }; - -template <typename From, typename To> -struct TupleVecIterCompatible; - -template<typename... Us, typename... Ts> -struct TupleVecIterCompatible<TupleTypes<Us...>, TupleTypes<Ts...>> : - public TupleVecIterCompatibleImpl<sizeof...(Us) == sizeof...(Ts), TupleTypes<Us...>, TupleTypes<Ts...>> -{ }; - -// The Iterator operates by storing a persistent index internally, -// and resolving the tuple of pointers to the various parts of the original tupleVec when dereferenced. -// While resolving the tuple is a non-zero operation, it consistently generated better code than the alternative of -// storing - and harmoniously updating on each modification - a full tuple of pointers to the tupleVec's data -template <eastl_size_t... Indices, typename... Ts> -struct TupleVecIter<index_sequence<Indices...>, Ts...> - : public iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> -{ -private: - typedef TupleVecIter<index_sequence<Indices...>, Ts...> this_type; - typedef eastl_size_t size_type; - - typedef iterator<EASTL_ITC_NS::random_access_iterator_tag, tuple<Ts...>, eastl_size_t, tuple<Ts*...>, tuple<Ts&...>> iter_type; - - template<typename U, typename... Us> - friend struct TupleVecIter; - - template<typename U, typename V, typename... Us> - friend class TupleVecImpl; - - template<typename U> - friend class move_iterator; -public: - typedef typename iter_type::iterator_category iterator_category; - typedef typename iter_type::value_type value_type; - typedef typename iter_type::difference_type difference_type; - typedef typename iter_type::pointer pointer; - typedef typename iter_type::reference reference; - - TupleVecIter() = default; - - template<typename VecImplType> - TupleVecIter(VecImplType* tupleVec, size_type index) - : mIndex(index) - , mpData{(void*)tupleVec->TupleVecLeaf<Indices, Ts>::mpData...} - { } - - template <typename OtherIndicesType, typename... Us, - typename = typename enable_if<TupleVecIterCompatible<TupleTypes<Us...>, TupleTypes<Ts...>>::value, bool>::type> - TupleVecIter(const TupleVecIter<OtherIndicesType, Us...>& other) - : mIndex(other.mIndex) - , mpData{other.mpData[Indices]...} - { - } - - bool operator==(const TupleVecIter& other) const { return mIndex == other.mIndex && mpData[0] == other.mpData[0]; } - bool operator!=(const TupleVecIter& other) const { return mIndex != other.mIndex || mpData[0] != other.mpData[0]; } - reference operator*() const { return MakeReference(); } - - this_type& operator++() { ++mIndex; return *this; } - this_type operator++(int) - { - this_type temp = *this; - ++mIndex; - return temp; - } - - this_type& operator--() { --mIndex; return *this; } - this_type operator--(int) - { - this_type temp = *this; - --mIndex; - return temp; - } - - this_type& operator+=(difference_type n) { mIndex += n; return *this; } - this_type operator+(difference_type n) const - { - this_type temp = *this; - return temp += n; - } - friend this_type operator+(difference_type n, const this_type& rhs) - { - this_type temp = rhs; - return temp += n; - } - - this_type& operator-=(difference_type n) { mIndex -= n; return *this; } - this_type operator-(difference_type n) const - { - this_type temp = *this; - return temp -= n; - } - friend this_type operator-(difference_type n, const this_type& rhs) - { - this_type temp = rhs; - return temp -= n; - } - - difference_type operator-(const this_type& rhs) const { return mIndex - rhs.mIndex; } - bool operator<(const this_type& rhs) const { return mIndex < rhs.mIndex; } - bool operator>(const this_type& rhs) const { return mIndex > rhs.mIndex; } - bool operator>=(const this_type& rhs) const { return mIndex >= rhs.mIndex; } - bool operator<=(const this_type& rhs) const { return mIndex <= rhs.mIndex; } - - reference operator[](const size_type n) const - { - return *(*this + n); - } - -private: - - value_type MakeValue() const - { - return value_type(((Ts*)mpData[Indices])[mIndex]...); - } - - reference MakeReference() const - { - return reference(((Ts*)mpData[Indices])[mIndex]...); - } - - pointer MakePointer() const - { - return pointer(&((Ts*)mpData[Indices])[mIndex]...); - } - - size_type mIndex = 0; - const void* mpData[sizeof...(Ts)]; -}; - -// TupleVecImpl -template <typename Allocator, eastl_size_t... Indices, typename... Ts> -class TupleVecImpl<Allocator, index_sequence<Indices...>, Ts...> : public TupleVecLeaf<Indices, Ts>... -{ - typedef Allocator allocator_type; - typedef index_sequence<Indices...> index_sequence_type; - typedef TupleVecImpl<Allocator, index_sequence_type, Ts...> this_type; - typedef TupleVecImpl<Allocator, index_sequence_type, const Ts...> const_this_type; - -public: - typedef TupleVecInternal::TupleVecIter<index_sequence_type, Ts...> iterator; - typedef TupleVecInternal::TupleVecIter<index_sequence_type, const Ts...> const_iterator; - typedef eastl::reverse_iterator<iterator> reverse_iterator; - typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator; - typedef eastl_size_t size_type; - typedef eastl::tuple<Ts...> value_tuple; - typedef eastl::tuple<Ts&...> reference_tuple; - typedef eastl::tuple<const Ts&...> const_reference_tuple; - typedef eastl::tuple<Ts*...> ptr_tuple; - typedef eastl::tuple<const Ts*...> const_ptr_tuple; - typedef eastl::tuple<Ts&&...> rvalue_tuple; - - TupleVecImpl() - : mDataSizeAndAllocator(0, EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - {} - - TupleVecImpl(const allocator_type& allocator) - : mDataSizeAndAllocator(0, allocator) - {} - - TupleVecImpl(this_type&& x) - : mDataSizeAndAllocator(0, eastl::move(x.get_allocator())) - { - swap(x); - } - - TupleVecImpl(this_type&& x, const Allocator& allocator) - : mDataSizeAndAllocator(0, allocator) - { - if (get_allocator() == x.get_allocator()) // If allocators are equivalent, then we can safely swap member-by-member - { - swap(x); - } - else - { - this_type temp(eastl::move(*this)); - temp.swap(x); - } - } - - TupleVecImpl(const this_type& x) - : mDataSizeAndAllocator(0, x.get_allocator()) - { - DoInitFromIterator(x.begin(), x.end()); - } - - template<typename OtherAllocator> - TupleVecImpl(const TupleVecImpl<OtherAllocator, index_sequence_type, Ts...>& x, const Allocator& allocator) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFromIterator(x.begin(), x.end()); - } - - template<typename MoveIterBase> - TupleVecImpl(move_iterator<MoveIterBase> begin, move_iterator<MoveIterBase> end, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFromIterator(begin, end); - } - - TupleVecImpl(const_iterator begin, const_iterator end, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator ) - { - DoInitFromIterator(begin, end); - } - - TupleVecImpl(size_type n, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator) - { - DoInitDefaultFill(n); - } - - TupleVecImpl(size_type n, const Ts&... args) - : mDataSizeAndAllocator(0, EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - { - DoInitFillArgs(n, args...); - } - - TupleVecImpl(size_type n, const Ts&... args, const allocator_type& allocator) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFillArgs(n, args...); - } - - TupleVecImpl(size_type n, const_reference_tuple tup, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFillTuple(n, tup); - } - - TupleVecImpl(const value_tuple* first, const value_tuple* last, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFromTupleArray(first, last); - } - - TupleVecImpl(std::initializer_list<value_tuple> iList, const allocator_type& allocator = EASTL_TUPLE_VECTOR_DEFAULT_ALLOCATOR) - : mDataSizeAndAllocator(0, allocator) - { - DoInitFromTupleArray(iList.begin(), iList.end()); - } - -protected: - // ctor to provide a pre-allocated field of data that the container will own, specifically for fixed_tuple_vector - TupleVecImpl(const allocator_type& allocator, void* pData, size_type capacity, size_type dataSize) - : mpData(pData), mNumCapacity(capacity), mDataSizeAndAllocator(dataSize, allocator) - { - TupleRecurser<Ts...>::template SetNewData<this_type, 0>(*this, mpData, mNumCapacity, 0); - } - -public: - ~TupleVecImpl() - { - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData, TupleVecLeaf<Indices, Ts>::mpData + mNumElements), 0)...); - if (mpData) - EASTLFree(get_allocator(), mpData, internalDataSize()); - } - - void assign(size_type n, const Ts&... args) - { - if (n > mNumCapacity) - { - this_type temp(n, args..., get_allocator()); // We have little choice but to reallocate with new memory. - swap(temp); - } - else if (n > mNumElements) // If n > mNumElements ... - { - size_type oldNumElements = mNumElements; - swallow((eastl::fill(TupleVecLeaf<Indices, Ts>::mpData, TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, args), 0)...); - swallow((eastl::uninitialized_fill_ptr(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData + n, args), 0)...); - mNumElements = n; - } - else // else 0 <= n <= mNumElements - { - swallow((eastl::fill(TupleVecLeaf<Indices, Ts>::mpData, TupleVecLeaf<Indices, Ts>::mpData + n, args), 0)...); - erase(begin() + n, end()); - } - } - - void assign(const_iterator first, const_iterator last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(!validate_iterator_pair(first, last))) - EASTL_FAIL_MSG("tuple_vector::assign -- invalid iterator pair"); -#endif - size_type newNumElements = last - first; - if (newNumElements > mNumCapacity) - { - this_type temp(first, last, get_allocator()); - swap(temp); - } - else - { - const void* ppOtherData[sizeof...(Ts)] = {first.mpData[Indices]...}; - size_type firstIdx = first.mIndex; - size_type lastIdx = last.mIndex; - if (newNumElements > mNumElements) // If n > mNumElements ... - { - size_type oldNumElements = mNumElements; - swallow((eastl::copy((Ts*)(ppOtherData[Indices]) + firstIdx, - (Ts*)(ppOtherData[Indices]) + firstIdx + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData), 0)...); - swallow((eastl::uninitialized_copy_ptr((Ts*)(ppOtherData[Indices]) + firstIdx + oldNumElements, - (Ts*)(ppOtherData[Indices]) + lastIdx, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - mNumElements = newNumElements; - } - else // else 0 <= n <= mNumElements - { - swallow((eastl::copy((Ts*)(ppOtherData[Indices]) + firstIdx, (Ts*)(ppOtherData[Indices]) + lastIdx, - TupleVecLeaf<Indices, Ts>::mpData), 0)...); - erase(begin() + newNumElements, end()); - } - } - } - - void assign(const value_tuple* first, const value_tuple* last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(first > last || first == nullptr || last == nullptr)) - EASTL_FAIL_MSG("tuple_vector::assign from tuple array -- invalid ptrs"); -#endif - size_type newNumElements = last - first; - if (newNumElements > mNumCapacity) - { - this_type temp(first, last, get_allocator()); - swap(temp); - } - else - { - if (newNumElements > mNumElements) // If n > mNumElements ... - { - size_type oldNumElements = mNumElements; - - DoCopyFromTupleArray(begin(), begin() + oldNumElements, first); - DoUninitializedCopyFromTupleArray(begin() + oldNumElements, begin() + newNumElements, first + oldNumElements); - mNumElements = newNumElements; - } - else // else 0 <= n <= mNumElements - { - DoCopyFromTupleArray(begin(), begin() + newNumElements, first); - erase(begin() + newNumElements, end()); - } - } - } - - reference_tuple push_back() - { - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + 1; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - DoGrow(oldNumElements, oldNumCapacity, newNumElements); - swallow(::new(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements) Ts()...); - return back(); - } - - void push_back(const Ts&... args) - { - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + 1; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - DoGrow(oldNumElements, oldNumCapacity, newNumElements); - swallow(::new(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements) Ts(args)...); - } - - void push_back_uninitialized() - { - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + 1; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - DoGrow(oldNumElements, oldNumCapacity, newNumElements); - } - - reference_tuple emplace_back(Ts&&... args) - { - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + 1; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - DoGrow(oldNumElements, oldNumCapacity, newNumElements); - swallow(::new(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements) Ts(eastl::forward<Ts>(args))...); - return back(); - } - - iterator emplace(const_iterator pos, Ts&&... args) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(pos) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::emplace -- invalid iterator"); -#endif - size_type firstIdx = pos - cbegin(); - size_type oldNumElements = mNumElements; - size_type newNumElements = mNumElements + 1; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - if (newNumElements > oldNumCapacity || firstIdx != oldNumElements) - { - if (newNumElements > oldNumCapacity) - { - const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); - - void* ppNewLeaf[sizeof...(Ts)]; - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<allocator_type, 0, index_sequence_type, Ts...>( - *this, ppNewLeaf, newCapacity, 0); - - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - 0, firstIdx, (Ts*)ppNewLeaf[Indices]), 0)...); - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - firstIdx, oldNumElements, (Ts*)ppNewLeaf[Indices] + firstIdx + 1), 0)...); - swallow(::new ((Ts*)ppNewLeaf[Indices] + firstIdx) Ts(eastl::forward<Ts>(args))...); - swallow(TupleVecLeaf<Indices, Ts>::mpData = (Ts*)ppNewLeaf[Indices]...); - - EASTLFree(get_allocator(), mpData, internalDataSize()); - mpData = allocation.first; - mNumCapacity = newCapacity; - internalDataSize() = allocation.second; - } - else - { - swallow((TupleVecLeaf<Indices, Ts>::DoInsertValue(firstIdx, oldNumElements, eastl::forward<Ts>(args)), 0)...); - } - } - else - { - swallow(::new (TupleVecLeaf<Indices, Ts>::mpData + oldNumElements) Ts(eastl::forward<Ts>(args))...); - } - return begin() + firstIdx; - } - - iterator insert(const_iterator pos, size_type n, const Ts&... args) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(pos) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::insert -- invalid iterator"); -#endif - size_type firstIdx = pos - cbegin(); - size_type lastIdx = firstIdx + n; - size_type oldNumElements = mNumElements; - size_type newNumElements = mNumElements + n; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - if (newNumElements > oldNumCapacity || firstIdx != oldNumElements) - { - if (newNumElements > oldNumCapacity) - { - const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); - - void* ppNewLeaf[sizeof...(Ts)]; - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<allocator_type, 0, index_sequence_type, Ts...>( - *this, ppNewLeaf, newCapacity, 0); - - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - 0, firstIdx, (Ts*)ppNewLeaf[Indices]), 0)...); - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - firstIdx, oldNumElements, (Ts*)ppNewLeaf[Indices] + lastIdx), 0)...); - swallow((eastl::uninitialized_fill_ptr((Ts*)ppNewLeaf[Indices] + firstIdx, (Ts*)ppNewLeaf[Indices] + lastIdx, args), 0)...); - swallow(TupleVecLeaf<Indices, Ts>::mpData = (Ts*)ppNewLeaf[Indices]...); - - EASTLFree(get_allocator(), mpData, internalDataSize()); - mpData = allocation.first; - mNumCapacity = newCapacity; - internalDataSize() = allocation.second; - } - else - { - swallow((TupleVecLeaf<Indices, Ts>::DoInsertAndFill(firstIdx, n, oldNumElements, args), 0)...); - } - } - else - { - swallow((eastl::uninitialized_fill_ptr(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData + newNumElements, args), 0)...); - } - return begin() + firstIdx; - } - - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(pos) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::insert -- invalid iterator"); - if (EASTL_UNLIKELY(!validate_iterator_pair(first, last))) - EASTL_FAIL_MSG("tuple_vector::insert -- invalid iterator pair"); -#endif - size_type posIdx = pos - cbegin(); - size_type firstIdx = first.mIndex; - size_type lastIdx = last.mIndex; - size_type numToInsert = last - first; - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + numToInsert; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - const void* ppOtherData[sizeof...(Ts)] = {first.mpData[Indices]...}; - if (newNumElements > oldNumCapacity || posIdx != oldNumElements) - { - if (newNumElements > oldNumCapacity) - { - const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); - - void* ppNewLeaf[sizeof...(Ts)]; - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<allocator_type, 0, index_sequence_type, Ts...>( - *this, ppNewLeaf, newCapacity, 0); - - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - 0, posIdx, (Ts*)ppNewLeaf[Indices]), 0)...); - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - posIdx, oldNumElements, (Ts*)ppNewLeaf[Indices] + posIdx + numToInsert), 0)...); - swallow((eastl::uninitialized_copy_ptr((Ts*)(ppOtherData[Indices]) + firstIdx, - (Ts*)(ppOtherData[Indices]) + lastIdx, - (Ts*)ppNewLeaf[Indices] + posIdx), 0)...); - swallow(TupleVecLeaf<Indices, Ts>::mpData = (Ts*)ppNewLeaf[Indices]...); - - EASTLFree(get_allocator(), mpData, internalDataSize()); - mpData = allocation.first; - mNumCapacity = newCapacity; - internalDataSize() = allocation.second; - } - else - { - swallow((TupleVecLeaf<Indices, Ts>::DoInsertRange( - (Ts*)(ppOtherData[Indices]) + firstIdx, (Ts*)(ppOtherData[Indices]) + lastIdx, - TupleVecLeaf<Indices, Ts>::mpData + posIdx, oldNumElements), 0)...); - } - } - else - { - swallow((eastl::uninitialized_copy_ptr((Ts*)(ppOtherData[Indices]) + firstIdx, - (Ts*)(ppOtherData[Indices]) + lastIdx, - TupleVecLeaf<Indices, Ts>::mpData + posIdx), 0)...); - } - return begin() + posIdx; - } - - iterator insert(const_iterator pos, const value_tuple* first, const value_tuple* last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(pos) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::insert -- invalid iterator"); - if (EASTL_UNLIKELY(first > last || first == nullptr || last == nullptr)) - EASTL_FAIL_MSG("tuple_vector::insert -- invalid source pointers"); -#endif - size_type posIdx = pos - cbegin(); - size_type numToInsert = last - first; - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements + numToInsert; - size_type oldNumCapacity = mNumCapacity; - mNumElements = newNumElements; - if (newNumElements > oldNumCapacity || posIdx != oldNumElements) - { - if (newNumElements > oldNumCapacity) - { - const size_type newCapacity = eastl::max(GetNewCapacity(oldNumCapacity), newNumElements); - - void* ppNewLeaf[sizeof...(Ts)]; - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<allocator_type, 0, index_sequence_type, Ts...>( - *this, ppNewLeaf, newCapacity, 0); - - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - 0, posIdx, (Ts*)ppNewLeaf[Indices]), 0)...); - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct( - posIdx, oldNumElements, (Ts*)ppNewLeaf[Indices] + posIdx + numToInsert), 0)...); - - swallow(TupleVecLeaf<Indices, Ts>::mpData = (Ts*)ppNewLeaf[Indices]...); - - // Do this after mpData is updated so that we can use new iterators - DoUninitializedCopyFromTupleArray(begin() + posIdx, begin() + posIdx + numToInsert, first); - - EASTLFree(get_allocator(), mpData, internalDataSize()); - mpData = allocation.first; - mNumCapacity = newCapacity; - internalDataSize() = allocation.second; - } - else - { - const size_type nExtra = oldNumElements - posIdx; - void* ppDataEnd[sizeof...(Ts)] = { (void*)(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements)... }; - void* ppDataBegin[sizeof...(Ts)] = { (void*)(TupleVecLeaf<Indices, Ts>::mpData + posIdx)... }; - if (numToInsert < nExtra) // If the inserted values are entirely within initialized memory (i.e. are before mpEnd)... - { - swallow((eastl::uninitialized_move_ptr((Ts*)ppDataEnd[Indices] - numToInsert, - (Ts*)ppDataEnd[Indices], (Ts*)ppDataEnd[Indices]), 0)...); - // We need move_backward because of potential overlap issues. - swallow((eastl::move_backward((Ts*)ppDataBegin[Indices], - (Ts*)ppDataEnd[Indices] - numToInsert, (Ts*)ppDataEnd[Indices]), 0)...); - - DoCopyFromTupleArray(pos, pos + numToInsert, first); - } - else - { - size_type numToInitialize = numToInsert - nExtra; - swallow((eastl::uninitialized_move_ptr((Ts*)ppDataBegin[Indices], - (Ts*)ppDataEnd[Indices], (Ts*)ppDataEnd[Indices] + numToInitialize), 0)...); - - DoCopyFromTupleArray(pos, begin() + oldNumElements, first); - DoUninitializedCopyFromTupleArray(begin() + oldNumElements, pos + numToInsert, first + nExtra); - } - } - } - else - { - DoUninitializedCopyFromTupleArray(pos, pos + numToInsert, first); - } - return begin() + posIdx; - } - - iterator erase(const_iterator first, const_iterator last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(first) == isf_none || validate_iterator(last) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::erase -- invalid iterator"); - if (EASTL_UNLIKELY(!validate_iterator_pair(first, last))) - EASTL_FAIL_MSG("tuple_vector::erase -- invalid iterator pair"); -#endif - if (first != last) - { - size_type firstIdx = first - cbegin(); - size_type lastIdx = last - cbegin(); - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements - (lastIdx - firstIdx); - mNumElements = newNumElements; - swallow((eastl::move(TupleVecLeaf<Indices, Ts>::mpData + lastIdx, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData + firstIdx), 0)...); - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData + newNumElements, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - } - return begin() + first.mIndex; - } - - iterator erase_unsorted(const_iterator pos) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(validate_iterator(pos) == isf_none)) - EASTL_FAIL_MSG("tuple_vector::erase_unsorted -- invalid iterator"); -#endif - size_type oldNumElements = mNumElements; - size_type newNumElements = oldNumElements - 1; - mNumElements = newNumElements; - swallow((eastl::move(TupleVecLeaf<Indices, Ts>::mpData + newNumElements, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData + (pos - begin())), 0)...); - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData + newNumElements, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - return begin() + pos.mIndex; - } - - void resize(size_type n) - { - size_type oldNumElements = mNumElements; - size_type oldNumCapacity = mNumCapacity; - mNumElements = n; - if (n > oldNumElements) - { - if (n > oldNumCapacity) - { - DoReallocate(oldNumElements, eastl::max<size_type>(GetNewCapacity(oldNumCapacity), n)); - } - swallow((eastl::uninitialized_default_fill_n(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, n - oldNumElements), 0)...); - } - else - { - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData + n, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - } - } - - void resize(size_type n, const Ts&... args) - { - size_type oldNumElements = mNumElements; - size_type oldNumCapacity = mNumCapacity; - mNumElements = n; - if (n > oldNumElements) - { - if (n > oldNumCapacity) - { - DoReallocate(oldNumElements, eastl::max<size_type>(GetNewCapacity(oldNumCapacity), n)); - } - swallow((eastl::uninitialized_fill_ptr(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements, - TupleVecLeaf<Indices, Ts>::mpData + n, args), 0)...); - } - else - { - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData + n, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - } - } - - void reserve(size_type n) - { - DoConditionalReallocate(mNumElements, mNumCapacity, n); - } - - void shrink_to_fit() - { - this_type temp(move_iterator<iterator>(begin()), move_iterator<iterator>(end()), get_allocator()); - swap(temp); - } - - void clear() EA_NOEXCEPT - { - size_type oldNumElements = mNumElements; - mNumElements = 0; - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData, TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - } - - void pop_back() - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(mNumElements <= 0)) - EASTL_FAIL_MSG("tuple_vector::pop_back -- container is empty"); -#endif - size_type oldNumElements = mNumElements--; - swallow((eastl::destruct(TupleVecLeaf<Indices, Ts>::mpData + oldNumElements - 1, - TupleVecLeaf<Indices, Ts>::mpData + oldNumElements), 0)...); - } - - void swap(this_type& x) - { - swallow((eastl::swap(TupleVecLeaf<Indices, Ts>::mpData, x.TupleVecLeaf<Indices, Ts>::mpData), 0)...); - eastl::swap(mpData, x.mpData); - eastl::swap(mNumElements, x.mNumElements); - eastl::swap(mNumCapacity, x.mNumCapacity); - eastl::swap(get_allocator(), x.get_allocator()); - eastl::swap(internalDataSize(), x.internalDataSize()); - } - - void assign(size_type n, const_reference_tuple tup) { assign(n, eastl::get<Indices>(tup)...); } - void assign(std::initializer_list<value_tuple> iList) { assign(iList.begin(), iList.end()); } - - void push_back(Ts&&... args) { emplace_back(eastl::forward<Ts>(args)...); } - void push_back(const_reference_tuple tup) { push_back(eastl::get<Indices>(tup)...); } - void push_back(rvalue_tuple tup) { emplace_back(eastl::forward<Ts>(eastl::get<Indices>(tup))...); } - - void emplace_back(rvalue_tuple tup) { emplace_back(eastl::forward<Ts>(eastl::get<Indices>(tup))...); } - void emplace(const_iterator pos, rvalue_tuple tup) { emplace(pos, eastl::forward<Ts>(eastl::get<Indices>(tup))...); } - - iterator insert(const_iterator pos, const Ts&... args) { return insert(pos, 1, args...); } - iterator insert(const_iterator pos, Ts&&... args) { return emplace(pos, eastl::forward<Ts>(args)...); } - iterator insert(const_iterator pos, rvalue_tuple tup) { return emplace(pos, eastl::forward<Ts>(eastl::get<Indices>(tup))...); } - iterator insert(const_iterator pos, const_reference_tuple tup) { return insert(pos, eastl::get<Indices>(tup)...); } - iterator insert(const_iterator pos, size_type n, const_reference_tuple tup) { return insert(pos, n, eastl::get<Indices>(tup)...); } - iterator insert(const_iterator pos, std::initializer_list<value_tuple> iList) { return insert(pos, iList.begin(), iList.end()); } - - iterator erase(const_iterator pos) { return erase(pos, pos + 1); } - reverse_iterator erase(const_reverse_iterator pos) { return reverse_iterator(erase((pos + 1).base(), (pos).base())); } - reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last) { return reverse_iterator(erase((last).base(), (first).base())); } - reverse_iterator erase_unsorted(const_reverse_iterator pos) { return reverse_iterator(erase_unsorted((pos + 1).base())); } - - void resize(size_type n, const_reference_tuple tup) { resize(n, eastl::get<Indices>(tup)...); } - - bool empty() const EA_NOEXCEPT { return mNumElements == 0; } - size_type size() const EA_NOEXCEPT { return mNumElements; } - size_type capacity() const EA_NOEXCEPT { return mNumCapacity; } - - iterator begin() EA_NOEXCEPT { return iterator(this, 0); } - const_iterator begin() const EA_NOEXCEPT { return const_iterator((const_this_type*)(this), 0); } - const_iterator cbegin() const EA_NOEXCEPT { return const_iterator((const_this_type*)(this), 0); } - - iterator end() EA_NOEXCEPT { return iterator(this, size()); } - const_iterator end() const EA_NOEXCEPT { return const_iterator((const_this_type*)(this), size()); } - const_iterator cend() const EA_NOEXCEPT { return const_iterator((const_this_type*)(this), size()); } - - reverse_iterator rbegin() EA_NOEXCEPT { return reverse_iterator(end()); } - const_reverse_iterator rbegin() const EA_NOEXCEPT { return const_reverse_iterator(end()); } - const_reverse_iterator crbegin() const EA_NOEXCEPT { return const_reverse_iterator(end()); } - - reverse_iterator rend() EA_NOEXCEPT { return reverse_iterator(begin()); } - const_reverse_iterator rend() const EA_NOEXCEPT { return const_reverse_iterator(begin()); } - const_reverse_iterator crend() const EA_NOEXCEPT { return const_reverse_iterator(begin()); } - - ptr_tuple data() EA_NOEXCEPT { return ptr_tuple(TupleVecLeaf<Indices, Ts>::mpData...); } - const_ptr_tuple data() const EA_NOEXCEPT { return const_ptr_tuple(TupleVecLeaf<Indices, Ts>::mpData...); } - - reference_tuple at(size_type n) - { -#if EASTL_EXCEPTIONS_ENABLED - if (EASTL_UNLIKELY(n >= mNumElements)) - throw std::out_of_range("tuple_vector::at -- out of range"); -#elif EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(n >= mNumElements)) - EASTL_FAIL_MSG("tuple_vector::at -- out of range"); -#endif - return reference_tuple(*(TupleVecLeaf<Indices, Ts>::mpData + n)...); - } - - const_reference_tuple at(size_type n) const - { -#if EASTL_EXCEPTIONS_ENABLED - if (EASTL_UNLIKELY(n >= mNumElements)) - throw std::out_of_range("tuple_vector::at -- out of range"); -#elif EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(n >= mNumElements)) - EASTL_FAIL_MSG("tuple_vector::at -- out of range"); -#endif - return const_reference_tuple(*(TupleVecLeaf<Indices, Ts>::mpData + n)...); - } - - reference_tuple operator[](size_type n) { return at(n); } - const_reference_tuple operator[](size_type n) const { return at(n); } - - reference_tuple front() - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(mNumElements == 0)) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("tuple_vector::front -- empty vector"); - #else - // We allow the user to reference an empty container. - #endif - - return at(0); - } - - const_reference_tuple front() const - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(mNumElements == 0)) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("tuple_vector::front -- empty vector"); - #else - // We allow the user to reference an empty container. - #endif - - return at(0); - } - - reference_tuple back() - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(mNumElements == 0)) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("tuple_vector::back -- empty vector"); - #else - // We allow the user to reference an empty container. - #endif - - return at(size() - 1); - } - - const_reference_tuple back() const - { - #if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED - if (EASTL_UNLIKELY(mNumElements == 0)) // We don't allow the user to reference an empty container. - EASTL_FAIL_MSG("tuple_vector::back -- empty vector"); - #else - // We allow the user to reference an empty container. - #endif - - return at(size() - 1); - } - - template <size_type I> - tuplevec_element_t<I, Ts...>* get() - { - typedef tuplevec_element_t<I, Ts...> Element; - return TupleVecLeaf<I, Element>::mpData; - } - template <size_type I> - const tuplevec_element_t<I, Ts...>* get() const - { - typedef tuplevec_element_t<I, Ts...> Element; - return TupleVecLeaf<I, Element>::mpData; - } - - template <typename T> - T* get() - { - typedef tuplevec_index<T, TupleTypes<Ts...>> Index; - return TupleVecLeaf<Index::index, T>::mpData; - } - template <typename T> - const T* get() const - { - typedef tuplevec_index<T, TupleTypes<Ts...>> Index; - return TupleVecLeaf<Index::index, T>::mpData; - } - - this_type& operator=(const this_type& other) - { - if (this != &other) - { - clear(); - assign(other.begin(), other.end()); - } - return *this; - } - - this_type& operator=(this_type&& other) - { - if (this != &other) - { - swap(other); - } - return *this; - } - - this_type& operator=(std::initializer_list<value_tuple> iList) - { - assign(iList.begin(), iList.end()); - return *this; - } - - bool validate() const EA_NOEXCEPT - { - if (mNumElements > mNumCapacity) - return false; - if (!(variadicAnd(mpData <= TupleVecLeaf<Indices, Ts>::mpData...))) - return false; - void* pDataEnd = (void*)((uintptr_t)mpData + internalDataSize()); - if (!(variadicAnd(pDataEnd >= TupleVecLeaf<Indices, Ts>::mpData...))) - return false; - return true; - } - - int validate_iterator(const_iterator iter) const EA_NOEXCEPT - { - if (!(variadicAnd(iter.mpData[Indices] == TupleVecLeaf<Indices, Ts>::mpData...))) - return isf_none; - if (iter.mIndex < mNumElements) - return (isf_valid | isf_current | isf_can_dereference); - if (iter.mIndex <= mNumElements) - return (isf_valid | isf_current); - return isf_none; - } - - static bool validate_iterator_pair(const_iterator first, const_iterator last) EA_NOEXCEPT - { - return (first.mIndex <= last.mIndex) && variadicAnd(first.mpData[Indices] == last.mpData[Indices]...); - } - - template <typename Iterator, typename = typename enable_if<is_iterator_wrapper<Iterator>::value, bool>::type> - int validate_iterator(Iterator iter) const EA_NOEXCEPT { return validate_iterator(unwrap_iterator(iter)); } - - template <typename Iterator, typename = typename enable_if<is_iterator_wrapper<Iterator>::value, bool>::type> - static bool validate_iterator_pair(Iterator first, Iterator last) EA_NOEXCEPT { return validate_iterator_pair(unwrap_iterator(first), unwrap_iterator(last)); } - - allocator_type& get_allocator() EA_NOEXCEPT { return mDataSizeAndAllocator.second(); } - const allocator_type& get_allocator() const EA_NOEXCEPT { return mDataSizeAndAllocator.second(); } - - void set_allocator(const allocator_type& alloc) { mDataSizeAndAllocator.second() = alloc; } - -protected: - - void* mpData = nullptr; - size_type mNumElements = 0; - size_type mNumCapacity = 0; - - compressed_pair<size_type, allocator_type> mDataSizeAndAllocator; - - size_type& internalDataSize() EA_NOEXCEPT { return mDataSizeAndAllocator.first(); } - size_type const& internalDataSize() const EA_NOEXCEPT { return mDataSizeAndAllocator.first(); } - - friend struct TupleRecurser<>; - template<typename... Us> - friend struct TupleRecurser; - - template <typename MoveIterBase> - void DoInitFromIterator(move_iterator<MoveIterBase> begin, move_iterator<MoveIterBase> end) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(!validate_iterator_pair(begin, end))) - EASTL_FAIL_MSG("tuple_vector::erase -- invalid iterator pair"); -#endif - size_type newNumElements = (size_type)(end - begin); - const void* ppOtherData[sizeof...(Ts)] = { begin.base().mpData[Indices]... }; - size_type beginIdx = begin.base().mIndex; - size_type endIdx = end.base().mIndex; - DoConditionalReallocate(0, mNumCapacity, newNumElements); - mNumElements = newNumElements; - swallow((eastl::uninitialized_move_ptr(eastl::move_iterator<Ts*>((Ts*)(ppOtherData[Indices]) + beginIdx), - eastl::move_iterator<Ts*>((Ts*)(ppOtherData[Indices]) + endIdx), - TupleVecLeaf<Indices, Ts>::mpData), 0)...); - } - - void DoInitFromIterator(const_iterator begin, const_iterator end) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(!validate_iterator_pair(begin, end))) - EASTL_FAIL_MSG("tuple_vector::erase -- invalid iterator pair"); -#endif - size_type newNumElements = (size_type)(end - begin); - const void* ppOtherData[sizeof...(Ts)] = { begin.mpData[Indices]... }; - size_type beginIdx = begin.mIndex; - size_type endIdx = end.mIndex; - DoConditionalReallocate(0, mNumCapacity, newNumElements); - mNumElements = newNumElements; - swallow((eastl::uninitialized_copy_ptr((Ts*)(ppOtherData[Indices]) + beginIdx, - (Ts*)(ppOtherData[Indices]) + endIdx, - TupleVecLeaf<Indices, Ts>::mpData), 0)...); - } - - void DoInitFillTuple(size_type n, const_reference_tuple tup) { DoInitFillArgs(n, eastl::get<Indices>(tup)...); } - - void DoInitFillArgs(size_type n, const Ts&... args) - { - DoConditionalReallocate(0, mNumCapacity, n); - mNumElements = n; - swallow((eastl::uninitialized_fill_ptr(TupleVecLeaf<Indices, Ts>::mpData, TupleVecLeaf<Indices, Ts>::mpData + n, args), 0)...); - } - - void DoInitDefaultFill(size_type n) - { - DoConditionalReallocate(0, mNumCapacity, n); - mNumElements = n; - swallow((eastl::uninitialized_default_fill_n(TupleVecLeaf<Indices, Ts>::mpData, n), 0)...); - } - - void DoInitFromTupleArray(const value_tuple* first, const value_tuple* last) - { -#if EASTL_ASSERT_ENABLED - if (EASTL_UNLIKELY(first > last || first == nullptr || last == nullptr)) - EASTL_FAIL_MSG("tuple_vector::ctor from tuple array -- invalid ptrs"); -#endif - size_type newNumElements = last - first; - DoConditionalReallocate(0, mNumCapacity, newNumElements); - mNumElements = newNumElements; - DoUninitializedCopyFromTupleArray(begin(), end(), first); - } - - void DoCopyFromTupleArray(iterator destPos, iterator destEnd, const value_tuple* srcTuple) - { - // assign to constructed region - while (destPos < destEnd) - { - *destPos = *srcTuple; - ++destPos; - ++srcTuple; - } - } - - void DoUninitializedCopyFromTupleArray(iterator destPos, iterator destEnd, const value_tuple* srcTuple) - { - // placement-new/copy-ctor to unconstructed regions - while (destPos < destEnd) - { - swallow(::new(eastl::get<Indices>(destPos.MakePointer())) Ts(eastl::get<Indices>(*srcTuple))...); - ++destPos; - ++srcTuple; - } - } - - // Try to grow the size of the container "naturally" given the number of elements being used - void DoGrow(size_type oldNumElements, size_type oldNumCapacity, size_type requiredCapacity) - { - if (requiredCapacity > oldNumCapacity) - DoReallocate(oldNumElements, GetNewCapacity(requiredCapacity)); - } - - // Reallocate to the newCapacity (IFF it's actually larger, though) - void DoConditionalReallocate(size_type oldNumElements, size_type oldNumCapacity, size_type requiredCapacity) - { - if (requiredCapacity > oldNumCapacity) - DoReallocate(oldNumElements, requiredCapacity); - } - - void DoReallocate(size_type oldNumElements, size_type requiredCapacity) - { - void* ppNewLeaf[sizeof...(Ts)]; - pair<void*, size_type> allocation = TupleRecurser<Ts...>::template DoAllocate<allocator_type, 0, index_sequence_type, Ts...>( - *this, ppNewLeaf, requiredCapacity, 0); - swallow((TupleVecLeaf<Indices, Ts>::DoUninitializedMoveAndDestruct(0, oldNumElements, (Ts*)ppNewLeaf[Indices]), 0)...); - swallow(TupleVecLeaf<Indices, Ts>::mpData = (Ts*)ppNewLeaf[Indices]...); - - EASTLFree(get_allocator(), mpData, internalDataSize()); - mpData = allocation.first; - mNumCapacity = requiredCapacity; - internalDataSize() = allocation.second; - } - - size_type GetNewCapacity(size_type oldNumCapacity) - { - return (oldNumCapacity > 0) ? (2 * oldNumCapacity) : 1; - } -}; - -} // namespace TupleVecInternal - -// Move_iterator specialization for TupleVecIter. -// An rvalue reference of a move_iterator would normaly be "tuple<Ts...> &&" whereas -// what we actually want is "tuple<Ts&&...>". This specialization gives us that. -template <eastl_size_t... Indices, typename... Ts> -class move_iterator<TupleVecInternal::TupleVecIter<index_sequence<Indices...>, Ts...>> -{ -public: - typedef TupleVecInternal::TupleVecIter<index_sequence<Indices...>, Ts...> iterator_type; - // a wrapping iterator type. - typedef iterator_traits<iterator_type> traits_type; - typedef typename traits_type::iterator_category iterator_category; - typedef typename traits_type::value_type value_type; - typedef typename traits_type::difference_type difference_type; - typedef typename traits_type::pointer pointer; - typedef tuple<Ts&&...> reference; - typedef move_iterator<iterator_type> this_type; - -protected: - iterator_type mIterator; - -public: - move_iterator() : mIterator() {} - explicit move_iterator(iterator_type mi) : mIterator(mi) {} - - template <typename U> - move_iterator(const move_iterator<U>& mi) : mIterator(mi.base()) {} - - iterator_type base() const { return mIterator; } - reference operator*() const { return eastl::move(MakeReference()); } - pointer operator->() const { return mIterator; } - - this_type& operator++() { ++mIterator; return *this; } - this_type operator++(int) { - this_type tempMoveIterator = *this; - ++mIterator; - return tempMoveIterator; - } - - this_type& operator--() { --mIterator; return *this; } - this_type operator--(int) - { - this_type tempMoveIterator = *this; - --mIterator; - return tempMoveIterator; - } - - this_type operator+(difference_type n) const { return move_iterator(mIterator + n); } - this_type& operator+=(difference_type n) - { - mIterator += n; - return *this; - } - - this_type operator-(difference_type n) const { return move_iterator(mIterator - n); } - this_type& operator-=(difference_type n) - { - mIterator -= n; - return *this; - } - - difference_type operator-(const this_type& rhs) const { return mIterator - rhs.mIterator; } - bool operator<(const this_type& rhs) const { return mIterator < rhs.mIterator; } - bool operator>(const this_type& rhs) const { return mIterator > rhs.mIterator; } - bool operator>=(const this_type& rhs) const { return mIterator >= rhs.mIterator; } - bool operator<=(const this_type& rhs) const { return mIterator <= rhs.mIterator; } - - reference operator[](difference_type n) const { return *(*this + n); } - -private: - reference MakeReference() const - { - return reference(eastl::move(((Ts*)mIterator.mpData[Indices])[mIterator.mIndex])...); - } - - // Unwrapping interface, not part of the public API. - iterator_type unwrap() const { return mIterator; } - - // The unwrapper helpers need access to unwrap(). - friend is_iterator_wrapper_helper<this_type, true>; - friend is_iterator_wrapper<this_type>; -}; - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator==(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return ((a.size() == b.size()) && eastl::equal(a.begin(), a.end(), b.begin())); -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator!=(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return ((a.size() != b.size()) || !eastl::equal(a.begin(), a.end(), b.begin())); -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator<(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator>(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return b < a; -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator<=(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return !(b < a); -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline bool operator>=(const TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - const TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - return !(a < b); -} - -template <typename AllocatorA, typename AllocatorB, typename Indices, typename... Ts> -inline void swap(TupleVecInternal::TupleVecImpl<AllocatorA, Indices, Ts...>& a, - TupleVecInternal::TupleVecImpl<AllocatorB, Indices, Ts...>& b) -{ - a.swap(b); -} - -// A customization of swap is made for r-values of tuples-of-references - -// normally, swapping rvalues doesn't make sense, but in this case, we do want to -// swap the contents of what the tuple-of-references are referring to -// -// This is required due to TupleVecIter returning a value-type for its dereferencing, -// as opposed to an actual real reference of some sort -template<typename... Ts> -inline -typename enable_if<conjunction<is_swappable<Ts>...>::value>::type -swap(tuple<Ts&...>&& a, tuple<Ts&...>&& b) -{ - a.swap(b); -} - -template<typename... Ts> -inline -typename enable_if<!conjunction<is_swappable<Ts>...>::value>::type -swap(tuple<Ts&...>&& a, tuple<Ts&...>&& b) = delete; - - -// External interface of tuple_vector -template <typename... Ts> -class tuple_vector : public TupleVecInternal::TupleVecImpl<EASTLAllocatorType, make_index_sequence<sizeof...(Ts)>, Ts...> -{ - typedef tuple_vector<Ts...> this_type; - typedef TupleVecInternal::TupleVecImpl<EASTLAllocatorType, make_index_sequence<sizeof...(Ts)>, Ts...> base_type; - using base_type::base_type; - -public: - this_type& operator=(std::initializer_list<typename base_type::value_tuple> iList) - { - base_type::operator=(iList); - return *this; - } -}; - -// Variant of tuple_vector that allows a user-defined allocator type (can't mix default template params with variadics) -template <typename AllocatorType, typename... Ts> -class tuple_vector_alloc - : public TupleVecInternal::TupleVecImpl<AllocatorType, make_index_sequence<sizeof...(Ts)>, Ts...> -{ - typedef tuple_vector_alloc<AllocatorType, Ts...> this_type; - typedef TupleVecInternal::TupleVecImpl<AllocatorType, make_index_sequence<sizeof...(Ts)>, Ts...> base_type; - using base_type::base_type; - -public: - - this_type& operator=(std::initializer_list<typename base_type::value_tuple> iList) - { - base_type::operator=(iList); - return *this; - } -}; - -} // namespace eastl - -EA_RESTORE_VC_WARNING() -EA_RESTORE_VC_WARNING() -EA_RESTORE_VC_WARNING() -EA_RESTORE_VC_WARNING() - -#endif // EASTL_TUPLEVECTOR_H |