This commit is contained in:
jeanlemotan
2024-07-02 18:10:39 +02:00
commit 48ab06b1d9
733 changed files with 321088 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+397
View File
@@ -0,0 +1,397 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ALLOCATOR_H
#define EASTL_ALLOCATOR_H
#include <EASTL/internal/config.h>
#include <EABase/nullptr.h>
#include <stddef.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
namespace eastl
{
/// alloc_flags
///
/// Defines allocation flags.
///
enum alloc_flags
{
MEM_TEMP = 0, // Low memory, not necessarily actually temporary.
MEM_PERM = 1 // High memory, for things that won't be unloaded.
};
/// allocator
///
/// In this allocator class, note that it is not templated on any type and
/// instead it simply allocates blocks of memory much like the C malloc and
/// free functions. It can be thought of as similar to C++ std::allocator<char>.
/// The flags parameter has meaning that is specific to the allocation
///
/// C++11's std::allocator (20.6.9) doesn't have a move constructor or assignment
/// operator. This is possibly because std::allocators are associated with types
/// instead of as instances. The potential non-equivalance of C++ std::allocator
/// instances has been a source of some acknowledged design problems.
/// We don't implement support for move construction or assignment in eastl::allocator,
/// but users can define their own allocators which do have move functions and
/// the eastl containers are compatible with such allocators (i.e. nothing unexpected
/// will happen).
///
class EASTL_API allocator
{
public:
EASTL_ALLOCATOR_EXPLICIT allocator(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME));
allocator(const allocator& x);
allocator(const allocator& x, const char* pName);
allocator& operator=(const allocator& x);
void* allocate(size_t n, int flags = 0);
void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0);
void deallocate(void* p, size_t n);
const char* get_name() const;
void set_name(const char* pName);
protected:
#if EASTL_NAME_ENABLED
const char* mpName; // Debug name, used to track memory.
#endif
};
bool operator==(const allocator& a, const allocator& b);
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
bool operator!=(const allocator& a, const allocator& b);
#endif
/// dummy_allocator
///
/// Defines an allocator which does nothing. It returns NULL from allocate calls.
///
class EASTL_API dummy_allocator
{
public:
EASTL_ALLOCATOR_EXPLICIT dummy_allocator(const char* = NULL) { }
dummy_allocator(const dummy_allocator&) { }
dummy_allocator(const dummy_allocator&, const char*) { }
dummy_allocator& operator=(const dummy_allocator&) { return *this; }
void* allocate(size_t, int = 0) { return NULL; }
void* allocate(size_t, size_t, size_t, int = 0) { return NULL; }
void deallocate(void*, size_t) { }
const char* get_name() const { return ""; }
void set_name(const char*) { }
};
inline bool operator==(const dummy_allocator&, const dummy_allocator&) { return true; }
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const dummy_allocator&, const dummy_allocator&) { return false; }
#endif
/// Defines a static default allocator which is constant across all types.
/// This is different from get_default_allocator, which is is bound at
/// compile-time and expected to differ per allocator type.
/// Currently this Default Allocator applies only to CoreAllocatorAdapter.
/// To consider: This naming of this function is too similar to get_default_allocator
/// and instead should be named something like GetStaticDefaultAllocator.
EASTL_API allocator* GetDefaultAllocator();
EASTL_API allocator* SetDefaultAllocator(allocator* pAllocator);
/// get_default_allocator
///
/// This templated function allows the user to implement a default allocator
/// retrieval function that any part of EASTL can use. EASTL containers take
/// an Allocator parameter which identifies an Allocator class to use. But
/// different kinds of allocators have different mechanisms for retrieving
/// a default allocator instance, and some don't even intrinsically support
/// such functionality. The user can override this get_default_allocator
/// function in order to provide the glue between EASTL and whatever their
/// system's default allocator happens to be.
///
/// Example usage:
/// MyAllocatorType* gpSystemAllocator;
///
/// MyAllocatorType* get_default_allocator(const MyAllocatorType*)
/// { return gpSystemAllocator; }
///
template <typename Allocator>
Allocator* get_default_allocator(const Allocator*);
EASTLAllocatorType* get_default_allocator(const EASTLAllocatorType*);
/// default_allocfreemethod
///
/// Implements a default allocfreemethod which uses the default global allocator.
/// This version supports only default alignment.
///
void* default_allocfreemethod(size_t n, void* pBuffer, void* /*pContext*/);
/// allocate_memory
///
/// This is a memory allocation dispatching function.
/// To do: Make aligned and unaligned specializations.
/// Note that to do this we will need to use a class with a static
/// function instead of a standalone function like below.
///
template <typename Allocator>
void* allocate_memory(Allocator& a, size_t n, size_t alignment, size_t alignmentOffset);
} // namespace eastl
#ifndef EASTL_USER_DEFINED_ALLOCATOR // If the user hasn't declared that he has defined a different allocator implementation elsewhere...
EA_DISABLE_ALL_VC_WARNINGS()
#include <new>
EA_RESTORE_ALL_VC_WARNINGS()
#if !EASTL_DLL // If building a regular library and not building EASTL as a DLL...
// It is expected that the application define the following
// versions of operator new for the application. Either that or the
// user needs to override the implementation of the allocator class.
void* operator new[](size_t size, const char* pName, int flags, unsigned debugFlags, const char* file, int line);
void* operator new[](size_t size, size_t alignment, size_t alignmentOffset, const char* pName, int flags, unsigned debugFlags, const char* file, int line);
#endif
namespace eastl
{
inline allocator::allocator(const char* EASTL_NAME(pName))
{
#if EASTL_NAME_ENABLED
mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
inline allocator::allocator(const allocator& EASTL_NAME(alloc))
{
#if EASTL_NAME_ENABLED
mpName = alloc.mpName;
#endif
}
inline allocator::allocator(const allocator&, const char* EASTL_NAME(pName))
{
#if EASTL_NAME_ENABLED
mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
inline allocator& allocator::operator=(const allocator& EASTL_NAME(alloc))
{
#if EASTL_NAME_ENABLED
mpName = alloc.mpName;
#endif
return *this;
}
inline const char* allocator::get_name() const
{
#if EASTL_NAME_ENABLED
return mpName;
#else
return EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
inline void allocator::set_name(const char* EASTL_NAME(pName))
{
#if EASTL_NAME_ENABLED
mpName = pName;
#endif
}
inline void* allocator::allocate(size_t n, int flags)
{
#if EASTL_NAME_ENABLED
#define pName mpName
#else
#define pName EASTL_ALLOCATOR_DEFAULT_NAME
#endif
#if EASTL_DLL
return allocate(n, EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT, 0, flags);
#elif (EASTL_DEBUGPARAMS_LEVEL <= 0)
return ::new((char*)0, flags, 0, (char*)0, 0) char[n];
#elif (EASTL_DEBUGPARAMS_LEVEL == 1)
return ::new( pName, flags, 0, (char*)0, 0) char[n];
#else
return ::new( pName, flags, 0, __FILE__, __LINE__) char[n];
#endif
}
inline void* allocator::allocate(size_t n, size_t alignment, size_t offset, int flags)
{
#if EASTL_DLL
// We currently have no support for implementing flags when
// using the C runtime library operator new function. The user
// can use SetDefaultAllocator to override the default allocator.
EA_UNUSED(offset); EA_UNUSED(flags);
size_t adjustedAlignment = (alignment > EA_PLATFORM_PTR_SIZE) ? alignment : EA_PLATFORM_PTR_SIZE;
void* p = new char[n + adjustedAlignment + EA_PLATFORM_PTR_SIZE];
void* pPlusPointerSize = (void*)((uintptr_t)p + EA_PLATFORM_PTR_SIZE);
void* pAligned = (void*)(((uintptr_t)pPlusPointerSize + adjustedAlignment - 1) & ~(adjustedAlignment - 1));
void** pStoredPtr = (void**)pAligned - 1;
EASTL_ASSERT(pStoredPtr >= p);
*(pStoredPtr) = p;
EASTL_ASSERT(((size_t)pAligned & ~(alignment - 1)) == (size_t)pAligned);
return pAligned;
#elif (EASTL_DEBUGPARAMS_LEVEL <= 0)
return ::new(alignment, offset, (char*)0, flags, 0, (char*)0, 0) char[n];
#elif (EASTL_DEBUGPARAMS_LEVEL == 1)
return ::new(alignment, offset, pName, flags, 0, (char*)0, 0) char[n];
#else
return ::new(alignment, offset, pName, flags, 0, __FILE__, __LINE__) char[n];
#endif
#undef pName // See above for the definition of this.
}
inline void allocator::deallocate(void* p, size_t)
{
#if EASTL_DLL
if (p != nullptr)
{
void* pOriginalAllocation = *((void**)p - 1);
delete[](char*)pOriginalAllocation;
}
#else
delete[](char*)p;
#endif
}
inline bool operator==(const allocator&, const allocator&)
{
return true; // All allocators are considered equal, as they merely use global new/delete.
}
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
inline bool operator!=(const allocator&, const allocator&)
{
return false; // All allocators are considered equal, as they merely use global new/delete.
}
#endif
} // namespace eastl
#endif // EASTL_USER_DEFINED_ALLOCATOR
namespace eastl
{
template <typename Allocator>
inline Allocator* get_default_allocator(const Allocator*)
{
return NULL; // By default we return NULL; the user must make specialization of this function in order to provide their own implementation.
}
inline EASTLAllocatorType* get_default_allocator(const EASTLAllocatorType*)
{
return EASTLAllocatorDefault(); // For the built-in allocator EASTLAllocatorType, we happen to already have a function for returning the default allocator instance, so we provide it.
}
inline void* default_allocfreemethod(size_t n, void* pBuffer, void* /*pContext*/)
{
EASTLAllocatorType* const pAllocator = EASTLAllocatorDefault();
if(pBuffer) // If freeing...
{
EASTLFree(*pAllocator, pBuffer, n);
return NULL; // The return value is meaningless for the free.
}
else // allocating
return EASTLAlloc(*pAllocator, n);
}
/// allocate_memory
///
/// This is a memory allocation dispatching function.
/// To do: Make aligned and unaligned specializations.
/// Note that to do this we will need to use a class with a static
/// function instead of a standalone function like below.
///
template <typename Allocator>
inline void* allocate_memory(Allocator& a, size_t n, size_t alignment, size_t alignmentOffset)
{
void *result;
if (alignment <= EASTL_ALLOCATOR_MIN_ALIGNMENT)
{
result = EASTLAlloc(a, n);
// Ensure the result is correctly aligned. An assertion likely indicates a mismatch between EASTL_ALLOCATOR_MIN_ALIGNMENT and the minimum alignment
// of EASTLAlloc. If there is a mismatch it may be necessary to define EASTL_ALLOCATOR_MIN_ALIGNMENT to be the minimum alignment of EASTLAlloc, or
// to increase the alignment of EASTLAlloc to match EASTL_ALLOCATOR_MIN_ALIGNMENT.
EASTL_ASSERT((reinterpret_cast<size_t>(result)& ~(alignment - 1)) == reinterpret_cast<size_t>(result));
}
else
{
result = EASTLAllocAligned(a, n, alignment, alignmentOffset);
// Ensure the result is correctly aligned. An assertion here may indicate a bug in the allocator.
auto resultMinusOffset = (char*)result - alignmentOffset;
EA_UNUSED(resultMinusOffset);
EASTL_ASSERT((reinterpret_cast<size_t>(resultMinusOffset)& ~(alignment - 1)) == reinterpret_cast<size_t>(resultMinusOffset));
}
return result;
}
}
#endif // Header include guard
+130
View File
@@ -0,0 +1,130 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ALLOCATOR_MALLOC_H
#define EASTL_ALLOCATOR_MALLOC_H
#include <EABase/eahave.h>
#include <EASTL/allocator.h>
#include <stddef.h>
// EASTL_ALIGNED_MALLOC_AVAILABLE
//
// Identifies if the standard library provides a built-in aligned version of malloc.
// Defined as 0 or 1, depending on the standard library or platform availability.
// None of the viable C functions provides for an aligned malloc with offset, so we
// don't consider that supported in any case.
//
// Options for aligned allocations:
// C11 aligned_alloc http://linux.die.net/man/3/aligned_alloc
// glibc memalign http://linux.die.net/man/3/posix_memalign
// Posix posix_memalign http://pubs.opengroup.org/onlinepubs/000095399/functions/posix_memalign.html
// VC++ _aligned_malloc http://msdn.microsoft.com/en-us/library/8z34s9c6%28VS.80%29.aspx This is not suitable, since it has a limitation that you need to free via _aligned_free.
//
#if !defined EASTL_ALIGNED_MALLOC_AVAILABLE
#if defined(EA_PLATFORM_POSIX) && !defined(EA_PLATFORM_APPLE)
// memalign is more consistently available than posix_memalign, though its location isn't consistent across
// platforms and compiler libraries. Typically it's declared in one of three headers: stdlib.h, malloc.h, or malloc/malloc.h
#include <stdlib.h> // memalign, posix_memalign.
#define EASTL_ALIGNED_MALLOC_AVAILABLE 1
#if EA_HAS_INCLUDE_AVAILABLE
#if EA_HAS_INCLUDE(<malloc/malloc.h>)
#include <malloc/malloc.h>
#elif EA_HAS_INCLUDE(<malloc.h>)
#include <malloc.h>
#endif
#elif defined(EA_PLATFORM_BSD)
#include <malloc/malloc.h>
#elif defined(__clang__)
#if __has_include(<malloc/malloc.h>)
#include <malloc/malloc.h>
#elif __has_include(<malloc.h>)
#include <malloc.h>
#endif
#else
#include <malloc.h>
#endif
#else
#define EASTL_ALIGNED_MALLOC_AVAILABLE 0
#endif
#endif
namespace eastl
{
///////////////////////////////////////////////////////////////////////////////
// allocator_malloc
//
// Implements an EASTL allocator that uses malloc/free as opposed to
// new/delete or PPMalloc Malloc/Free.
//
// Example usage:
// vector<int, allocator_malloc> intVector;
//
class allocator_malloc
{
public:
allocator_malloc(const char* = NULL)
{ }
allocator_malloc(const allocator_malloc&)
{ }
allocator_malloc(const allocator_malloc&, const char*)
{ }
allocator_malloc& operator=(const allocator_malloc&)
{ return *this; }
bool operator==(const allocator_malloc&)
{ return true; }
bool operator!=(const allocator_malloc&)
{ return false; }
void* allocate(size_t n, int /*flags*/ = 0)
{ return malloc(n); }
void* allocate(size_t n, size_t alignment, size_t alignmentOffset, int /*flags*/ = 0)
{
#if EASTL_ALIGNED_MALLOC_AVAILABLE
if((alignmentOffset % alignment) == 0) // We check for (offset % alignmnent == 0) instead of (offset == 0) because any block which is aligned on e.g. 64 also is aligned at an offset of 64 by definition.
return memalign(alignment, n); // memalign is more consistently available than posix_memalign.
#else
if((alignment <= EASTL_SYSTEM_ALLOCATOR_MIN_ALIGNMENT) && ((alignmentOffset % alignment) == 0))
return malloc(n);
#endif
return NULL;
}
void deallocate(void* p, size_t /*n*/)
{ free(p); }
const char* get_name() const
{ return "allocator_malloc"; }
void set_name(const char*)
{ }
};
} // namespace eastl
#endif // Header include guard
+652
View File
@@ -0,0 +1,652 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements the eastl::any which is part of the C++ standard STL
// library specification.
//
// eastl::any is a type-safe container for single values of any type. Our
// implementation makes use of the "small local buffer" optimization to avoid
// unnecessary dynamic memory allocation if the specified type is eligible to
// be stored in its local buffer. The user type must satisfy the size
// requirements and must be no-throw move-constructible to qualify for the local
// buffer optimization.
//
// To consider: Implement a fixed_any<SIZE> variant to allow users to customize
// the size of the "small local buffer" optimization.
//
// http://en.cppreference.com/w/cpp/utility/any
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ANY_H
#define EASTL_ANY_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
#include <EASTL/internal/config.h>
#include <EASTL/internal/in_place_t.h>
#if EASTL_RTTI_ENABLED
#include <typeinfo>
#endif
#if EASTL_EXCEPTIONS_ENABLED
#include <exception>
#endif
namespace eastl
{
///////////////////////////////////////////////////////////////////////////////
// bad_any_cast
//
// The type thrown by any_cast on failure.
//
// http://en.cppreference.com/w/cpp/utility/any/bad_any_cast
//
#if EASTL_EXCEPTIONS_ENABLED
struct bad_cast : std::exception
{
const char* what() const EA_NOEXCEPT EA_OVERRIDE
{ return "bad cast"; }
};
struct bad_any_cast : public bad_cast
{
const char* what() const EA_NOEXCEPT EA_OVERRIDE
{ return "bad_any_cast"; }
};
#endif
namespace Internal
{
// utility to switch between exceptions and asserts
inline void DoBadAnyCast()
{
#if EASTL_EXCEPTIONS_ENABLED
throw bad_any_cast();
#else
EASTL_ASSERT_MSG(false, "bad_any_cast\n");
// NOTE(rparolin): CRASH!
// You crashed here because you requested a type that was not contained in the object.
// We choose to intentionally crash here instead of returning invalid data to the calling
// code which could cause hard to track down bugs.
*((volatile int*)0) = 0xDEADC0DE;
#endif
}
template<typename T, typename... Args>
void* DefaultConstruct(Args&&... args)
{
auto* pMem = EASTLAllocatorDefault()->allocate(sizeof(T), alignof(T), 0);
return ::new(pMem) T(eastl::forward<Args>(args)...);
}
template<typename T>
void DefaultDestroy(T* p)
{
p->~T();
EASTLAllocatorDefault()->deallocate(static_cast<void*>(p), sizeof(T));
}
}
///////////////////////////////////////////////////////////////////////////////
// 20.7.3, class any
//
class any
{
//////////////////////////////////////////////////////////////////////////////////////////
// storage_operation
//
// operations supported by the storage handler
//
enum class storage_operation
{
GET,
DESTROY,
COPY,
MOVE,
TYPE_INFO
};
//////////////////////////////////////////////////////////////////////////////////////////
// storage
//
// the underlying storage type which enables the switching between objects stored in
// the heap and objects stored within the any type.
//
union storage
{
typedef aligned_storage_t<4 * sizeof(void*), alignment_of<void*>::value> internal_storage_t;
void* external_storage = nullptr;
internal_storage_t internal_storage;
};
//////////////////////////////////////////////////////////////////////////////////////////
// use_internal_storage
//
// determines when the "local buffer optimization" is used
//
template <typename T>
using use_internal_storage = bool_constant
<
is_nothrow_move_constructible<T>::value
&& (sizeof(T) <= sizeof(storage)) &&
(alignment_of<storage>::value % alignment_of<T>::value == 0)
>;
//////////////////////////////////////////////////////////////////////////////////////////
// non-member friend functions
//
template <class ValueType> friend const ValueType* any_cast(const any* pAny) EA_NOEXCEPT;
template <class ValueType> friend ValueType* any_cast(any* pAny) EA_NOEXCEPT;
template <class ValueType> friend ValueType any_cast(const any& operand);
template <class ValueType> friend ValueType any_cast(any& operand);
template <class ValueType> friend ValueType any_cast(any&& operand);
//Adding Unsafe any cast operations
template <class ValueType> friend const ValueType* unsafe_any_cast(const any* pAny) EA_NOEXCEPT;
template <class ValueType> friend ValueType* unsafe_any_cast(any* pAny) EA_NOEXCEPT;
//////////////////////////////////////////////////////////////////////////////////////////
// internal storage handler
//
template <typename T>
struct storage_handler_internal
{
template <typename V>
static void construct(storage& s, V&& v)
{
::new(&s.internal_storage) T(eastl::forward<V>(v));
}
template <typename... Args>
static void construct_inplace(storage& s, Args... args)
{
::new(&s.internal_storage) T(eastl::forward<Args>(args)...);
}
template <class NT, class U, class... Args>
static void construct_inplace(storage& s, std::initializer_list<U> il, Args&&... args)
{
::new(&s.internal_storage) NT(il, eastl::forward<Args>(args)...);
}
static inline void destroy(any& refAny)
{
T& t = *static_cast<T*>(static_cast<void*>(&refAny.m_storage.internal_storage));
EA_UNUSED(t);
t.~T();
refAny.m_handler = nullptr;
}
static void* handler_func(storage_operation op, const any* pThis, any* pOther)
{
switch (op)
{
case storage_operation::GET:
{
EASTL_ASSERT(pThis);
return (void*)(&pThis->m_storage.internal_storage);
}
break;
case storage_operation::DESTROY:
{
EASTL_ASSERT(pThis);
destroy(const_cast<any&>(*pThis));
}
break;
case storage_operation::COPY:
{
EASTL_ASSERT(pThis);
EASTL_ASSERT(pOther);
construct(pOther->m_storage, *(T*)(&pThis->m_storage.internal_storage));
}
break;
case storage_operation::MOVE:
{
EASTL_ASSERT(pThis);
EASTL_ASSERT(pOther);
construct(pOther->m_storage, eastl::move(*(T*)(&pThis->m_storage.internal_storage)));
destroy(const_cast<any&>(*pThis));
}
break;
case storage_operation::TYPE_INFO:
{
#if EASTL_RTTI_ENABLED
return (void*)&typeid(T);
#endif
}
break;
default:
{
EASTL_ASSERT_MSG(false, "unknown storage operation\n");
}
break;
};
return nullptr;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// external storage handler
//
template <typename T>
struct storage_handler_external
{
template <typename V>
static inline void construct(storage& s, V&& v)
{
s.external_storage = Internal::DefaultConstruct<T>(eastl::forward<V>(v));
}
template <typename... Args>
static inline void construct_inplace(storage& s, Args... args)
{
s.external_storage = Internal::DefaultConstruct<T>(eastl::forward<Args>(args)...);
}
template <class NT, class U, class... Args>
static inline void construct_inplace(storage& s, std::initializer_list<U> il, Args&&... args)
{
s.external_storage = Internal::DefaultConstruct<NT>(il, eastl::forward<Args>(args)...);
}
static inline void destroy(any& refAny)
{
Internal::DefaultDestroy(static_cast<T*>(refAny.m_storage.external_storage));
refAny.m_handler = nullptr;
}
static void* handler_func(storage_operation op, const any* pThis, any* pOther)
{
switch (op)
{
case storage_operation::GET:
{
EASTL_ASSERT(pThis);
EASTL_ASSERT(pThis->m_storage.external_storage);
return static_cast<void*>(pThis->m_storage.external_storage);
}
break;
case storage_operation::DESTROY:
{
EASTL_ASSERT(pThis);
destroy(*const_cast<any*>(pThis));
}
break;
case storage_operation::COPY:
{
EASTL_ASSERT(pThis);
EASTL_ASSERT(pOther);
construct(pOther->m_storage, *static_cast<T*>(pThis->m_storage.external_storage));
}
break;
case storage_operation::MOVE:
{
EASTL_ASSERT(pThis);
EASTL_ASSERT(pOther);
construct(pOther->m_storage, eastl::move(*(T*)(pThis->m_storage.external_storage)));
destroy(const_cast<any&>(*pThis));
}
break;
case storage_operation::TYPE_INFO:
{
#if EASTL_RTTI_ENABLED
return (void*)&typeid(T);
#endif
}
break;
default:
{
EASTL_ASSERT_MSG(false, "unknown storage operation\n");
}
break;
};
return nullptr;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
// storage_handler_ptr
//
// defines the function signature of the storage handler that both the internal and
// external storage handlers must implement to retrieve the underlying type of the any
// object.
//
using storage_handler_ptr = void* (*)(storage_operation, const any*, any*);
//////////////////////////////////////////////////////////////////////////////////////////
// storage_handler
//
// based on the specified type T we select the appropriate underlying storage handler
// based on the 'use_internal_storage' trait.
//
template <typename T>
using storage_handler = typename conditional<use_internal_storage<T>::value,
storage_handler_internal<T>,
storage_handler_external<T>>::type;
//////////////////////////////////////////////////////////////////////////////////////////
// data layout
//
storage m_storage;
storage_handler_ptr m_handler;
public:
#ifndef EA_COMPILER_GNUC
// TODO(rparolin): renable constexpr for GCC
EA_CONSTEXPR
#endif
any() EA_NOEXCEPT
: m_storage(), m_handler(nullptr) {}
any(const any& other) : m_handler(nullptr)
{
if (other.m_handler)
{
// NOTE(rparolin): You can not simply copy the underlying
// storage because it could hold a pointer to an object on the
// heap which breaks the copy semantics of the language.
other.m_handler(storage_operation::COPY, &other, this);
m_handler = other.m_handler;
}
}
any(any&& other) EA_NOEXCEPT : m_handler(nullptr)
{
if(other.m_handler)
{
// NOTE(rparolin): You can not simply move the underlying
// storage because because the storage class has effectively
// type erased user type so we have to defer to the handler
// function to get the type back and pass on the move request.
m_handler = eastl::move(other.m_handler);
other.m_handler(storage_operation::MOVE, &other, this);
}
}
~any() { reset(); }
template <class ValueType>
any(ValueType&& value,
typename eastl::enable_if<!eastl::is_same<typename eastl::decay<ValueType>::type, any>::value>::type* = 0)
{
typedef decay_t<ValueType> DecayedValueType;
static_assert(is_copy_constructible<DecayedValueType>::value, "ValueType must be copy-constructible");
storage_handler<DecayedValueType>::construct(m_storage, eastl::forward<ValueType>(value));
m_handler = &storage_handler<DecayedValueType>::handler_func;
}
template <class T, class... Args>
explicit any(in_place_type_t<T>, Args&&... args)
{
typedef storage_handler<decay_t<T>> StorageHandlerT;
static_assert(eastl::is_constructible<T, Args...>::value, "T must be constructible with Args...");
StorageHandlerT::construct_inplace(m_storage, eastl::forward<Args>(args)...);
m_handler = &StorageHandlerT::handler_func;
}
template <class T, class U, class... Args>
explicit any(in_place_type_t<T>,
std::initializer_list<U> il,
Args&&... args,
typename eastl::enable_if<eastl::is_constructible<T, std::initializer_list<U>&, Args...>::value,
void>::type* = 0)
{
typedef storage_handler<decay_t<T>> StorageHandlerT;
StorageHandlerT::construct_inplace(m_storage, il, eastl::forward<Args>(args)...);
m_handler = &StorageHandlerT::handler_func;
}
// 20.7.3.2, assignments
template <class ValueType>
any& operator=(ValueType&& value)
{
static_assert(is_copy_constructible<decay_t<ValueType>>::value, "ValueType must be copy-constructible");
any(eastl::forward<ValueType>(value)).swap(*this);
return *this;
}
any& operator=(const any& other)
{
any(other).swap(*this);
return *this;
}
any& operator=(any&& other) EA_NOEXCEPT
{
any(eastl::move(other)).swap(*this);
return *this;
}
// 20.7.3.3, modifiers
#if EASTL_VARIADIC_TEMPLATES_ENABLED
template <class T, class... Args>
void emplace(Args&&... args)
{
typedef storage_handler<decay_t<T>> StorageHandlerT;
static_assert(eastl::is_constructible<T, Args...>::value, "T must be constructible with Args...");
reset();
StorageHandlerT::construct_inplace(m_storage, eastl::forward<Args>(args)...);
m_handler = &StorageHandlerT::handler_func;
}
template <class NT, class U, class... Args>
typename eastl::enable_if<eastl::is_constructible<NT, std::initializer_list<U>&, Args...>::value, void>::type
emplace(std::initializer_list<U> il, Args&&... args)
{
typedef storage_handler<decay_t<NT>> StorageHandlerT;
reset();
StorageHandlerT::construct_inplace(m_storage, il, eastl::forward<Args>(args)...);
m_handler = &StorageHandlerT::handler_func;
}
#endif
void reset() EA_NOEXCEPT
{
if(m_handler)
m_handler(storage_operation::DESTROY, this, nullptr);
}
void swap(any& other) EA_NOEXCEPT
{
if(this == &other)
return;
if(m_handler && other.m_handler)
{
any tmp;
tmp.m_handler = other.m_handler;
other.m_handler(storage_operation::MOVE, &other, &tmp);
other.m_handler = m_handler;
m_handler(storage_operation::MOVE, this, &other);
m_handler = tmp.m_handler;
tmp.m_handler(storage_operation::MOVE, &tmp, this);
}
else if (m_handler == nullptr && other.m_handler)
{
eastl::swap(m_handler, other.m_handler);
m_handler(storage_operation::MOVE, &other, this);
}
else if(m_handler && other.m_handler == nullptr)
{
eastl::swap(m_handler, other.m_handler);
other.m_handler(storage_operation::MOVE, this, &other);
}
//else if (m_handler == nullptr && other.m_handler == nullptr)
//{
// // nothing to swap
//}
}
// 20.7.3.4, observers
bool has_value() const EA_NOEXCEPT { return m_handler != nullptr; }
#if EASTL_RTTI_ENABLED
inline const std::type_info& type() const EA_NOEXCEPT
{
if(m_handler)
{
auto* pTypeInfo = m_handler(storage_operation::TYPE_INFO, this, nullptr);
return *static_cast<const std::type_info*>(pTypeInfo);
}
else
{
return typeid(void);
}
}
#endif
};
//////////////////////////////////////////////////////////////////////////////////////////
// 20.7.4, non-member functions
//
inline void swap(any& rhs, any& lhs) EA_NOEXCEPT { rhs.swap(lhs); }
//////////////////////////////////////////////////////////////////////////////////////////
// 20.7.4, The non-member any_cast functions provide type-safe access to the contained object.
//
template <class ValueType>
inline ValueType any_cast(const any& operand)
{
static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
"ValueType must be a reference or copy constructible");
auto* p = any_cast<typename add_const<typename remove_reference<ValueType>::type>::type>(&operand);
if(p == nullptr)
Internal::DoBadAnyCast();
return *p;
}
template <class ValueType>
inline ValueType any_cast(any& operand)
{
static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
"ValueType must be a reference or copy constructible");
auto* p = any_cast<typename remove_reference<ValueType>::type>(&operand);
if(p == nullptr)
Internal::DoBadAnyCast();
return *p;
}
template <class ValueType>
inline ValueType any_cast(any&& operand)
{
static_assert(eastl::is_reference<ValueType>::value || eastl::is_copy_constructible<ValueType>::value,
"ValueType must be a reference or copy constructible");
auto* p = any_cast<typename remove_reference<ValueType>::type>(&operand);
if (p == nullptr)
Internal::DoBadAnyCast();
return *p;
}
// NOTE(rparolin): The runtime type check was commented out because in DLL builds the templated function pointer
// value will be different -- completely breaking the validation mechanism. Due to the fact that eastl::any uses
// type erasure we can't refresh (on copy/move) the cached function pointer to the internal handler function because
// we don't statically know the type.
template <class ValueType>
inline const ValueType* any_cast(const any* pAny) EA_NOEXCEPT
{
return (pAny && pAny->m_handler EASTL_IF_NOT_DLL(== &any::storage_handler<decay_t<ValueType>>::handler_func)
#if EASTL_RTTI_ENABLED
&& pAny->type() == typeid(typename remove_reference<ValueType>::type)
#endif
) ?
static_cast<const ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr)) :
nullptr;
}
template <class ValueType>
inline ValueType* any_cast(any* pAny) EA_NOEXCEPT
{
return (pAny && pAny->m_handler EASTL_IF_NOT_DLL(== &any::storage_handler<decay_t<ValueType>>::handler_func)
#if EASTL_RTTI_ENABLED
&& pAny->type() == typeid(typename remove_reference<ValueType>::type)
#endif
) ?
static_cast<ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr)) :
nullptr;
}
//Unsafe operations - use with caution
template <class ValueType>
inline const ValueType* unsafe_any_cast(const any* pAny) EA_NOEXCEPT
{
return unsafe_any_cast<ValueType>(const_cast<any*>(pAny));
}
template <class ValueType>
inline ValueType* unsafe_any_cast(any* pAny) EA_NOEXCEPT
{
return static_cast<ValueType*>(pAny->m_handler(any::storage_operation::GET, pAny, nullptr));
}
//////////////////////////////////////////////////////////////////////////////////////////
// make_any
//
#if EASTL_VARIADIC_TEMPLATES_ENABLED
template <class T, class... Args>
inline any make_any(Args&&... args)
{
return any(eastl::in_place<T>, eastl::forward<Args>(args)...);
}
template <class T, class U, class... Args>
inline any make_any(std::initializer_list<U> il, Args&&... args)
{
return any(eastl::in_place<T>, il, eastl::forward<Args>(args)...);
}
#endif
} // namespace eastl
#endif // EASTL_ANY_H
+589
View File
@@ -0,0 +1,589 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Implements a templated array class as per the C++ standard TR1 (technical
// report 1, which is a list of proposed C++ library amendments).
// The primary distinctions between this array and TR1 array are:
// - array::size_type is defined as eastl_size_t instead of size_t in order
// to save memory and run faster on 64 bit systems.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ARRAY_H
#define EASTL_ARRAY_H
#include <EASTL/internal/config.h>
#include <EASTL/iterator.h>
#include <EASTL/algorithm.h>
#include <EASTL/utility.h>
#include <stddef.h>
#if EASTL_EXCEPTIONS_ENABLED
EA_DISABLE_ALL_VC_WARNINGS()
#include <stdexcept> // std::out_of_range, std::length_error.
EA_RESTORE_ALL_VC_WARNINGS()
#endif
#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
namespace eastl
{
///////////////////////////////////////////////////////////////////////
/// array
///
/// Implements a templated array class as per the C++ standard TR1.
/// This class allows you to use a built-in C style array like an STL vector.
/// It does not let you change its size, as it is just like a C built-in array.
/// Our implementation here strives to remove function call nesting, as that
/// makes it hard for us to profile debug builds due to function call overhead.
/// Note that this is intentionally a struct with public data, as per the
/// C++ standard update proposal requirements.
///
/// Example usage:
/// array<int, 5> a = { { 0, 1, 2, 3, 4 } }; // Strict compilers such as GCC require the double brackets.
/// a[2] = 4;
/// for(array<int, 5>::iterator i = a.begin(); i < a.end(); ++i)
/// *i = 0;
///
template <typename T, size_t N = 1>
struct array
{
public:
typedef array<T, N> this_type;
typedef T value_type;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef eastl::reverse_iterator<iterator> reverse_iterator;
typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
public:
enum
{
count = N
};
// Note that the member data is intentionally public.
// This allows for aggregate initialization of the
// object (e.g. array<int, 5> a = { 0, 3, 2, 4 }; )
value_type mValue[N ? N : 1];
public:
// We intentionally provide no constructor, destructor, or assignment operator.
void fill(const value_type& value);
// Unlike the swap function for other containers, array::swap takes linear time,
// may exit via an exception, and does not cause iterators to become associated with the other container.
void swap(this_type& x) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable<value_type>::value);
EA_CPP14_CONSTEXPR iterator begin() EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_iterator begin() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_iterator cbegin() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR iterator end() EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_iterator end() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_iterator cend() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR reverse_iterator rbegin() EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_reverse_iterator rbegin() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_reverse_iterator crbegin() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR reverse_iterator rend() EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_reverse_iterator rend() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const_reverse_iterator crend() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR bool empty() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR size_type size() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR size_type max_size() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR T* data() EA_NOEXCEPT;
EA_CPP14_CONSTEXPR const T* data() const EA_NOEXCEPT;
EA_CPP14_CONSTEXPR reference operator[](size_type i);
EA_CPP14_CONSTEXPR const_reference operator[](size_type i) const;
EA_CPP14_CONSTEXPR const_reference at(size_type i) const;
EA_CPP14_CONSTEXPR reference at(size_type i);
EA_CPP14_CONSTEXPR reference front();
EA_CPP14_CONSTEXPR const_reference front() const;
EA_CPP14_CONSTEXPR reference back();
EA_CPP14_CONSTEXPR const_reference back() const;
bool validate() const;
int validate_iterator(const_iterator i) const;
}; // class array
///////////////////////////////////////////////////////////////////////////
// template deduction guides
///////////////////////////////////////////////////////////////////////////
#ifdef __cpp_deduction_guides
template <class T, class... U> array(T, U...) -> array<T, 1 + sizeof...(U)>;
#endif
///////////////////////////////////////////////////////////////////////
// array
///////////////////////////////////////////////////////////////////////
template <typename T, size_t N>
inline void array<T, N>::fill(const value_type& value)
{
eastl::fill_n(&mValue[0], N, value);
}
template <typename T, size_t N>
inline void array<T, N>::swap(this_type& x) EA_NOEXCEPT_IF(eastl::is_nothrow_swappable<value_type>::value)
{
eastl::swap_ranges(&mValue[0], &mValue[N], &x.mValue[0]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::iterator
array<T, N>::begin() EA_NOEXCEPT
{
return &mValue[0];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_iterator
array<T, N>::begin() const EA_NOEXCEPT
{
return &mValue[0];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_iterator
array<T, N>::cbegin() const EA_NOEXCEPT
{
return &mValue[0];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::iterator
array<T, N>::end() EA_NOEXCEPT
{
return &mValue[N];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_iterator
array<T, N>::end() const EA_NOEXCEPT
{
return &mValue[N];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_iterator
array<T, N>::cend() const EA_NOEXCEPT
{
return &mValue[N];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reverse_iterator
array<T, N>::rbegin() EA_NOEXCEPT
{
return reverse_iterator(&mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reverse_iterator
array<T, N>::rbegin() const EA_NOEXCEPT
{
return const_reverse_iterator(&mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reverse_iterator
array<T, N>::crbegin() const EA_NOEXCEPT
{
return const_reverse_iterator(&mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reverse_iterator
array<T, N>::rend() EA_NOEXCEPT
{
return reverse_iterator(&mValue[0]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reverse_iterator
array<T, N>::rend() const EA_NOEXCEPT
{
return const_reverse_iterator(static_cast<const_iterator>(&mValue[0]));
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reverse_iterator
array<T, N>::crend() const EA_NOEXCEPT
{
return const_reverse_iterator(static_cast<const_iterator>(&mValue[0]));
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::size_type
array<T, N>::size() const EA_NOEXCEPT
{
return (size_type)N;
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::size_type
array<T, N>::max_size() const EA_NOEXCEPT
{
return (size_type)N;
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool array<T, N>::empty() const EA_NOEXCEPT
{
return (N == 0);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::operator[](size_type i)
{
return mValue[i];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::operator[](size_type i) const
{
return mValue[i];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::front()
{
return mValue[0];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::front() const
{
return mValue[0];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference
array<T, N>::back()
{
return mValue[N - 1];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference
array<T, N>::back() const
{
return mValue[N - 1];
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline T* array<T, N>::data() EA_NOEXCEPT
{
return mValue;
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline const T* array<T, N>::data() const EA_NOEXCEPT
{
return mValue;
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::const_reference array<T, N>::at(size_type i) const
{
#if EASTL_EXCEPTIONS_ENABLED
if(EASTL_UNLIKELY(i >= N))
throw std::out_of_range("array::at -- out of range");
#elif EASTL_ASSERT_ENABLED
if(EASTL_UNLIKELY(i >= N))
EASTL_FAIL_MSG("array::at -- out of range");
#endif
return static_cast<const_reference>(mValue[i]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline typename array<T, N>::reference array<T, N>::at(size_type i)
{
#if EASTL_EXCEPTIONS_ENABLED
if(EASTL_UNLIKELY(i >= N))
throw std::out_of_range("array::at -- out of range");
#elif EASTL_ASSERT_ENABLED
if(EASTL_UNLIKELY(i >= N))
EASTL_FAIL_MSG("array::at -- out of range");
#endif
return static_cast<reference>(mValue[i]);
}
template <typename T, size_t N>
inline bool array<T, N>::validate() const
{
return true; // There is nothing to do.
}
template <typename T, size_t N>
inline int array<T, N>::validate_iterator(const_iterator i) const
{
if(i >= mValue)
{
if(i < (mValue + N))
return (isf_valid | isf_current | isf_can_dereference);
if(i <= (mValue + N))
return (isf_valid | isf_current);
}
return isf_none;
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator==(const array<T, N>& a, const array<T, N>& b)
{
return eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]);
}
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename T, size_t N>
inline synth_three_way_result<T> operator<=>(const array<T, N>& a, const array<T,N>& b)
{
return eastl::lexicographical_compare_three_way(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N], synth_three_way{});
}
#else
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator<(const array<T, N>& a, const array<T, N>& b)
{
return eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator!=(const array<T, N>& a, const array<T, N>& b)
{
return !eastl::equal(&a.mValue[0], &a.mValue[N], &b.mValue[0]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator>(const array<T, N>& a, const array<T, N>& b)
{
return eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator<=(const array<T, N>& a, const array<T, N>& b)
{
return !eastl::lexicographical_compare(&b.mValue[0], &b.mValue[N], &a.mValue[0], &a.mValue[N]);
}
template <typename T, size_t N>
EA_CPP14_CONSTEXPR inline bool operator>=(const array<T, N>& a, const array<T, N>& b)
{
return !eastl::lexicographical_compare(&a.mValue[0], &a.mValue[N], &b.mValue[0], &b.mValue[N]);
}
#endif
template <typename T, size_t N>
inline void swap(array<T, N>& a, array<T, N>& b)
{
eastl::swap_ranges(&a.mValue[0], &a.mValue[N], &b.mValue[0]);
}
///////////////////////////////////////////////////////////////////////
// to_array
///////////////////////////////////////////////////////////////////////
namespace internal
{
template<class T, size_t N, size_t... I>
EA_CONSTEXPR auto to_array(T (&a)[N], index_sequence<I...>)
{
return eastl::array<eastl::remove_cv_t<T>, N>{{a[I]...}};
}
template<class T, size_t N, size_t... I>
EA_CONSTEXPR auto to_array(T (&&a)[N], index_sequence<I...>)
{
return eastl::array<eastl::remove_cv_t<T>, N>{{eastl::move(a[I])...}};
}
}
template<class T, size_t N>
EA_CONSTEXPR eastl::array<eastl::remove_cv_t<T>, N> to_array(T (&a)[N])
{
static_assert(eastl::is_constructible_v<T, T&>, "element type T must be copy-initializable");
static_assert(!eastl::is_array_v<T>, "passing multidimensional arrays to to_array is ill-formed");
return internal::to_array(a, eastl::make_index_sequence<N>{});
}
template<class T, size_t N>
EA_CONSTEXPR eastl::array<eastl::remove_cv_t<T>, N> to_array(T (&&a)[N])
{
static_assert(eastl::is_move_constructible_v<T>, "element type T must be move-constructible");
static_assert(!eastl::is_array_v<T>, "passing multidimensional arrays to to_array is ill-formed");
return internal::to_array(eastl::move(a), eastl::make_index_sequence<N>{});
}
#if EASTL_TUPLE_ENABLED
template <typename T, size_t N>
class tuple_size<array<T, N>> : public integral_constant<size_t, N>
{
};
template <typename T, size_t N>
class tuple_size<const array<T, N>> : public integral_constant<size_t, N>
{
};
template <size_t I, typename T, size_t N>
class tuple_element<I, array<T, N>>
{
public:
using type = T;
};
template <size_t I, typename T, size_t N>
class tuple_element<I, const array<T, N>>
{
public:
using type = const T;
};
template <size_t I>
struct GetArray
{
template <typename T, size_t N>
static EA_CONSTEXPR T& getInternal(array<T, N>& a)
{
return a[I];
}
template <typename T, size_t N>
static EA_CONSTEXPR const T& getInternal(const array<T, N>& a)
{
return a[I];
}
template <typename T, size_t N>
static EA_CONSTEXPR T&& getInternal(array<T, N>&& a)
{
return eastl::forward<T>(a[I]);
}
};
template <size_t I, typename T, size_t N>
EA_CONSTEXPR tuple_element_t<I, array<T, N>>& get(array<T, N>& p)
{
return GetArray<I>::getInternal(p);
}
template <size_t I, typename T, size_t N>
EA_CONSTEXPR const tuple_element_t<I, array<T, N>>& get(const array<T, N>& p)
{
return GetArray<I>::getInternal(p);
}
template <size_t I, typename T, size_t N>
EA_CONSTEXPR tuple_element_t<I, array<T, N>>&& get(array<T, N>&& p)
{
return GetArray<I>::getInternal(eastl::move(p));
}
#endif // EASTL_TUPLE_ENABLED
} // namespace eastl
///////////////////////////////////////////////////////////////
// C++17 structured binding support for eastl::array
//
#ifndef EA_COMPILER_NO_STRUCTURED_BINDING
#include <tuple>
template <typename T, size_t N>
class std::tuple_size<::eastl::array<T, N>> : public ::eastl::integral_constant<size_t, N>
{
};
template <size_t I, typename T, size_t N>
struct std::tuple_element<I, ::eastl::array<T, N>>
{
static_assert(I < N, "index is out of bounds");
using type = T;
};
#endif // EA_COMPILER_NO_STRUCTURED_BINDING
#endif // Header include guard
File diff suppressed because it is too large Load Diff
+172
View File
@@ -0,0 +1,172 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_BIT_H
#define EASTL_BIT_H
#include <EASTL/internal/config.h>
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/memory_base.h>
#include <EASTL/type_traits.h>
#include <string.h> // memcpy
namespace eastl
{
// eastl::bit_cast
// Obtains a value of type To by reinterpreting the object representation of 'from'.
// Every bit in the value representation of the returned To object is equal to the
// corresponding bit in the object representation of 'from'.
//
// In order for bit_cast to be constexpr, the compiler needs to explicitly support
// it by providing the __builtin_bit_cast builtin. If that builtin is not available,
// then we memcpy into aligned storage at runtime and return that instead.
//
// Both types To and From must be equal in size, and must be trivially copyable.
#if defined(EASTL_CONSTEXPR_BIT_CAST_SUPPORTED) && EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
template<typename To, typename From,
typename = eastl::enable_if_t<
sizeof(To) == sizeof(From)
&& eastl::is_trivially_copyable<To>::value
&& eastl::is_trivially_copyable<From>::value
>
>
EA_CONSTEXPR To bit_cast(const From& from) EA_NOEXCEPT
{
return __builtin_bit_cast(To, from);
}
#else
template<typename To, typename From,
typename = eastl::enable_if_t<
sizeof(To) == sizeof(From)
&& eastl::is_trivially_copyable<To>::value
&& eastl::is_trivially_copyable<From>::value
>
>
inline To bit_cast(const From& from) EA_NOEXCEPT
{
typename eastl::aligned_storage<sizeof(To), alignof(To)>::type to;
::memcpy(eastl::addressof(to), eastl::addressof(from), sizeof(To));
return reinterpret_cast<To&>(to);
}
#endif // EASTL_CONSTEXPR_BIT_CAST_SUPPORTED
#if defined(EA_COMPILER_CPP20_ENABLED)
#ifndef EASTL_COUNT_LEADING_ZEROES
#if defined(__GNUC__)
#if (EA_PLATFORM_PTR_SIZE == 8)
#define EASTL_COUNT_LEADING_ZEROES __builtin_clzll
#else
#define EASTL_COUNT_LEADING_ZEROES __builtin_clz
#endif
#endif
#ifndef EASTL_COUNT_LEADING_ZEROES
static inline int eastl_count_leading_zeroes(uint64_t x)
{
if(x)
{
int n = 0;
if(x & UINT64_C(0xFFFFFFFF00000000)) { n += 32; x >>= 32; }
if(x & 0xFFFF0000) { n += 16; x >>= 16; }
if(x & 0xFFFFFF00) { n += 8; x >>= 8; }
if(x & 0xFFFFFFF0) { n += 4; x >>= 4; }
if(x & 0xFFFFFFFC) { n += 2; x >>= 2; }
if(x & 0xFFFFFFFE) { n += 1; }
return 63 - n;
}
return 64;
}
static inline int eastl_count_leading_zeroes(uint32_t x)
{
if(x)
{
int n = 0;
if(x <= 0x0000FFFF) { n += 16; x <<= 16; }
if(x <= 0x00FFFFFF) { n += 8; x <<= 8; }
if(x <= 0x0FFFFFFF) { n += 4; x <<= 4; }
if(x <= 0x3FFFFFFF) { n += 2; x <<= 2; }
if(x <= 0x7FFFFFFF) { n += 1; }
return n;
}
return 32;
}
#define EASTL_COUNT_LEADING_ZEROES eastl_count_leading_zeroes
#endif
#endif
template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
EA_CONSTEXPR int countl_zero(const T num) EA_NOEXCEPT
{
EA_CONSTEXPR auto DIGITS = eastl::numeric_limits<T>::digits;
EA_CONSTEXPR auto DIGITS_U = eastl::numeric_limits<unsigned>::digits;
EA_CONSTEXPR auto DIGITS_ULL = eastl::numeric_limits<unsigned long long>::digits;
if (num == 0)
{
return DIGITS;
}
if constexpr (DIGITS <= DIGITS_U)
{
EA_CONSTEXPR auto DIFF = DIGITS_U - DIGITS;
return EASTL_COUNT_LEADING_ZEROES(static_cast<uint32_t>(num)) - DIFF;
}
else
{
EA_CONSTEXPR auto DIFF = DIGITS_ULL - DIGITS;
return EASTL_COUNT_LEADING_ZEROES(static_cast<uint64_t>(num)) - DIFF;
}
}
template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
EA_CONSTEXPR bool has_single_bit(const T num) EA_NOEXCEPT
{
return num != 0 && (num & (num - 1)) == 0;
}
template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
EA_CONSTEXPR T bit_ceil(const T num) EA_NOEXCEPT
{
if (num <= 1U)
{
return T(1);
}
const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(static_cast<T>(num - 1));
return static_cast<T>(T(1) << shift);
}
template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
EA_CONSTEXPR T bit_floor(const T num) EA_NOEXCEPT
{
if (num == 0)
{
return T(0);
}
const auto shift = eastl::numeric_limits<T>::digits - eastl::countl_zero(num) - 1;
return static_cast<T>(T(1) << shift);
}
template <typename T, typename = eastl::enable_if_t<eastl::is_unsigned_v<T>>>
EA_CONSTEXPR T bit_width(const T num) EA_NOEXCEPT
{
return static_cast<T>(eastl::numeric_limits<T>::digits - eastl::countl_zero(num));
}
#endif
} // namespace eastl
#endif // EASTL_BIT_H
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+88
View File
@@ -0,0 +1,88 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ADAPTORS_H
#define EASTL_ADAPTORS_H
#include <EASTL/internal/config.h>
#include <EASTL/internal/move_help.h>
#include <EASTL/type_traits.h>
#include <EASTL/iterator.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(4512 4626)
#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015+
EA_DISABLE_VC_WARNING(5027) // move assignment operator was implicitly defined as deleted
#endif
namespace eastl
{
/// reverse
///
/// This adaptor allows reverse iteration of a container in ranged base for-loops.
///
/// for (auto& i : reverse(c)) { ... }
///
template <typename Container>
struct reverse_wrapper
{
template <typename C>
reverse_wrapper(C&& c)
: mContainer(eastl::forward<C>(c))
{
/**
* NOTE:
*
* Due to reference collapsing rules of universal references Container type is either
*
* const C& if the input is a const lvalue
* C& if the input is a non-const lvalue
* C if the input is an rvalue
* const C if the input is a const rvalue thus the object will have to be copied and the copy-ctor will be called
*
*
* Thus we either move the whole container into this object or take a reference to the lvalue avoiding the copy.
* The static_assert below ensures this.
*/
static_assert(eastl::is_same_v<C, Container>, "Reference collapsed deduced type must be the same as the deduced Container type!");
}
Container mContainer;
};
template <typename Container>
auto begin(const reverse_wrapper<Container>& w) -> decltype(eastl::rbegin(w.mContainer))
{
return eastl::rbegin(w.mContainer);
}
template <typename Container>
auto end(const reverse_wrapper<Container>& w) -> decltype(eastl::rend(w.mContainer))
{
return eastl::rend(w.mContainer);
}
template <typename Container>
reverse_wrapper<Container> reverse(Container&& c)
{
return reverse_wrapper<Container>(eastl::forward<Container>(c));
}
} // namespace eastl
#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015+
EA_RESTORE_VC_WARNING()
#endif
EA_RESTORE_VC_WARNING()
#endif // Header include guard
+117
View File
@@ -0,0 +1,117 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The design for call_traits here is very similar to that found in template
// metaprogramming libraries such as Boost, GCC, and Metrowerks, given that
// these libraries have established this interface as a defacto standard for
// solving this problem. Also, these are described in various books on the
// topic of template metaprogramming, such as "Modern C++ Design".
//
// See http://www.boost.org/libs/utility/call_traits.htm or search for
// call_traits in Google for a description of call_traits.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_CALL_TRAITS_H
#define EASTL_CALL_TRAITS_H
#include <EASTL/internal/config.h>
#include <EASTL/type_traits.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
namespace eastl
{
template <typename T, bool small_>
struct ct_imp2 { typedef const T& param_type; };
template <typename T>
struct ct_imp2<T, true> { typedef const T param_type; };
template <typename T, bool isp, bool b1>
struct ct_imp { typedef const T& param_type; };
template <typename T, bool isp>
struct ct_imp<T, isp, true> { typedef typename ct_imp2<T, sizeof(T) <= sizeof(void*)>::param_type param_type; };
template <typename T, bool b1>
struct ct_imp<T, true, b1> { typedef T const param_type; };
template <typename T>
struct call_traits
{
public:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef typename ct_imp<T, is_pointer<T>::value, is_arithmetic<T>::value>::param_type param_type;
};
template <typename T>
struct call_traits<T&>
{
typedef T& value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T& param_type;
};
template <typename T, size_t N>
struct call_traits<T [N]>
{
private:
typedef T array_type[N];
public:
typedef const T* value_type;
typedef array_type& reference;
typedef const array_type& const_reference;
typedef const T* const param_type;
};
template <typename T, size_t N>
struct call_traits<const T [N]>
{
private:
typedef const T array_type[N];
public:
typedef const T* value_type;
typedef array_type& reference;
typedef const array_type& const_reference;
typedef const T* const param_type;
};
} // namespace eastl
#endif // Header include guard
+460
View File
@@ -0,0 +1,460 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The compressed pair class is very similar to std::pair, but if either of the
// template arguments are empty classes, then the "empty base-class optimization"
// is applied to compress the size of the pair.
//
// The design for compressed_pair here is very similar to that found in template
// metaprogramming libraries such as Boost, GCC, and Metrowerks, given that
// these libraries have established this interface as a defacto standard for
// solving this problem. Also, these are described in various books on the
// topic of template metaprogramming, such as "Modern C++ Design".
//
// template <typename T1, typename T2>
// class compressed_pair
// {
// public:
// typedef T1 first_type;
// typedef T2 second_type;
// typedef typename call_traits<first_type>::param_type first_param_type;
// typedef typename call_traits<second_type>::param_type second_param_type;
// typedef typename call_traits<first_type>::reference first_reference;
// typedef typename call_traits<second_type>::reference second_reference;
// typedef typename call_traits<first_type>::const_reference first_const_reference;
// typedef typename call_traits<second_type>::const_reference second_const_reference;
//
// compressed_pair() : base() {}
// compressed_pair(first_param_type x, second_param_type y);
// explicit compressed_pair(first_param_type x);
// explicit compressed_pair(second_param_type y);
//
// compressed_pair& operator=(const compressed_pair&);
//
// first_reference first();
// first_const_reference first() const;
//
// second_reference second();
// second_const_reference second() const;
//
// void swap(compressed_pair& y);
// };
//
// The two members of the pair can be accessed using the member functions first()
// and second(). Note that not all member functions can be instantiated for all
// template parameter types. In particular compressed_pair can be instantiated for
// reference and array types, however in these cases the range of constructors that
// can be used are limited. If types T1 and T2 are the same type, then there is
// only one version of the single-argument constructor, and this constructor
// initialises both values in the pair to the passed value.
//
// Note that compressed_pair can not be instantiated if either of the template
// arguments is a union type, unless there is compiler support for is_union,
// or if is_union is specialised for the union type.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_COMPRESSED_PAIR_H
#define EASTL_COMPRESSED_PAIR_H
#include <EASTL/internal/config.h>
#include <EASTL/type_traits.h>
#include <EASTL/bonus/call_traits.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
#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later
EA_DISABLE_VC_WARNING(4626 5027) // warning C4626: 'eastl::compressed_pair_imp<T1,T2,0>': assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted
#endif
namespace eastl
{
template <typename T1, typename T2>
class compressed_pair;
template <typename T1, typename T2, bool isSame, bool firstEmpty, bool secondEmpty>
struct compressed_pair_switch;
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, false, false, false>{ static const int value = 0; };
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, false, true, false> { static const int value = 1; };
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, false, false, true> { static const int value = 2; };
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, false, true, true> { static const int value = 3; };
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, true, true, true> { static const int value = 4; };
template <typename T1, typename T2>
struct compressed_pair_switch<T1, T2, true, false, false> { static const int value = 5; };
template <typename T1, typename T2, int version>
class compressed_pair_imp;
template <typename T>
inline void cp_swap(T& t1, T& t2)
{
T tTemp = t1;
t1 = t2;
t2 = tTemp;
}
// Derive from neither
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 0>
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type y)
: mFirst(x), mSecond(y) {}
compressed_pair_imp(first_param_type x)
: mFirst(x) {}
compressed_pair_imp(second_param_type y)
: mSecond(y) {}
first_reference first() { return mFirst; }
first_const_reference first() const { return mFirst; }
second_reference second() { return mSecond; }
second_const_reference second() const { return mSecond; }
void swap(compressed_pair<T1, T2>& y)
{
cp_swap(mFirst, y.first());
cp_swap(mSecond, y.second());
}
private:
first_type mFirst;
second_type mSecond;
};
// Derive from T1
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 1> : private T1
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type y)
: first_type(x), mSecond(y) {}
compressed_pair_imp(first_param_type x)
: first_type(x) {}
compressed_pair_imp(second_param_type y)
: mSecond(y) {}
first_reference first() { return *this; }
first_const_reference first() const { return *this; }
second_reference second() { return mSecond; }
second_const_reference second() const { return mSecond; }
void swap(compressed_pair<T1,T2>& y)
{
// No need to swap empty base class
cp_swap(mSecond, y.second());
}
private:
second_type mSecond;
};
// Derive from T2
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 2> : private T2
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type y)
: second_type(y), mFirst(x) {}
compressed_pair_imp(first_param_type x)
: mFirst(x) {}
compressed_pair_imp(second_param_type y)
: second_type(y) {}
first_reference first() { return mFirst; }
first_const_reference first() const { return mFirst; }
second_reference second() { return *this; }
second_const_reference second() const { return *this; }
void swap(compressed_pair<T1,T2>& y)
{
// No need to swap empty base class
cp_swap(mFirst, y.first());
}
private:
first_type mFirst;
};
// Derive from T1 and T2
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 3> : private T1, private T2
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type y)
: first_type(x), second_type(y) {}
compressed_pair_imp(first_param_type x)
: first_type(x) {}
compressed_pair_imp(second_param_type y)
: second_type(y) {}
first_reference first() { return *this; }
first_const_reference first() const { return *this; }
second_reference second() { return *this; }
second_const_reference second() const { return *this; }
// No need to swap empty bases
void swap(compressed_pair<T1, T2>&)
{ }
};
// T1 == T2, T1 and T2 are both empty
// Note does not actually store an instance of T2 at all;
// but reuses T1 base class for both first() and second().
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 4> : private T1
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type)
: first_type(x) {}
compressed_pair_imp(first_param_type x)
: first_type(x) {}
first_reference first() { return *this; }
first_const_reference first() const { return *this; }
second_reference second() { return *this; }
second_const_reference second() const { return *this; }
void swap(compressed_pair<T1, T2>&) { }
};
// T1 == T2 and are not empty
template <typename T1, typename T2>
class compressed_pair_imp<T1, T2, 5>
{
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair_imp() {}
compressed_pair_imp(first_param_type x, second_param_type y)
: mFirst(x), mSecond(y) {}
compressed_pair_imp(first_param_type x)
: mFirst(x), mSecond(x) {}
first_reference first() { return mFirst; }
first_const_reference first() const { return mFirst; }
second_reference second() { return mSecond; }
second_const_reference second() const { return mSecond; }
void swap(compressed_pair<T1, T2>& y)
{
cp_swap(mFirst, y.first());
cp_swap(mSecond, y.second());
}
private:
first_type mFirst;
second_type mSecond;
};
template <typename T1, typename T2>
class compressed_pair
: private compressed_pair_imp<T1, T2,
compressed_pair_switch<
T1,
T2,
is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
is_empty<T1>::value,
is_empty<T2>::value>::value>
{
private:
typedef compressed_pair_imp<T1, T2,
compressed_pair_switch<
T1,
T2,
is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
is_empty<T1>::value,
is_empty<T2>::value>::value> base;
public:
typedef T1 first_type;
typedef T2 second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair() : base() {}
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
explicit compressed_pair(first_param_type x) : base(x) {}
explicit compressed_pair(second_param_type y) : base(y) {}
first_reference first() { return base::first(); }
first_const_reference first() const { return base::first(); }
second_reference second() { return base::second(); }
second_const_reference second() const { return base::second(); }
void swap(compressed_pair& y) { base::swap(y); }
};
// Partial specialisation for case where T1 == T2:
template <typename T>
class compressed_pair<T, T>
: private compressed_pair_imp<T, T,
compressed_pair_switch<
T,
T,
is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
is_empty<T>::value,
is_empty<T>::value>::value>
{
private:
typedef compressed_pair_imp<T, T,
compressed_pair_switch<
T,
T,
is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
is_empty<T>::value,
is_empty<T>::value>::value> base;
public:
typedef T first_type;
typedef T second_type;
typedef typename call_traits<first_type>::param_type first_param_type;
typedef typename call_traits<second_type>::param_type second_param_type;
typedef typename call_traits<first_type>::reference first_reference;
typedef typename call_traits<second_type>::reference second_reference;
typedef typename call_traits<first_type>::const_reference first_const_reference;
typedef typename call_traits<second_type>::const_reference second_const_reference;
compressed_pair() : base() {}
compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
explicit compressed_pair(first_param_type x) : base(x) {}
first_reference first() { return base::first(); }
first_const_reference first() const { return base::first(); }
second_reference second() { return base::second(); }
second_const_reference second() const { return base::second(); }
void swap(compressed_pair<T, T>& y) { base::swap(y); }
};
template <typename T1, typename T2>
inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
{
x.swap(y);
}
} // namespace eastl
#if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later
EA_RESTORE_VC_WARNING()
#endif
#endif // Header include guard
+50
View File
@@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_RING_BUFFER_H
#define EASTL_FIXED_RING_BUFFER_H
#include <EASTL/internal/config.h>
#include <EASTL/fixed_vector.h>
#include <EASTL/bonus/ring_buffer.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
namespace eastl
{
/// fixed_ring_buffer
///
/// This is a convenience template alias for creating a fixed-sized
/// ring_buffer using eastl::fixed_vector as its storage container. This has
/// been tricky for users to get correct due to the constructor requirements
/// of eastl::ring_buffer leaking the implementation detail of the sentinel
/// value being used internally. In addition, it was not obvious what the
/// correct allocator_type template parameter should be used for containers
/// providing both a default allocator type and an overflow allocator type.
///
/// We are over-allocating the fixed_vector container to accommodate the
/// ring_buffer sentinel to prevent that implementation detail leaking into
/// user code.
///
/// Example usage:
///
/// fixed_ring_buffer<int, 8> rb = {0, 1, 2, 3, 4, 5, 6, 7};
/// or
/// fixed_ring_buffer<int, 8> rb(8); // capacity doesn't need to respect sentinel
/// rb.push_back(0);
///
///
#if !defined(EA_COMPILER_NO_TEMPLATE_ALIASES)
template <typename T, size_t N>
using fixed_ring_buffer =
ring_buffer<T, fixed_vector<T, N + 1, false>, typename fixed_vector<T, N + 1, false>::overflow_allocator_type>;
#endif
} // namespace eastl
#endif // Header include guard
+210
View File
@@ -0,0 +1,210 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXEDTUPLEVECTOR_H
#define EASTL_FIXEDTUPLEVECTOR_H
#include <EASTL/bonus/tuple_vector.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME
#define EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_tuple_vector" // Unless the user overrides something, this is "EASTL fixed_vector".
#endif
/// EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR
#define EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_TUPLE_VECTOR_DEFAULT_NAME)
#endif
// External interface of fixed_tuple_vector
template <size_t nodeCount, bool bEnableOverflow, typename... Ts>
class fixed_tuple_vector : public TupleVecInternal::TupleVecImpl<fixed_vector_allocator<
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAllocationSize(nodeCount, 0), 1,
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAlignment(), 0,
bEnableOverflow, EASTLAllocatorType>, make_index_sequence<sizeof...(Ts)>, Ts...>
{
public:
typedef fixed_vector_allocator<
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAllocationSize(nodeCount, 0), 1,
TupleVecInternal::TupleRecurser<Ts...>::GetTotalAlignment(), 0,
bEnableOverflow, EASTLAllocatorType> fixed_allocator_type;
typedef aligned_buffer<fixed_allocator_type::kNodesSize, fixed_allocator_type::kNodeAlignment> aligned_buffer_type;
typedef fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...> this_type;
typedef EASTLAllocatorType overflow_allocator_type;
typedef TupleVecInternal::TupleVecImpl<fixed_allocator_type, make_index_sequence<sizeof...(Ts)>, Ts...> base_type;
typedef typename base_type::size_type size_type;
private:
aligned_buffer_type mBuffer;
public:
fixed_tuple_vector()
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{ }
fixed_tuple_vector(const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{ }
fixed_tuple_vector(this_type&& x)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::get_allocator().copy_overflow_allocator(x.get_allocator());
base_type::DoInitFromIterator(make_move_iterator(x.begin()), make_move_iterator(x.end()));
x.clear();
}
fixed_tuple_vector(this_type&& x, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(make_move_iterator(x.begin()), make_move_iterator(x.end()));
x.clear();
}
fixed_tuple_vector(const this_type& x)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::get_allocator().copy_overflow_allocator(x.get_allocator());
base_type::DoInitFromIterator(x.begin(), x.end());
}
fixed_tuple_vector(const this_type& x, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(x.begin(), x.end());
}
template <typename MoveIterBase>
fixed_tuple_vector(move_iterator<MoveIterBase> begin, move_iterator<MoveIterBase> end, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(begin, end);
}
template <typename Iterator>
fixed_tuple_vector(Iterator begin, Iterator end, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromIterator(begin, end);
}
fixed_tuple_vector(size_type n, const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitDefaultFill(n);
}
fixed_tuple_vector(size_type n, const Ts&... args)
: base_type(fixed_allocator_type(mBuffer.buffer), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillArgs(n, args...);
}
fixed_tuple_vector(size_type n, const Ts&... args, const overflow_allocator_type& allocator)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillArgs(n, args...);
}
fixed_tuple_vector(size_type n,
typename base_type::const_reference_tuple tup,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFillTuple(n, tup);
}
fixed_tuple_vector(const typename base_type::value_tuple* first, const typename base_type::value_tuple* last,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromTupleArray(first, last);
}
fixed_tuple_vector(std::initializer_list<typename base_type::value_tuple> iList,
const overflow_allocator_type& allocator = EASTL_FIXED_TUPLE_VECTOR_DEFAULT_ALLOCATOR)
: base_type(fixed_allocator_type(mBuffer.buffer, allocator), mBuffer.buffer, nodeCount, fixed_allocator_type::kNodeSize)
{
base_type::DoInitFromTupleArray(iList.begin(), iList.end());
}
this_type& operator=(const this_type& other)
{
base_type::operator=(other);
return *this;
}
this_type& operator=(this_type&& other)
{
base_type::clear();
// OK to call DoInitFromIterator in a non-ctor scenario because clear() reset everything, more-or-less
base_type::DoInitFromIterator(make_move_iterator(other.begin()), make_move_iterator(other.end()));
other.clear();
return *this;
}
this_type& operator=(std::initializer_list<typename base_type::value_tuple> iList)
{
base_type::operator=(iList);
return *this;
}
void swap(this_type& x)
{
// If both containers are using the heap instead of local memory
// then we can do a fast pointer swap instead of content swap.
if ((has_overflowed() && x.has_overflowed()) && (get_overflow_allocator() == x.get_overflow_allocator()))
{
base_type::swap(x);
}
else
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
}
// Returns the max fixed size, which is the user-supplied nodeCount parameter.
size_type max_size() const { return nodeCount; }
// Returns true if the fixed space has been fully allocated. Note that if overflow is enabled,
// the container size can be greater than nodeCount but full() could return true because the
// fixed space may have a recently freed slot.
bool full() const { return (base_type::mNumElements >= nodeCount) || ((void*)base_type::mpData != (void*)mBuffer.buffer); }
// Returns true if the allocations spilled over into the overflow allocator. Meaningful
// only if overflow is enabled.
bool has_overflowed() const { return ((void*)base_type::mpData != (void*)mBuffer.buffer); }
// Returns the value of the bEnableOverflow template parameter.
bool can_overflow() const { return bEnableOverflow; }
const overflow_allocator_type& get_overflow_allocator() const { return base_type::get_allocator().get_overflow_allocator(); }
};
template <size_t nodeCount, bool bEnableOverflow, typename... Ts>
inline void swap(fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...>& a,
fixed_tuple_vector<nodeCount, bEnableOverflow, Ts...>& b)
{
a.swap(b);
}
} // namespace eastl
#endif // EASTL_TUPLEVECTOR_H
+694
View File
@@ -0,0 +1,694 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// intrusive_sdlist is a special kind of intrusive list which we say is
// "singly-doubly" linked. Instead of having a typical intrusive list node
// which looks like this:
//
// struct intrusive_sdlist_node {
// intrusive_sdlist_node *mpNext;
// intrusive_sdlist_node *mpPrev;
// };
//
// We instead have one that looks like this:
//
// struct intrusive_sdlist_node {
// intrusive_sdlist_node* mpNext;
// intrusive_sdlist_node** mppPrevNext;
// };
//
// This may seem to be suboptimal, but it has one specific advantage: it allows
// the intrusive_sdlist class to be the size of only one pointer instead of two.
// This may seem like a minor optimization, but some users have wanted to create
// thousands of empty instances of these.
// This is because while an intrusive_list class looks like this:
//
// class intrusive_list {
// intrusive_list_node mBaseNode;
// };
//
// an intrusive_sdlist class looks like this:
//
// class intrusive_sdlist {
// intrusive_sdlist_node* mpNext;
// };
//
// So here we make a list of plusses and minuses of intrusive sdlists
// compared to intrusive_lists and intrusive_slists:
//
// | list | slist | sdlist
// ---------------------------------------------------------
// min size | 8 | 4 | 4
// node size | 8 | 4 | 8
// anonymous erase | yes | no | yes
// reverse iteration | yes | no | no
//
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_INTRUSIVE_SDLIST_H
#define EASTL_INTRUSIVE_SDLIST_H
#include <EASTL/internal/config.h>
#include <EASTL/iterator.h>
#include <EASTL/algorithm.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
namespace eastl
{
/// intrusive_sdlist_node
///
struct intrusive_sdlist_node
{
intrusive_sdlist_node* mpNext;
intrusive_sdlist_node** mppPrevNext;
};
/// IntrusiveSDListIterator
///
template <typename T, typename Pointer, typename Reference>
struct IntrusiveSDListIterator
{
typedef IntrusiveSDListIterator<T, Pointer, Reference> this_type;
typedef IntrusiveSDListIterator<T, T*, T&> iterator;
typedef IntrusiveSDListIterator<T, const T*, const T&> const_iterator;
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T node_type;
typedef Pointer pointer;
typedef Reference reference;
typedef EASTL_ITC_NS::forward_iterator_tag iterator_category;
public:
pointer mpNode;
public:
IntrusiveSDListIterator();
explicit IntrusiveSDListIterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type.
IntrusiveSDListIterator(const iterator& x);
reference operator*() const;
pointer operator->() const;
this_type& operator++();
this_type operator++(int);
}; // struct IntrusiveSDListIterator
/// intrusive_sdlist_base
///
/// Provides a template-less base class for intrusive_sdlist.
///
class intrusive_sdlist_base
{
public:
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
protected:
intrusive_sdlist_node* mpNext;
public:
intrusive_sdlist_base();
bool empty() const; ///< Returns true if the container is empty.
size_type size() const; ///< Returns the number of elements in the list; O(n).
void clear(); ///< Clears the list; O(1). No deallocation occurs.
void pop_front(); ///< Removes an element from the front of the list; O(1). The element must be present, but is not deallocated.
void reverse(); ///< Reverses a list so that front and back are swapped; O(n).
//bool validate() const; ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching.
}; // class intrusive_sdlist_base
/// intrusive_sdlist
///
template <typename T = intrusive_sdlist_node>
class intrusive_sdlist : public intrusive_sdlist_base
{
public:
typedef intrusive_sdlist<T> this_type;
typedef intrusive_sdlist_base base_type;
typedef T node_type;
typedef T value_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef IntrusiveSDListIterator<T, T*, T&> iterator;
typedef IntrusiveSDListIterator<T, const T*, const T&> const_iterator;
typedef eastl::reverse_iterator<iterator> reverse_iterator;
typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
public:
intrusive_sdlist(); ///< Creates an empty list.
intrusive_sdlist(const this_type& x); ///< Creates an empty list; ignores the argument.
this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument.
iterator begin(); ///< Returns an iterator pointing to the first element in the list.
const_iterator begin() const; ///< Returns a const_iterator pointing to the first element in the list.
const_iterator cbegin() const; ///< Returns a const_iterator pointing to the first element in the list.
iterator end(); ///< Returns an iterator pointing one-after the last element in the list.
const_iterator end() const; ///< Returns a const_iterator pointing one-after the last element in the list.
const_iterator cend() const; ///< Returns a const_iterator pointing one-after the last element in the list.
reference front(); ///< Returns a reference to the first element. The list must be empty.
const_reference front() const; ///< Returns a const reference to the first element. The list must be empty.
void push_front(value_type& value); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list.
void push_back(value_type& value); ///< Adds an element to the back of the list; O(N). The element is not copied. The element must not be in any other list.
void pop_back(); ///< Removes an element from the back of the list; O(N). The element must be present, but is not deallocated.
bool contains(const value_type& value) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()).
iterator locate(value_type& value); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n)
const_iterator locate(const value_type& value) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n)
iterator insert(iterator position, value_type& value); ///< Inserts an element before the element pointed to by the iterator. O(1)
iterator erase(iterator position); ///< Erases the element pointed to by the iterator. O(1)
iterator erase(iterator first, iterator last); ///< Erases elements within the iterator range [first, last). O(1).
void swap(intrusive_sdlist& x); ///< Swaps the contents of two intrusive lists; O(1).
static void remove(value_type& value); ///< Erases an element from a list; O(1). Note that this is static so you don't need to know which list the element, although it must be in some list.
void splice(iterator position, value_type& value); ///< Moves the given element into this list before the element pointed to by position; O(1).
///< Required: x must be in some list or have first/next pointers that point it itself.
void splice(iterator position, this_type& x); ///< Moves the contents of a list into this list before the element pointed to by position; O(1).
///< Required: &x != this (same as std::list).
void splice(iterator position, this_type& x, iterator xPosition); ///< Moves the given element pointed to i within the list x into the current list before
///< the element pointed to by position; O(1).
void splice(iterator position, this_type& x, iterator first, iterator last); ///< Moves the range of elements [first, last) from list x into the current list before
///< the element pointed to by position; O(1).
///< Required: position must not be in [first, last). (same as std::list).
bool validate() const;
int validate_iterator(const_iterator i) const;
}; // intrusive_sdlist
///////////////////////////////////////////////////////////////////////
// IntrusiveSDListIterator functions
///////////////////////////////////////////////////////////////////////
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSDListIterator<T, Pointer, Reference>::IntrusiveSDListIterator()
{
#if EASTL_DEBUG
mpNode = NULL;
#endif
}
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSDListIterator<T, Pointer, Reference>::IntrusiveSDListIterator(pointer pNode)
: mpNode(pNode)
{
}
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSDListIterator<T, Pointer, Reference>::IntrusiveSDListIterator(const iterator& x)
: mpNode(x.mpNode)
{
}
template <typename T, typename Pointer, typename Reference>
inline typename IntrusiveSDListIterator<T, Pointer, Reference>::reference
IntrusiveSDListIterator<T, Pointer, Reference>::operator*() const
{
return *mpNode;
}
template <typename T, typename Pointer, typename Reference>
inline typename IntrusiveSDListIterator<T, Pointer, Reference>::pointer
IntrusiveSDListIterator<T, Pointer, Reference>::operator->() const
{
return mpNode;
}
template <typename T, typename Pointer, typename Reference>
inline typename IntrusiveSDListIterator<T, Pointer, Reference>::this_type&
IntrusiveSDListIterator<T, Pointer, Reference>::operator++()
{
mpNode = static_cast<node_type*>(mpNode->mpNext);
return *this;
}
template <typename T, typename Pointer, typename Reference>
inline typename IntrusiveSDListIterator<T, Pointer, Reference>::this_type
IntrusiveSDListIterator<T, Pointer, Reference>::operator++(int)
{
this_type temp = *this;
mpNode = static_cast<node_type*>(mpNode->mpNext);
return temp;
}
// The C++ defect report #179 requires that we support comparisons between const and non-const iterators.
// Thus we provide additional template paremeters here to support this. The defect report does not
// require us to support comparisons between reverse_iterators and const_reverse_iterators.
template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
inline bool operator==(const IntrusiveSDListIterator<T, PointerA, ReferenceA>& a,
const IntrusiveSDListIterator<T, PointerB, ReferenceB>& b)
{
return a.mpNode == b.mpNode;
}
template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
inline bool operator!=(const IntrusiveSDListIterator<T, PointerA, ReferenceA>& a,
const IntrusiveSDListIterator<T, PointerB, ReferenceB>& b)
{
return a.mpNode != b.mpNode;
}
// We provide a version of operator!= for the case where the iterators are of the
// same type. This helps prevent ambiguity errors in the presence of rel_ops.
template <typename T, typename Pointer, typename Reference>
inline bool operator!=(const IntrusiveSDListIterator<T, Pointer, Reference>& a,
const IntrusiveSDListIterator<T, Pointer, Reference>& b)
{
return a.mpNode != b.mpNode;
}
///////////////////////////////////////////////////////////////////////
// intrusive_sdlist_base
///////////////////////////////////////////////////////////////////////
inline intrusive_sdlist_base::intrusive_sdlist_base()
{ mpNext = NULL; }
inline bool intrusive_sdlist_base::empty() const
{ return mpNext == NULL; }
inline intrusive_sdlist_base::size_type intrusive_sdlist_base::size() const
{
size_type n = 0;
for(const intrusive_sdlist_node* pCurrent = mpNext; pCurrent; pCurrent = pCurrent->mpNext)
n++;
return n;
}
inline void intrusive_sdlist_base::clear()
{ mpNext = NULL; } // Note that we don't do anything with the list nodes.
inline void intrusive_sdlist_base::pop_front()
{
// To consider: Set mpNext's pointers to NULL in debug builds.
mpNext = mpNext->mpNext;
mpNext->mppPrevNext = &mpNext;
}
///////////////////////////////////////////////////////////////////////
// intrusive_sdlist
///////////////////////////////////////////////////////////////////////
template <typename T>
inline intrusive_sdlist<T>::intrusive_sdlist()
{
}
template <typename T>
inline intrusive_sdlist<T>::intrusive_sdlist(const this_type& /*x*/)
: intrusive_sdlist_base()
{
// We intentionally ignore argument x.
}
template <typename T>
inline typename intrusive_sdlist<T>::this_type& intrusive_sdlist<T>::operator=(const this_type& /*x*/)
{
return *this; // We intentionally ignore argument x.
}
template <typename T>
inline typename intrusive_sdlist<T>::iterator intrusive_sdlist<T>::begin()
{ return iterator(static_cast<T*>(mpNext)); }
template <typename T>
inline typename intrusive_sdlist<T>::const_iterator intrusive_sdlist<T>::begin() const
{ return const_iterator(static_cast<T*>(const_cast<intrusive_sdlist_node*>(mpNext))); }
template <typename T>
inline typename intrusive_sdlist<T>::const_iterator intrusive_sdlist<T>::cbegin() const
{ return const_iterator(static_cast<T*>(const_cast<intrusive_sdlist_node*>(mpNext))); }
template <typename T>
inline typename intrusive_sdlist<T>::iterator intrusive_sdlist<T>::end()
{ return iterator(static_cast<T*>(NULL)); }
template <typename T>
inline typename intrusive_sdlist<T>::const_iterator intrusive_sdlist<T>::end() const
{ return const_iterator(static_cast<const T*>(NULL)); }
template <typename T>
inline typename intrusive_sdlist<T>::const_iterator intrusive_sdlist<T>::cend() const
{ return const_iterator(static_cast<const T*>(NULL)); }
template <typename T>
inline typename intrusive_sdlist<T>::reference intrusive_sdlist<T>::front()
{ return *static_cast<T*>(mpNext); }
template <typename T>
inline typename intrusive_sdlist<T>::const_reference intrusive_sdlist<T>::front() const
{ return *static_cast<const T*>(mpNext); }
template <typename T>
inline void intrusive_sdlist<T>::push_front(value_type& value)
{
value.mpNext = mpNext;
value.mppPrevNext = &mpNext;
if(mpNext)
mpNext->mppPrevNext = &value.mpNext;
mpNext = &value;
}
template <typename T>
inline void intrusive_sdlist<T>::push_back(value_type& value)
{
intrusive_sdlist_node* pNext = mpNext;
intrusive_sdlist_node** ppPrevNext = &mpNext;
while(pNext)
{
ppPrevNext = &pNext->mpNext;
pNext = pNext->mpNext;
}
*ppPrevNext = &value;
value.mppPrevNext = ppPrevNext;
value.mpNext = NULL;
}
template <typename T>
inline void intrusive_sdlist<T>::pop_back()
{
node_type* pCurrent = static_cast<node_type*>(mpNext);
while(pCurrent->mpNext)
pCurrent = static_cast<node_type*>(pCurrent->mpNext);
*pCurrent->mppPrevNext = NULL;
}
template <typename T>
inline bool intrusive_sdlist<T>::contains(const value_type& value) const
{
const intrusive_sdlist_node* pCurrent;
for(pCurrent = mpNext; pCurrent; pCurrent = pCurrent->mpNext)
{
if(pCurrent == &value)
break;
}
return (pCurrent != NULL);
}
template <typename T>
inline typename intrusive_sdlist<T>::iterator intrusive_sdlist<T>::locate(value_type& value)
{
intrusive_sdlist_node* pCurrent;
for(pCurrent = static_cast<value_type*>(mpNext); pCurrent; pCurrent = pCurrent->mpNext)
{
if(pCurrent == &value)
break;
}
return iterator(static_cast<value_type*>(pCurrent));
}
template <typename T>
inline typename intrusive_sdlist<T>::const_iterator intrusive_sdlist<T>::locate(const T& value) const
{
const intrusive_sdlist_node* pCurrent;
for(pCurrent = static_cast<value_type*>(mpNext); pCurrent; pCurrent = pCurrent->mpNext)
{
if(pCurrent == &value)
break;
}
return const_iterator(static_cast<value_type*>(const_cast<intrusive_sdlist_node*>(pCurrent)));
}
template <typename T>
inline typename intrusive_sdlist<T>::iterator
intrusive_sdlist<T>::insert(iterator position, value_type& value)
{
value.mppPrevNext = position.mpNode->mppPrevNext;
value.mpNext = position.mpNode;
*value.mppPrevNext = &value;
position.mpNode->mppPrevNext = &value.mpNext;
return iterator(&value);
}
template <typename T>
inline typename intrusive_sdlist<T>::iterator
intrusive_sdlist<T>::erase(iterator position)
{
*position.mpNode->mppPrevNext = position.mpNode->mpNext;
position.mpNode->mpNext->mppPrevNext = position.mpNode->mppPrevNext;
return iterator(position.mpNode);
}
template <typename T>
inline typename intrusive_sdlist<T>::iterator
intrusive_sdlist<T>::erase(iterator first, iterator last)
{
if(first.mpNode) // If not erasing the end...
{
*first.mpNode->mppPrevNext = last.mpNode;
if(last.mpNode) // If not erasing to the end...
last.mpNode->mppPrevNext = first.mpNode->mppPrevNext;
}
return last;
}
template <typename T>
inline void intrusive_sdlist<T>::remove(value_type& value)
{
*value.mppPrevNext = value.mpNext;
if(value.mpNext)
value.mpNext->mppPrevNext = value.mppPrevNext;
}
template <typename T>
void intrusive_sdlist<T>::swap(intrusive_sdlist& x)
{
// swap anchors
intrusive_sdlist_node* const temp(mpNext);
mpNext = x.mpNext;
x.mpNext = temp;
if(x.mpNext)
x.mpNext->mppPrevNext = &mpNext;
if(mpNext)
mpNext->mppPrevNext = &x.mpNext;
}
// To do: Complete these splice functions. Might want to look at intrusive_sdlist for help.
template <typename T>
void intrusive_sdlist<T>::splice(iterator /*position*/, value_type& /*value*/)
{
EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion.
}
template <typename T>
void intrusive_sdlist<T>::splice(iterator /*position*/, intrusive_sdlist& /*x*/)
{
EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion.
}
template <typename T>
void intrusive_sdlist<T>::splice(iterator /*position*/, intrusive_sdlist& /*x*/, iterator /*xPosition*/)
{
EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion.
}
template <typename T>
void intrusive_sdlist<T>::splice(iterator /*position*/, intrusive_sdlist& /*x*/, iterator /*first*/, iterator /*last*/)
{
EASTL_ASSERT(false); // If you need this working, ask Paul Pedriana or submit a working version for inclusion.
}
template <typename T>
inline bool intrusive_sdlist<T>::validate() const
{
return true; // To do.
}
template <typename T>
inline int intrusive_sdlist<T>::validate_iterator(const_iterator i) const
{
// To do: Come up with a more efficient mechanism of doing this.
for(const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp)
{
if(temp == i)
return (isf_valid | isf_current | isf_can_dereference);
}
if(i == end())
return (isf_valid | isf_current);
return isf_none;
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename T>
bool operator==(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
// If we store an mSize member for intrusive_sdlist, we want to take advantage of it here.
typename intrusive_sdlist<T>::const_iterator ia = a.begin();
typename intrusive_sdlist<T>::const_iterator ib = b.begin();
typename intrusive_sdlist<T>::const_iterator enda = a.end();
typename intrusive_sdlist<T>::const_iterator endb = b.end();
while((ia != enda) && (ib != endb) && (*ia == *ib))
{
++ia;
++ib;
}
return (ia == enda) && (ib == endb);
}
template <typename T>
bool operator<(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
template <typename T>
bool operator!=(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
return !(a == b);
}
template <typename T>
bool operator>(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
return b < a;
}
template <typename T>
bool operator<=(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
return !(b < a);
}
template <typename T>
bool operator>=(const intrusive_sdlist<T>& a, const intrusive_sdlist<T>& b)
{
return !(a < b);
}
template <typename T>
void swap(intrusive_sdlist<T>& a, intrusive_sdlist<T>& b)
{
a.swap(b);
}
} // namespace eastl
#endif // Header include guard
+321
View File
@@ -0,0 +1,321 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// *** Note ***
// This implementation is incomplete.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_INTRUSIVE_SLIST_H
#define EASTL_INTRUSIVE_SLIST_H
#include <EASTL/internal/config.h>
#include <EASTL/iterator.h>
#include <EASTL/algorithm.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
namespace eastl
{
/// intrusive_slist_node
///
struct intrusive_slist_node
{
intrusive_slist_node* mpNext;
};
/// IntrusiveSListIterator
///
template <typename T, typename Pointer, typename Reference>
struct IntrusiveSListIterator
{
typedef IntrusiveSListIterator<T, Pointer, Reference> this_type;
typedef IntrusiveSListIterator<T, T*, T&> iterator;
typedef IntrusiveSListIterator<T, const T*, const T&> const_iterator;
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T node_type;
typedef Pointer pointer;
typedef Reference reference;
typedef EASTL_ITC_NS::forward_iterator_tag iterator_category;
public:
node_type* mpNode;
public:
IntrusiveSListIterator();
explicit IntrusiveSListIterator(pointer pNode); // Note that you can also construct an iterator from T via this, since value_type == node_type.
IntrusiveSListIterator(const iterator& x);
reference operator*() const;
pointer operator->() const;
this_type& operator++();
this_type operator++(int);
}; // struct IntrusiveSListIterator
/// intrusive_slist_base
///
/// Provides a template-less base class for intrusive_slist.
///
class intrusive_slist_base
{
public:
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
protected:
intrusive_slist_node* mpNext;
public:
intrusive_slist_base();
bool empty() const; ///< Returns true if the container is empty.
size_type size() const; ///< Returns the number of elements in the list; O(n).
void clear(); ///< Clears the list; O(1). No deallocation occurs.
void pop_front(); ///< Removes an element from the front of the list; O(1). The element must be present, but is not deallocated.
void reverse(); ///< Reverses a list so that front and back are swapped; O(n).
//bool validate() const; ///< Scans a list for linkage inconsistencies; O(n) time, O(1) space. Returns false if errors are detected, such as loops or branching.
}; // class intrusive_slist_base
/// intrusive_slist
///
template <typename T = intrusive_slist_node>
class intrusive_slist : public intrusive_slist_base
{
public:
typedef intrusive_slist<T> this_type;
typedef intrusive_slist_base base_type;
typedef T node_type;
typedef T value_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::difference_type difference_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;
typedef IntrusiveSListIterator<T, T*, T&> iterator;
typedef IntrusiveSListIterator<T, const T*, const T&> const_iterator;
public:
intrusive_slist(); ///< Creates an empty list.
//intrusive_slist(const this_type& x); ///< Creates an empty list; ignores the argument. To consider: Is this a useful function?
//this_type& operator=(const this_type& x); ///< Clears the list; ignores the argument. To consider: Is this a useful function?
iterator begin(); ///< Returns an iterator pointing to the first element in the list. O(1).
const_iterator begin() const; ///< Returns a const_iterator pointing to the first element in the list. O(1).
const_iterator cbegin() const; ///< Returns a const_iterator pointing to the first element in the list. O(1).
iterator end(); ///< Returns an iterator pointing one-after the last element in the list. O(1).
const_iterator end() const; ///< Returns a const_iterator pointing one-after the last element in the list. O(1).
const_iterator cend() const; ///< Returns a const_iterator pointing one-after the last element in the list. O(1).
iterator before_begin(); ///< Returns iterator to position before begin. O(1).
const_iterator before_begin() const; ///< Returns iterator to previous position. O(1).
const_iterator cbefore_begin() const; ///< Returns iterator to previous position. O(1).
iterator previous(const_iterator position); ///< Returns iterator to previous position. O(n).
const_iterator previous(const_iterator position) const; ///< Returns iterator to previous position. O(n).
reference front(); ///< Returns a reference to the first element. The list must be empty.
const_reference front() const; ///< Returns a const reference to the first element. The list must be empty.
void push_front(value_type& value); ///< Adds an element to the front of the list; O(1). The element is not copied. The element must not be in any other list.
void pop_front(); ///< Removes an element from the back of the list; O(n). The element must be present, but is not deallocated.
bool contains(const value_type& value) const; ///< Returns true if the given element is in the list; O(n). Equivalent to (locate(x) != end()).
iterator locate(value_type& value); ///< Converts a reference to an object in the list back to an iterator, or returns end() if it is not part of the list. O(n)
const_iterator locate(const value_type& value) const; ///< Converts a const reference to an object in the list back to a const iterator, or returns end() if it is not part of the list. O(n)
iterator insert(iterator position, value_type& value); ///< Inserts an element before the element pointed to by the iterator. O(n)
iterator insert_after(iterator position, value_type& value); ///< Inserts an element after the element pointed to by the iterator. O(1)
iterator erase(iterator position); ///< Erases the element pointed to by the iterator. O(n)
iterator erase_after(iterator position); ///< Erases the element after the element pointed to by the iterator. O(1)
iterator erase(iterator first, iterator last); ///< Erases elements within the iterator range [first, last). O(n).
iterator erase_after(iterator before_first, iterator last); ///< Erases elements within the iterator range [before_first, last). O(1).
void swap(this_type& x); ///< Swaps the contents of two intrusive lists; O(1).
void splice(iterator position, value_type& value); ///< Moves the given element into this list before the element pointed to by position; O(n).
///< Required: x must be in some list or have first/next pointers that point it itself.
void splice(iterator position, this_type& x); ///< Moves the contents of a list into this list before the element pointed to by position; O(n).
///< Required: &x != this (same as std::list).
void splice(iterator position, this_type& x, iterator xPosition); ///< Moves the given element pointed to i within the list x into the current list before
///< the element pointed to by position; O(n).
void splice(iterator position, this_type& x, iterator first, iterator last); ///< Moves the range of elements [first, last) from list x into the current list before
///< the element pointed to by position; O(n).
///< Required: position must not be in [first, last). (same as std::list).
void splice_after(iterator position, value_type& value); ///< Moves the given element into this list after the element pointed to by position; O(1).
///< Required: x must be in some list or have first/next pointers that point it itself.
void splice_after(iterator position, this_type& x); ///< Moves the contents of a list into this list after the element pointed to by position; O(n).
///< Required: &x != this (same as std::list).
void splice_after(iterator position, this_type& x, iterator xPrevious); ///< Moves the element after xPrevious to be after position. O(1).
///< Required: &x != this (same as std::list).
void splice_after(iterator position, this_type& x, iterator before_first, iterator before_last); ///< Moves the elements in the range of [before_first+1, before_last+1) to be after position. O(1).
bool validate() const;
int validate_iterator(const_iterator i) const;
}; // intrusive_slist
///////////////////////////////////////////////////////////////////////
// IntrusiveSListIterator
///////////////////////////////////////////////////////////////////////
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSListIterator<T, Pointer, Reference>::IntrusiveSListIterator()
{
#if EASTL_DEBUG
mpNode = NULL;
#endif
}
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSListIterator<T, Pointer, Reference>::IntrusiveSListIterator(pointer pNode)
: mpNode(pNode)
{
}
template <typename T, typename Pointer, typename Reference>
inline IntrusiveSListIterator<T, Pointer, Reference>::IntrusiveSListIterator(const iterator& x)
: mpNode(x.mpNode)
{
}
///////////////////////////////////////////////////////////////////////
// intrusive_slist_base
///////////////////////////////////////////////////////////////////////
// To do.
///////////////////////////////////////////////////////////////////////
// intrusive_slist
///////////////////////////////////////////////////////////////////////
// To do.
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename T>
bool operator==(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
// If we store an mSize member for intrusive_slist, we want to take advantage of it here.
typename intrusive_slist<T>::const_iterator ia = a.begin();
typename intrusive_slist<T>::const_iterator ib = b.begin();
typename intrusive_slist<T>::const_iterator enda = a.end();
typename intrusive_slist<T>::const_iterator endb = b.end();
while((ia != enda) && (ib != endb) && (*ia == *ib))
{
++ia;
++ib;
}
return (ia == enda) && (ib == endb);
}
template <typename T>
bool operator<(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
return eastl::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
}
template <typename T>
bool operator!=(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
return !(a == b);
}
template <typename T>
bool operator>(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
return b < a;
}
template <typename T>
bool operator<=(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
return !(b < a);
}
template <typename T>
bool operator>=(const intrusive_slist<T>& a, const intrusive_slist<T>& b)
{
return !(a < b);
}
template <typename T>
void swap(intrusive_slist<T>& a, intrusive_slist<T>& b)
{
a.swap(b);
}
} // namespace eastl
#endif // Header include guard
+932
View File
@@ -0,0 +1,932 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_LIST_MAP_H
#define EASTL_LIST_MAP_H
#include <EASTL/map.h>
namespace eastl
{
/// EASTL_MAP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_LIST_MAP_DEFAULT_NAME
#define EASTL_LIST_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " list_map" // Unless the user overrides something, this is "EASTL list_map".
#endif
/// EASTL_MAP_DEFAULT_ALLOCATOR
///
#ifndef EASTL_LIST_MAP_DEFAULT_ALLOCATOR
#define EASTL_LIST_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_LIST_MAP_DEFAULT_NAME)
#endif
/// list_map_data_base
///
/// We define a list_map_data_base separately from list_map_data (below), because it
/// allows us to have non-templated operations, and it makes it so that the
/// list_map anchor node doesn't carry a T with it, which would waste space and
/// possibly lead to surprising the user due to extra Ts existing that the user
/// didn't explicitly create. The downside to all of this is that it makes debug
/// viewing of an list_map harder, given that the node pointers are of type
/// list_map_data_base and not list_map_data.
///
struct list_map_data_base
{
list_map_data_base* mpNext;
list_map_data_base* mpPrev;
};
/// list_map_data
///
template <typename Value>
struct list_map_data : public list_map_data_base
{
typedef Value value_type;
list_map_data(const value_type& value);
value_type mValue; // This is a pair of key/value.
};
/// list_map_iterator
///
template <typename T, typename Pointer, typename Reference>
struct list_map_iterator
{
typedef list_map_iterator<T, Pointer, Reference> this_type;
typedef list_map_iterator<T, T*, T&> iterator;
typedef list_map_iterator<T, const T*, const T&> const_iterator;
typedef eastl_size_t size_type; // See config.h for the definition of eastl_size_t, which defaults to size_t.
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef list_map_data_base base_node_type;
typedef list_map_data<T> node_type;
typedef Pointer pointer;
typedef Reference reference;
typedef EASTL_ITC_NS::bidirectional_iterator_tag iterator_category;
public:
node_type* mpNode;
public:
list_map_iterator();
list_map_iterator(const base_node_type* pNode);
list_map_iterator(const iterator& x);
reference operator*() const;
pointer operator->() const;
this_type& operator++();
this_type operator++(int);
this_type& operator--();
this_type operator--(int);
}; // list_map_iterator
/// use_value_first
///
/// operator()(x) simply returns x.mValue.first. Used in list_map.
/// This is similar to eastl::use_first, however it assumes that the input type is an object
/// whose mValue is an eastl::pair, and the first value in the pair is the desired return.
///
template <typename Object>
struct use_value_first
{
typedef Object argument_type;
typedef typename Object::value_type::first_type result_type;
const result_type& operator()(const Object& x) const
{ return x.mValue.first; }
};
/// list_map
///
/// Implements a map like container, which also provides functionality similar to a list.
///
/// Note: Like a map, keys must still be unique. As such, push_back() and push_front() operations
/// return a bool indicating success, or failure if the entry's key is already in use.
///
/// list_map is designed to improve performance for situations commonly implemented as:
/// A map, which must be iterated over to find the oldest entry, or purge expired entries.
/// A list, which must be iterated over to remove a player's record when they sign off.
///
/// list_map requires a little more memory per node than either a list or map alone,
/// and many of list_map's functions have a higher operational cost (CPU time) than their
/// counterparts in list and map. However, as the node count increases, list_map quickly outperforms
/// either a list or a map when find [by-index] and front/back type operations are required.
///
/// In essence, list_map avoids O(n) iterations at the expense of additional costs to quick (O(1) and O(log n) operations:
/// push_front(), push_back(), pop_front() and pop_back() have O(log n) operation time, similar to map::insert(), rather than O(1) time like a list,
/// however, front() and back() maintain O(1) operation time.
///
/// As a canonical example, consider a large backlog of player group invites, which are removed when either:
/// The invitation times out - in main loop: while( !listMap.empty() && listMap.front().IsExpired() ) { listMap.pop_front(); }
/// The player rejects the outstanding invitation - on rejection: iter = listMap.find(playerId); if (iter != listMap.end()) { listMap.erase(iter); }
///
/// For a similar example, consider a high volume pending request container which must:
/// Time out old requests (similar to invites timing out above)
/// Remove requests once they've been handled (similar to rejecting invites above)
///
/// For such usage patterns, the performance benefits of list_map become dramatic with
/// common O(n) operations once the node count rises to hundreds or more.
///
/// When high performance is a priority, Containers with thousands of nodes or more
/// can quickly result in unacceptable performance when executing even infrequenty O(n) operations.
///
/// In order to maintain strong performance, avoid iterating over list_map whenever possible.
///
///////////////////////////////////////////////////////////////////////
/// find_as
/// In order to support the ability to have a tree of strings but
/// be able to do efficiently lookups via char pointers (i.e. so they
/// aren't converted to string objects), we provide the find_as
/// function. This function allows you to do a find with a key of a
/// type other than the tree's key type. See the find_as function
/// for more documentation on this.
///
///////////////////////////////////////////////////////////////////////
/// Pool allocation
/// If you want to make a custom memory pool for a list_map container, your pool
/// needs to contain items of type list_map::node_type. So if you have a memory
/// pool that has a constructor that takes the size of pool items and the
/// count of pool items, you would do this (assuming that MemoryPool implements
/// the Allocator interface):
/// typedef list_map<Widget, int, less<Widget>, MemoryPool> WidgetMap; // Delare your WidgetMap type.
/// MemoryPool myPool(sizeof(WidgetMap::node_type), 100); // Make a pool of 100 Widget nodes.
/// WidgetMap myMap(&myPool); // Create a map that uses the pool.
///
template <typename Key, typename T, typename Compare = eastl::less<Key>, typename Allocator = EASTLAllocatorType>
class list_map
: protected rbtree<Key, eastl::list_map_data<eastl::pair<const Key, T> >, Compare, Allocator, eastl::use_value_first<eastl::list_map_data<eastl::pair<const Key, T> > >, true, true>
{
public:
typedef rbtree<Key, eastl::list_map_data<eastl::pair<const Key, T> >, Compare, Allocator,
eastl::use_value_first<eastl::list_map_data<eastl::pair<const Key, T> > >, true, true> base_type;
typedef list_map<Key, T, Compare, Allocator> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::key_type key_type;
typedef T mapped_type;
typedef typename eastl::pair<const Key, T> value_type; // This is intentionally different from base_type::value_type
typedef value_type& reference;
typedef const value_type& const_reference;
typedef typename base_type::node_type node_type; // Despite the internal and external values being different, we're keeping the node type the same as the base
// in order to allow for pool allocation. See EASTL/map.h for more information.
typedef typename eastl::list_map_iterator<value_type, value_type*, value_type&> iterator; // This is intentionally different from base_type::iterator
typedef typename eastl::list_map_iterator<value_type, const value_type*, const value_type&> const_iterator; // This is intentionally different from base_type::const_iterator
typedef eastl::reverse_iterator<iterator> reverse_iterator;
typedef eastl::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename base_type::allocator_type allocator_type;
typedef typename eastl::pair<iterator, bool> insert_return_type; // This is intentionally removed, as list_map doesn't support insert() functions, in favor of list like push_back and push_front
typedef typename eastl::use_first<value_type> extract_key; // This is intentionally different from base_type::extract_key
using base_type::get_allocator;
using base_type::set_allocator;
using base_type::key_comp;
using base_type::empty;
using base_type::size;
protected:
typedef typename eastl::list_map_data<eastl::pair<const Key, T> > internal_value_type;
protected:
// internal base node, acting as the sentinel for list like behaviors
list_map_data_base mNode;
public:
list_map(const allocator_type& allocator = EASTL_LIST_MAP_DEFAULT_ALLOCATOR);
list_map(const Compare& compare, const allocator_type& allocator = EASTL_MAP_DEFAULT_ALLOCATOR);
// To do: Implement the following:
//list_map(const this_type& x);
//list_map(this_type&& x);
//list_map(this_type&& x, const allocator_type& allocator);
//list_map(std::initializer_list<mapped_type> ilist, const Compare& compare = Compare(), const allocator_type& allocator = EASTL_LIST_MAP_DEFAULT_ALLOCATOR);
//template <typename Iterator>
//list_map(Iterator itBegin, Iterator itEnd);
//this_type& operator=(const this_type& x);
//this_type& operator=(std::initializer_list<mapped_type> ilist);
//this_type& operator=(this_type&& x);
//void swap(this_type& x);
public:
// iterators
iterator begin() EA_NOEXCEPT;
const_iterator begin() const EA_NOEXCEPT;
const_iterator cbegin() const EA_NOEXCEPT;
iterator end() EA_NOEXCEPT;
const_iterator end() const EA_NOEXCEPT;
const_iterator cend() const EA_NOEXCEPT;
reverse_iterator rbegin() EA_NOEXCEPT;
const_reverse_iterator rbegin() const EA_NOEXCEPT;
const_reverse_iterator crbegin() const EA_NOEXCEPT;
reverse_iterator rend() EA_NOEXCEPT;
const_reverse_iterator rend() const EA_NOEXCEPT;
const_reverse_iterator crend() const EA_NOEXCEPT;
public:
// List like methods
reference front();
const_reference front() const;
reference back();
const_reference back() const;
// push_front and push_back which takes in a key/value pair
bool push_front(const value_type& value);
bool push_back(const value_type& value);
// push_front and push_back which take key and value separately, for convenience
bool push_front(const key_type& key, const mapped_type& value);
bool push_back(const key_type& key, const mapped_type& value);
void pop_front();
void pop_back();
public:
// Map like methods
iterator find(const key_type& key);
const_iterator find(const key_type& key) const;
template <typename U, typename Compare2>
iterator find_as(const U& u, Compare2 compare2);
template <typename U, typename Compare2>
const_iterator find_as(const U& u, Compare2 compare2) const;
size_type count(const key_type& key) const;
size_type erase(const key_type& key);
public:
// Shared methods which are common to list and map
iterator erase(const_iterator position);
reverse_iterator erase(const_reverse_iterator position);
void clear();
void reset_lose_memory();
bool validate() const;
int validate_iterator(const_iterator i) const;
public:
// list like functionality which is in consideration for implementation:
// iterator insert(const_iterator position, const value_type& value);
// void remove(const mapped_type& x);
public:
// list like functionality which may be implemented, but is discouraged from implementation:
// due to the liklihood that they would require O(n) time to execute.
// template <typename Predicate>
// void remove_if(Predicate);
// void reverse();
// void sort();
// template<typename Compare>
// void sort(Compare compare);
public:
// map like functionality which list_map does not support, due to abmiguity with list like functionality:
#if !defined(EA_COMPILER_NO_DELETED_FUNCTIONS)
template <typename InputIterator>
list_map(InputIterator first, InputIterator last, const Compare& compare, const allocator_type& allocator = EASTL_RBTREE_DEFAULT_ALLOCATOR) = delete;
insert_return_type insert(const value_type& value) = delete;
iterator insert(const_iterator position, const value_type& value) = delete;
template <typename InputIterator>
void insert(InputIterator first, InputIterator last) = delete;
insert_return_type insert(const key_type& key) = delete;
iterator erase(const_iterator first, const_iterator last) = delete;
reverse_iterator erase(reverse_iterator first, reverse_iterator last) = delete;
void erase(const key_type* first, const key_type* last) = delete;
iterator lower_bound(const key_type& key) = delete;
const_iterator lower_bound(const key_type& key) const = delete;
iterator upper_bound(const key_type& key) = delete;
const_iterator upper_bound(const key_type& key) const = delete;
eastl::pair<iterator, iterator> equal_range(const key_type& key) = delete;
eastl::pair<const_iterator, const_iterator> equal_range(const key_type& key) const = delete;
mapped_type& operator[](const key_type& key) = delete; // Of map, multimap, set, and multimap, only map has operator[].
#endif
public:
// list like functionality which list_map does not support, due to ambiguity with map like functionality:
#if 0
reference push_front() = delete;
void* push_front_uninitialized() = delete;
reference push_back() = delete;
void* push_back_uninitialized() = delete;
iterator insert(const_iterator position) = delete;
void insert(const_iterator position, size_type n, const value_type& value) = delete;
template <typename InputIterator>
void insert(const_iterator position, InputIterator first, InputIterator last) = delete;
iterator erase(const_iterator first, const_iterator last) = delete;
reverse_iterator erase(const_reverse_iterator first, const_reverse_iterator last) = delete;
void splice(const_iterator position, this_type& x) = delete
void splice(const_iterator position, this_type& x, const_iterator i) = delete;
void splice(const_iterator position, this_type& x, const_iterator first, const_iterator last) = delete;
void merge(this_type& x) = delete;
template <typename Compare>
void merge(this_type& x, Compare compare) = delete;
void unique() = delete; // Uniqueness is enforced by map functionality
template <typename BinaryPredicate>
void unique(BinaryPredicate) = delete; // Uniqueness is enforced by map functionality
#endif
}; // list_map
///////////////////////////////////////////////////////////////////////
// list_map_data
///////////////////////////////////////////////////////////////////////
template <typename Value>
inline list_map_data<Value>::list_map_data(const Value& value)
: mValue(value)
{
mpNext = NULL; // GCC 4.8 is generating warnings about referencing these values in list_map::push_front unless we
mpPrev = NULL; // initialize them here. The compiler seems to be mistaken, as our code isn't actually using them unintialized.
}
///////////////////////////////////////////////////////////////////////
// list_map_iterator
///////////////////////////////////////////////////////////////////////
template <typename T, typename Pointer, typename Reference>
inline list_map_iterator<T, Pointer, Reference>::list_map_iterator()
: mpNode(NULL)
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline list_map_iterator<T, Pointer, Reference>::list_map_iterator(const base_node_type* pNode)
: mpNode(static_cast<node_type*>(const_cast<base_node_type*>(pNode)))
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline list_map_iterator<T, Pointer, Reference>::list_map_iterator(const iterator& x)
: mpNode(const_cast<node_type*>(x.mpNode))
{
// Empty
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::reference
list_map_iterator<T, Pointer, Reference>::operator*() const
{
return mpNode->mValue;
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::pointer
list_map_iterator<T, Pointer, Reference>::operator->() const
{
return &mpNode->mValue;
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::this_type&
list_map_iterator<T, Pointer, Reference>::operator++()
{
mpNode = static_cast<node_type*>(mpNode->mpNext);
return *this;
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::this_type
list_map_iterator<T, Pointer, Reference>::operator++(int)
{
this_type temp(*this);
mpNode = static_cast<node_type*>(mpNode->mpNext);
return temp;
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::this_type&
list_map_iterator<T, Pointer, Reference>::operator--()
{
mpNode = static_cast<node_type*>(mpNode->mpPrev);
return *this;
}
template <typename T, typename Pointer, typename Reference>
inline typename list_map_iterator<T, Pointer, Reference>::this_type
list_map_iterator<T, Pointer, Reference>::operator--(int)
{
this_type temp(*this);
mpNode = static_cast<node_type*>(mpNode->mpPrev);
return temp;
}
// We provide additional template paremeters here to support comparisons between const and non-const iterators.
// See C++ defect report #179, or EASTL/list.h for more information.
template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
inline bool operator==(const list_map_iterator<T, PointerA, ReferenceA>& a,
const list_map_iterator<T, PointerB, ReferenceB>& b)
{
return a.mpNode == b.mpNode;
}
template <typename T, typename PointerA, typename ReferenceA, typename PointerB, typename ReferenceB>
inline bool operator!=(const list_map_iterator<T, PointerA, ReferenceA>& a,
const list_map_iterator<T, PointerB, ReferenceB>& b)
{
return a.mpNode != b.mpNode;
}
// We provide a version of operator!= for the case where the iterators are of the
// same type. This helps prevent ambiguity errors in the presence of rel_ops.
template <typename T, typename Pointer, typename Reference>
inline bool operator!=(const list_map_iterator<T, Pointer, Reference>& a,
const list_map_iterator<T, Pointer, Reference>& b)
{
return a.mpNode != b.mpNode;
}
///////////////////////////////////////////////////////////////////////
// list_map
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, typename Compare, typename Allocator>
inline list_map<Key, T, Compare, Allocator>::list_map(const allocator_type& allocator)
: base_type(allocator)
{
mNode.mpNext = &mNode;
mNode.mpPrev = &mNode;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline list_map<Key, T, Compare, Allocator>::list_map(const Compare& compare, const allocator_type& allocator)
: base_type(compare, allocator)
{
mNode.mpNext = &mNode;
mNode.mpPrev = &mNode;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::iterator
list_map<Key, T, Compare, Allocator>::begin() EA_NOEXCEPT
{
return iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::begin() const EA_NOEXCEPT
{
return const_iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::cbegin() const EA_NOEXCEPT
{
return const_iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::iterator
list_map<Key, T, Compare, Allocator>::end() EA_NOEXCEPT
{
return iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::end() const EA_NOEXCEPT
{
return const_iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::cend() const EA_NOEXCEPT
{
return const_iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::reverse_iterator
list_map<Key, T, Compare, Allocator>::rbegin() EA_NOEXCEPT
{
return reverse_iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reverse_iterator
list_map<Key, T, Compare, Allocator>::rbegin() const EA_NOEXCEPT
{
return const_reverse_iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reverse_iterator
list_map<Key, T, Compare, Allocator>::crbegin() const EA_NOEXCEPT
{
return const_reverse_iterator(&mNode);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::reverse_iterator
list_map<Key, T, Compare, Allocator>::rend() EA_NOEXCEPT
{
return reverse_iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reverse_iterator
list_map<Key, T, Compare, Allocator>::rend() const EA_NOEXCEPT
{
return const_reverse_iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reverse_iterator
list_map<Key, T, Compare, Allocator>::crend() const EA_NOEXCEPT
{
return const_reverse_iterator(mNode.mpNext);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::reference
list_map<Key, T, Compare, Allocator>::front()
{
#if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
if (EASTL_UNLIKELY(static_cast<internal_value_type*>(mNode.mpNext) == &mNode))
EASTL_FAIL_MSG("list_map::front -- empty container");
#else
// We allow the user to reference an empty container.
#endif
return static_cast<internal_value_type*>(mNode.mpNext)->mValue;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reference
list_map<Key, T, Compare, Allocator>::front() const
{
#if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
if (EASTL_UNLIKELY(static_cast<internal_value_type*>(mNode.mpNext) == &mNode))
EASTL_FAIL_MSG("list_map::front -- empty container");
#else
// We allow the user to reference an empty container.
#endif
return static_cast<internal_value_type*>(mNode.mpNext)->mValue;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::reference
list_map<Key, T, Compare, Allocator>::back()
{
#if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
if (EASTL_UNLIKELY(static_cast<internal_value_type*>(mNode.mpNext) == &mNode))
EASTL_FAIL_MSG("list_map::back -- empty container");
#else
// We allow the user to reference an empty container.
#endif
return static_cast<internal_value_type*>(mNode.mpPrev)->mValue;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_reference
list_map<Key, T, Compare, Allocator>::back() const
{
#if EASTL_ASSERT_ENABLED && EASTL_EMPTY_REFERENCE_ASSERT_ENABLED
if (EASTL_UNLIKELY(static_cast<internal_value_type*>(mNode.mpNext) == &mNode))
EASTL_FAIL_MSG("list_map::back -- empty container");
#else
// We allow the user to reference an empty container.
#endif
return static_cast<internal_value_type*>(mNode.mpPrev)->mValue;
}
template <typename Key, typename T, typename Compare, typename Allocator>
bool list_map<Key, T, Compare, Allocator>::push_front(const value_type& value)
{
internal_value_type tempValue(value);
typename base_type::insert_return_type baseReturn = base_type::insert(tempValue);
// Did the insert succeed?
if (baseReturn.second)
{
internal_value_type* pNode = &(*baseReturn.first);
pNode->mpNext = mNode.mpNext;
pNode->mpPrev = &mNode;
mNode.mpNext->mpPrev = pNode;
mNode.mpNext = pNode;
return true;
}
else
{
return false;
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
bool list_map<Key, T, Compare, Allocator>::push_back(const value_type& value)
{
internal_value_type tempValue(value);
typename base_type::insert_return_type baseReturn = base_type::insert(tempValue);
// Did the insert succeed?
if (baseReturn.second)
{
internal_value_type* pNode = &(*baseReturn.first);
pNode->mpPrev = mNode.mpPrev;
pNode->mpNext = &mNode;
mNode.mpPrev->mpNext = pNode;
mNode.mpPrev = pNode;
return true;
}
else
{
return false;
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
bool list_map<Key, T, Compare, Allocator>::push_front(const key_type& key, const mapped_type& value)
{
return push_front(eastl::make_pair(key, value));
}
template <typename Key, typename T, typename Compare, typename Allocator>
bool list_map<Key, T, Compare, Allocator>::push_back(const key_type& key, const mapped_type& value)
{
return push_back(eastl::make_pair(key, value));
}
template <typename Key, typename T, typename Compare, typename Allocator>
void list_map<Key, T, Compare, Allocator>::pop_front()
{
#if EASTL_ASSERT_ENABLED
if (EASTL_UNLIKELY(empty()))
EASTL_FAIL_MSG("list_map::pop_front -- empty container");
#endif
erase(static_cast<internal_value_type*>(mNode.mpNext)->mValue.first);
}
template <typename Key, typename T, typename Compare, typename Allocator>
void list_map<Key, T, Compare, Allocator>::pop_back()
{
#if EASTL_ASSERT_ENABLED
if (EASTL_UNLIKELY(empty()))
EASTL_FAIL_MSG("list_map::pop_back -- empty container");
#endif
erase(static_cast<internal_value_type*>(mNode.mpPrev)->mValue.first);
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::iterator
list_map<Key, T, Compare, Allocator>::find(const key_type& key)
{
typename base_type::iterator baseIter = base_type::find(key);
if (baseIter != base_type::end())
{
return iterator(&(*baseIter));
}
else
{
return end();
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::find(const key_type& key) const
{
typename base_type::const_iterator baseIter = base_type::find(key);
if (baseIter != base_type::end())
{
return const_iterator(&(*baseIter));
}
else
{
return end();
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
template <typename U, typename Compare2>
inline typename list_map<Key, T, Compare, Allocator>::iterator
list_map<Key, T, Compare, Allocator>::find_as(const U& u, Compare2 compare2)
{
typename base_type::iterator baseIter = base_type::find_as(u, compare2);
if (baseIter != base_type::end())
{
return iterator(&(*baseIter));
}
else
{
return end();
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
template <typename U, typename Compare2>
inline typename list_map<Key, T, Compare, Allocator>::const_iterator
list_map<Key, T, Compare, Allocator>::find_as(const U& u, Compare2 compare2) const
{
typename base_type::const_iterator baseIter = base_type::find_as(u, compare2);
if (baseIter != base_type::end())
{
return const_iterator(&(*baseIter));
}
else
{
return end();
}
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::size_type
list_map<Key, T, Compare, Allocator>::count(const key_type& key) const
{
const typename base_type::const_iterator it = base_type::find(key);
return (it != base_type::end()) ? 1 : 0;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::size_type
list_map<Key, T, Compare, Allocator>::erase(const key_type& key)
{
typename base_type::iterator baseIter = base_type::find(key);
if (baseIter != base_type::end())
{
internal_value_type* node = &(*baseIter);
node->mpNext->mpPrev = node->mpPrev;
node->mpPrev->mpNext = node->mpNext;
base_type::erase(baseIter);
return 1;
}
return 0;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::iterator
list_map<Key, T, Compare, Allocator>::erase(const_iterator position)
{
iterator posIter(position.mpNode); // Convert from const.
iterator eraseIter(posIter++);
erase(eraseIter->first);
return posIter;
}
template <typename Key, typename T, typename Compare, typename Allocator>
inline typename list_map<Key, T, Compare, Allocator>::reverse_iterator
list_map<Key, T, Compare, Allocator>::erase(const_reverse_iterator position)
{
return reverse_iterator(erase((++position).base()));
}
template <typename Key, typename T, typename Compare, typename Allocator>
void list_map<Key, T, Compare, Allocator>::clear()
{
base_type::clear();
mNode.mpNext = &mNode;
mNode.mpPrev = &mNode;
}
template <typename Key, typename T, typename Compare, typename Allocator>
void list_map<Key, T, Compare, Allocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
mNode.mpNext = &mNode;
mNode.mpPrev = &mNode;
}
template <typename Key, typename T, typename Compare, typename Allocator>
bool list_map<Key, T, Compare, Allocator>::validate() const
{
if (!base_type::validate())
{
return false;
}
size_type nodeCount(0);
list_map_data_base* node = mNode.mpNext;
while (node != &mNode)
{
internal_value_type* data = static_cast<internal_value_type*>(node);
if (base_type::find(data->mValue.first) == base_type::end())
{
return false;
}
node = node->mpNext;
++nodeCount;
}
if (nodeCount != size())
{
return false;
}
nodeCount = 0;
node = mNode.mpPrev;
while (node != &mNode)
{
internal_value_type* data = static_cast<internal_value_type*>(node);
if (base_type::find(data->mValue.first) == base_type::end())
{
return false;
}
node = node->mpPrev;
++nodeCount;
}
if (nodeCount != size())
{
return false;
}
return true;
}
template <typename Key, typename T, typename Compare, typename Allocator>
int list_map<Key, T, Compare, Allocator>::validate_iterator(const_iterator iter) const
{
for (const_iterator temp = begin(), tempEnd = end(); temp != tempEnd; ++temp)
{
if (temp == iter)
{
return (isf_valid | isf_current | isf_can_dereference);
}
}
if (iter == end())
return (isf_valid | isf_current);
return isf_none;
}
} // namespace eastl
#endif // Header include guard
+424
View File
@@ -0,0 +1,424 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// lru_cache is a container that simplifies caching of objects in a map.
// Basically, you give the container a key, like a string, and the data you want.
// The container provides callback mechanisms to generate data if it's missing
// as well as delete data when it's purged from the cache. This container
// uses a least recently used method: whatever the oldest item is will be
// replaced with a new entry.
//
// Algorithmically, the container is a combination of a map and a list.
// The list stores the age of the entries by moving the entry to the head
// of the list on each access, either by a call to get() or to touch().
// The map is just the map as one would expect.
//
// This is useful for caching off data that is expensive to generate,
// for example text to speech wave files that are dynamically generated,
// but that will need to be reused, as is the case in narration of menu
// entries as a user scrolls through the entries.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_LRUCACHE_H
#define EASTL_LRUCACHE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/list.h>
#include <EASTL/unordered_map.h>
#include <EASTL/optional.h>
namespace eastl
{
/// EASTL_LRUCACHE_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_LRUCACHE_DEFAULT_NAME
#define EASTL_LRUCACHE_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " lru_cache" // Unless the user overrides something, this is "EASTL lru_cache".
#endif
/// EASTL_LRUCACHE_DEFAULT_ALLOCATOR
///
#ifndef EASTL_LRUCACHE_DEFAULT_ALLOCATOR
#define EASTL_LRUCACHE_DEFAULT_ALLOCATOR allocator_type(EASTL_LRUCACHE_DEFAULT_NAME)
#endif
/// lru_cache
///
/// Implements a caching map based off of a key and data.
/// LRUList parameter is any container that guarantees the validity of its iterator even after a modification (e.g. list)
/// LRUMap is any mapping container that can map a key to some data. By default, we use unordered_set, but it might be better
/// to use hash_map or some other structure depending on your key/data combination. For example, you may want to swap the
/// map backing if using strings as keys or if the data objects are small. In any case, unordered_set is a good default and should
/// work well enough since the purpose of this class is to cache results of expensive, order of milliseconds, operations
///
/// Algorithmic Performance (default data structures):
/// touch() -> O(1)
/// insert() / update(), get() / operator[] -> equivalent to unordered_set (O(1) on average, O(n) worst)
/// size() -> O(1)
///
/// All accesses to a given key (insert, update, get) will push that key to most recently used.
/// If the data objects are shared between threads, it would be best to use a smartptr to manage the lifetime of the data.
/// as it could be removed from the cache while in use by another thread.
template <typename Key,
typename Value,
typename Allocator = EASTLAllocatorType,
typename list_type = eastl::list<Key, Allocator>,
typename map_type = eastl::unordered_map<Key,
eastl::pair<Value, typename list_type::iterator>,
eastl::hash<Key>,
eastl::equal_to<Key>,
Allocator>>
class lru_cache
{
public:
using key_type = Key;
using value_type = Value;
using allocator_type = Allocator;
using size_type = eastl_size_t;
using list_iterator = typename list_type::iterator;
using map_iterator = typename map_type::iterator;
using data_container_type = eastl::pair<value_type, list_iterator>;
using iterator = typename map_type::iterator;
using const_iterator = typename map_type::const_iterator;
using this_type = lru_cache<key_type, value_type, Allocator, list_type, map_type>;
using create_callback_type = eastl::function<value_type(key_type)>;
using delete_callback_type = eastl::function<void(const value_type &)>;
/// lru_cache constructor
///
/// Creates a Key / Value map that only stores size Value objects until it deletes them.
/// For complex objects or operations, the creator and deletor callbacks can be used.
/// This works just like a regular map object: on access, the Value will be created if it doesn't exist, returned otherwise.
explicit lru_cache(size_type size,
const allocator_type& allocator = EASTL_LRUCACHE_DEFAULT_ALLOCATOR,
create_callback_type creator = nullptr,
delete_callback_type deletor = nullptr)
: m_list(allocator)
, m_map(allocator)
, m_capacity(size)
, m_create_callback(creator)
, m_delete_callback(deletor)
{
}
/// lru_cache destructor
///
/// Iterates across every entry in the map and calls the deletor before calling the standard destructors
~lru_cache()
{
// Destruct everything we have cached
for (auto& iter : m_map)
{
if (m_delete_callback)
m_delete_callback(iter.second.first);
}
}
lru_cache(std::initializer_list<eastl::pair<Key, Value>> il)
: lru_cache(static_cast<size_type>(il.size()))
{
for(auto& p : il)
insert_or_assign(p.first, p.second);
}
// TODO(rparolin): Why do we prevent copies? And what about moves?
lru_cache(const this_type&) = delete;
this_type &operator=(const this_type&) = delete;
/// insert
///
/// insert key k with value v.
/// If key already exists, no change is made and the return value is false.
/// If the key doesn't exist, the data is added to the map and the return value is true.
bool insert(const key_type& k, const value_type& v)
{
if (m_map.find(k) == m_map.end())
{
make_space();
m_list.push_front(k);
m_map[k] = data_container_type(v, m_list.begin());
return true;
}
else
{
return false;
}
}
/// emplace
///
/// Places a new object in place k created with args
/// If the key already exists, it is replaced.
template <typename... Args>
void emplace(const key_type& k, Args&&... args)
{
make_space();
m_list.push_front(k);
m_map.emplace(k, data_container_type(eastl::forward<Args>(args)..., m_list.begin()));
}
/// insert_or_assign
///
/// Same as add, but replaces the data at key k, if it exists, with the new entry v
/// Note that the deletor for the old v will be called before it's replaced with the new value of v
void insert_or_assign(const key_type& k, const value_type& v)
{
auto iter = m_map.find(k);
if (m_map.find(k) != m_map.end())
{
assign(iter, v);
}
else
{
insert(k, v);
}
}
/// contains
///
/// Returns true if key k exists in the cache
bool contains(const key_type& k) const
{
return m_map.find(k) != m_map.end();
}
/// at
///
/// Retrives the data for key k, not valid if k does not exist
eastl::optional<value_type> at(const key_type& k)
{
auto iter = m_map.find(k);
if (iter != m_map.end())
{
return iter->second.first;
}
else
{
return eastl::nullopt;
}
}
/// get
///
/// Retrives the data for key k. If no data exists, it will be created by calling the
/// creator.
value_type& get(const key_type& k)
{
auto iter = m_map.find(k);
// The entry exists in the cache
if (iter != m_map.end())
{
touch(k);
return iter->second.first;
}
else // The entry doesn't exist in the cache, so create one
{
// Add the entry to the map
insert(k, m_create_callback ? m_create_callback(k) : value_type());
// return the new data
return m_map[k].first;
}
}
/// Equivalent to get(k)
value_type& operator[](const key_type& k) { return get(k); }
/// erase
///
/// erases key k from the cache.
/// If k does not exist, returns false. If k exists, returns true.
bool erase(const key_type& k)
{
auto iter = m_map.find(k);
if (iter != m_map.end())
{
m_list.erase(iter->second.second);
// Delete the actual entry
map_erase(iter);
return true;
}
return false;
}
/// erase_oldest
///
/// Removes the oldest entry from the cache.
void erase_oldest()
{
auto key = m_list.back();
m_list.pop_back();
// Delete the actual entry
auto iter = m_map.find(key);
map_erase(iter);
}
/// touch
///
/// Touches key k, marking it as most recently used.
/// If k does not exist, returns false. If the touch was successful, returns true.
bool touch(const key_type& k)
{
auto iter = m_map.find(k);
if (iter != m_map.end())
{
touch(iter);
return true;
}
return false;
}
/// touch
///
/// Touches key at iterator iter, moving it to most recently used position
void touch(iterator& iter)
{
auto listRef = iter->second.second;
m_list.erase(listRef);
m_list.push_front(iter->first);
iter->second.second = m_list.begin();
}
/// assign
///
/// Updates key k with data v.
/// If key k does not exist, returns false and no changes are made.
/// If key k exists, existing data has its deletor called and key k's data is replaced with new v data
bool assign(const key_type& k, const value_type& v)
{
auto iter = m_map.find(k);
if (iter != m_map.end())
{
assign(iter, v);
return true;
}
return false;
}
/// assign
///
/// Updates data at spot iter with data v.
void assign(iterator& iter, const value_type& v)
{
if (m_delete_callback)
m_delete_callback(iter->second.first);
touch(iter);
iter->second.first = v;
}
// standard container functions
iterator begin() EA_NOEXCEPT { return m_map.begin(); }
iterator end() EA_NOEXCEPT { return m_map.end(); }
iterator rbegin() EA_NOEXCEPT { return m_map.rbegin(); }
iterator rend() EA_NOEXCEPT { return m_map.rend(); }
const_iterator begin() const EA_NOEXCEPT { return m_map.begin(); }
const_iterator cbegin() const EA_NOEXCEPT { return m_map.cbegin(); }
const_iterator crbegin() const EA_NOEXCEPT { return m_map.crbegin(); }
const_iterator end() const EA_NOEXCEPT { return m_map.end(); }
const_iterator cend() const EA_NOEXCEPT { return m_map.cend(); }
const_iterator crend() const EA_NOEXCEPT { return m_map.crend(); }
bool empty() const EA_NOEXCEPT { return m_map.empty(); }
size_type size() const EA_NOEXCEPT { return m_map.size(); }
size_type capacity() const EA_NOEXCEPT { return m_capacity; }
void clear() EA_NOEXCEPT
{
// Since we have a delete callback, we want to reuse the trim function by cheating the max
// size to clear all the entries to avoid duplicating code.
auto old_max = m_capacity;
m_capacity = 0;
trim();
m_capacity = old_max;
}
/// resize
///
/// Resizes the cache. Can be used to either expand or contract the cache.
/// In the case of a contraction, the oldest entries will be evicted with their respective
/// deletors called before completing.
void resize(size_type newSize)
{
m_capacity = newSize;
trim();
}
void setCreateCallback(create_callback_type callback) { m_create_callback = callback; }
void setDeleteCallback(delete_callback_type callback) { m_delete_callback = callback; }
// EASTL extensions
const allocator_type& get_allocator() const EA_NOEXCEPT { return m_map.get_allocator(); }
allocator_type& get_allocator() EA_NOEXCEPT { return m_map.get_allocator(); }
void set_allocator(const allocator_type& allocator) { m_map.set_allocator(allocator); m_list.set_allocator(allocator); }
/// Does not reset the callbacks
void reset_lose_memory() EA_NOEXCEPT { m_map.reset_lose_memory(); m_list.reset_lose_memory(); }
private:
inline void map_erase(map_iterator pos)
{
if (m_delete_callback)
m_delete_callback(pos->second.first);
m_map.erase(pos);
}
bool trim()
{
if (size() <= m_capacity)
{
return false; // No trim necessary
}
// We need to trim
do
{
erase_oldest();
} while (m_list.size() > m_capacity);
return true;
}
void make_space()
{
if (size() == m_capacity)
{
erase_oldest();
}
}
private:
list_type m_list;
map_type m_map;
size_type m_capacity;
create_callback_type m_create_callback;
delete_callback_type m_delete_callback;
};
}
#endif
+81
View File
@@ -0,0 +1,81 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_OVERLOADED_H
#define EASTL_OVERLOADED_H
#include <EASTL/internal/move_help.h>
#include <EASTL/type_traits.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
namespace eastl
{
///////////////////////////////////////////////////////////////////////////
/// overloaded
///
/// A helper class that permits you to combine multiple function objects into one.
/// Typically, this helper is really handy when visiting an eastl::variant with multiple lambdas.
/// Example:
///
/// eastl::variant<int, string> v{42};
///
/// eastl::visit(
/// eastl::overloaded{
/// [](const int& x) { std::cout << "Visited an integer: " << x << "\n"; }, // Will reach that lambda with x == 42.
/// [](const string& s) { std::cout << "Visited an string: " << s << "\n"; }
/// },
/// v
/// );
///////////////////////////////////////////////////////////////////////////
template <class... T>
struct overloaded;
template <class T>
struct overloaded<T> : T
{
template <class U>
EA_CPP14_CONSTEXPR overloaded(U&& u) : T(eastl::forward<U>(u))
{
}
using T::operator();
};
template <class T, class... R>
struct overloaded<T, R...> : T, overloaded<R...>
{
template <class U, class... V>
EA_CPP14_CONSTEXPR overloaded(U&& u, V&&... v) : T(eastl::forward<U>(u)), overloaded<R...>(eastl::forward<V>(v)...)
{
}
using T::operator();
using overloaded<R...>::operator();
};
#ifdef __cpp_deduction_guides
template <class... T>
overloaded(T...) -> overloaded<T...>;
#endif
///////////////////////////////////////////////////////////////////////////
/// make_overloaded
///
/// Helper function to create an overloaded instance when lacking deduction guides.
/// make_overloaded(f1, f2, f3) == overloaded{f1, f2, f3}
///////////////////////////////////////////////////////////////////////////
template <class... T>
EA_CPP14_CONSTEXPR overloaded<typename eastl::remove_cvref<T>::type...> make_overloaded(T&&... t)
{
return overloaded<typename eastl::remove_cvref<T>::type...>{eastl::forward<T>(t)...};
}
} // namespace eastl
#endif // EASTL_OVERLOADED_H
File diff suppressed because it is too large Load Diff
+204
View File
@@ -0,0 +1,204 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// This file implements additional sort algorithms beyond the basic set.
// Included here are:
// selection_sort -- Unstable.
// shaker_sort -- Stable.
// bucket_sort -- Stable.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_SORT_EXTRA_H
#define EASTL_SORT_EXTRA_H
#include <EASTL/internal/config.h>
#include <EASTL/iterator.h>
#include <EASTL/algorithm.h>
#include <EASTL/functional.h>
#include <EASTL/heap.h>
#include <EASTL/sort.h> // For backwards compatibility due to sorts moved from here to sort.h.
#include <EASTL/allocator.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
namespace eastl
{
/// selection_sort
///
/// Implements the SelectionSort algorithm.
///
template <typename ForwardIterator, typename StrictWeakOrdering>
void selection_sort(ForwardIterator first, ForwardIterator last, StrictWeakOrdering compare)
{
ForwardIterator iCurrent, iMin;
for(; first != last; ++first)
{
iCurrent = first;
iMin = iCurrent;
for(++iCurrent; iCurrent != last; ++iCurrent)
{
if(compare(*iCurrent, *iMin))
{
EASTL_VALIDATE_COMPARE(!compare(*iMin, *iCurrent)); // Validate that the compare function is sane.
iMin = iCurrent;
}
}
if(first != iMin)
eastl::iter_swap(first, iMin);
}
} // selection_sort
template <typename ForwardIterator>
inline void selection_sort(ForwardIterator first, ForwardIterator last)
{
typedef eastl::less<typename eastl::iterator_traits<ForwardIterator>::value_type> Less;
eastl::selection_sort<ForwardIterator, Less>(first, last, Less());
}
/// shaker_sort
///
/// Implements the ShakerSort algorithm, which is a sorting algorithm which
/// improves on bubble_sort by sweeping both from left to right and right
/// to left, resulting in less iteration.
///
template <typename BidirectionalIterator, typename StrictWeakOrdering>
void shaker_sort(BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering compare)
{
if(first != last)
{
BidirectionalIterator iCurrent, iNext, iLastModified;
--last;
while(first != last)
{
iLastModified = first;
for(iCurrent = first; iCurrent != last; iCurrent = iNext)
{
iNext = iCurrent;
++iNext;
if(compare(*iNext, *iCurrent))
{
EASTL_VALIDATE_COMPARE(!compare(*iCurrent, *iNext)); // Validate that the compare function is sane.
iLastModified = iCurrent;
eastl::iter_swap(iCurrent, iNext);
}
}
last = iLastModified;
if(first != last)
{
for(iCurrent = last; iCurrent != first; iCurrent = iNext)
{
iNext = iCurrent;
--iNext;
if(compare(*iCurrent, *iNext))
{
EASTL_VALIDATE_COMPARE(!compare(*iNext, *iCurrent)); // Validate that the compare function is sane.
iLastModified = iCurrent;
eastl::iter_swap(iNext, iCurrent);
}
}
first = iLastModified;
}
}
}
} // shaker_sort
template <typename BidirectionalIterator>
inline void shaker_sort(BidirectionalIterator first, BidirectionalIterator last)
{
typedef eastl::less<typename eastl::iterator_traits<BidirectionalIterator>::value_type> Less;
eastl::shaker_sort<BidirectionalIterator, Less>(first, last, Less());
}
/// bucket_sort
///
/// Implements the BucketSort algorithm.
///
/// Example usage:
/// const size_t kElementRange = 32;
/// vector<int> intArray(1000);
///
/// for(int i = 0; i < 1000; i++)
/// intArray[i] = rand() % kElementRange;
///
/// vector< vector<int> > bucketArray(kElementRange);
/// bucket_sort(intArray.begin(), intArray.end(), bucketArray, eastl::hash_use_self<int>());
///
template <typename T>
struct hash_use_self
{
T operator()(const T& x) const
{ return x; }
};
// Requires buckeyArray to be an array of arrays with a size equal to the range of values
// returned by the hash function. The hash function is required to return a unique value
// for each uniquely sorted element. Usually the way this is done is the elements are
// integers of a limited range (e.g. 0-64) and the hash function returns the element value
// itself. If you had a case where all elements were always even numbers (e.g. 0-128),
// you could use a custom hash function that returns (element value / 2).
//
// The user is required to provide an empty bucketArray to this function. This function returns
// with the bucketArray non-empty. This function doesn't clear the bucketArray because that takes
// time and the user might not need it to be cleared, at least at that time.
//
template <typename ForwardIterator, typename ContainerArray, typename HashFunction>
void bucket_sort(ForwardIterator first, ForwardIterator last, ContainerArray& bucketArray, HashFunction hash /*= hash_use_self*/)
{
for(ForwardIterator iInput = first; iInput != last; ++iInput)
bucketArray[hash(*iInput)].push_back(*iInput);
for(typename ContainerArray::const_iterator iBucket = bucketArray.begin(); iBucket != bucketArray.end(); ++iBucket)
first = eastl::copy((*iBucket).begin(), (*iBucket).end(), first);
}
} // namespace eastl
#endif // Header include guard
File diff suppressed because it is too large Load Diff
+759
View File
@@ -0,0 +1,759 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements the eastl::chrono specification which is part of the
// standard STL date and time library. eastl::chrono implements all the
// mechanisms required to capture and manipulate times retrieved from the
// provided clocks. It implements the all of the features to allow type safe
// durations to be used in code.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_CHRONO_H
#define EASTL_CHRONO_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/config.h>
#include <EASTL/type_traits.h>
#include <EASTL/numeric_limits.h>
#include <EASTL/ratio.h>
// TODO: move to platform specific cpp or header file
#if defined EA_PLATFORM_MICROSOFT
EA_DISABLE_ALL_VC_WARNINGS()
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#undef NOMINMAX
#define NOMINMAX
#include <Windows.h>
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
EA_RESTORE_ALL_VC_WARNINGS()
#endif
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
// Nothing to do
#elif defined(EA_PLATFORM_APPLE)
#include <mach/mach_time.h>
#elif defined(EA_PLATFORM_POSIX) || defined(EA_PLATFORM_MINGW) || defined(EA_PLATFORM_ANDROID)
// Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if defined(EA_PLATFORM_MINGW)
#include <pthread_time.h>
#endif
#include <time.h>
#if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
#include <errno.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#endif
namespace eastl
{
namespace chrono
{
///////////////////////////////////////////////////////////////////////////////
// treat_as_floating_point
///////////////////////////////////////////////////////////////////////////////
template <class Rep>
struct treat_as_floating_point : is_floating_point<Rep> {};
///////////////////////////////////////////////////////////////////////////////
// 20.12.4, duration_values
///////////////////////////////////////////////////////////////////////////////
template <class Rep>
struct duration_values
{
public:
EASTL_FORCE_INLINE static EA_CONSTEXPR Rep zero() { return Rep(0); }
EASTL_FORCE_INLINE static EA_CONSTEXPR Rep max() { return eastl::numeric_limits<Rep>::max(); }
EASTL_FORCE_INLINE static EA_CONSTEXPR Rep min() { return eastl::numeric_limits<Rep>::lowest(); }
};
///////////////////////////////////////////////////////////////////////////////
// duration fwd_decl
///////////////////////////////////////////////////////////////////////////////
template <typename Rep, typename Period = ratio<1>>
class duration;
namespace Internal
{
///////////////////////////////////////////////////////////////////////////////
// IsRatio
///////////////////////////////////////////////////////////////////////////////
template <typename> struct IsRatio : eastl::false_type {};
template <intmax_t N, intmax_t D> struct IsRatio<ratio<N, D>> : eastl::true_type {};
template <intmax_t N, intmax_t D> struct IsRatio<const ratio<N, D>> : eastl::true_type {};
template <intmax_t N, intmax_t D> struct IsRatio<volatile ratio<N, D>> : eastl::true_type {};
template <intmax_t N, intmax_t D> struct IsRatio<const volatile ratio<N, D>> : eastl::true_type {};
///////////////////////////////////////////////////////////////////////////////
// IsDuration
///////////////////////////////////////////////////////////////////////////////
template<typename> struct IsDuration : eastl::false_type{};
template<typename Rep, typename Period> struct IsDuration<duration<Rep, Period>> : eastl::true_type{};
template<typename Rep, typename Period> struct IsDuration<const duration<Rep, Period>> : eastl::true_type{};
template<typename Rep, typename Period> struct IsDuration<volatile duration<Rep, Period>> : eastl::true_type{};
template<typename Rep, typename Period> struct IsDuration<const volatile duration<Rep, Period>> : eastl::true_type{};
///////////////////////////////////////////////////////////////////////////////
// RatioGCD
///////////////////////////////////////////////////////////////////////////////
template <class Period1, class Period2>
struct RatioGCD
{
static_assert(IsRatio<Period1>::value, "Period1 is not a eastl::ratio type");
static_assert(IsRatio<Period2>::value, "Period2 is not a eastl::ratio type");
typedef ratio<eastl::Internal::gcd<Period1::num, Period2::num>::value,
eastl::Internal::lcm<Period1::den, Period2::den>::value> type;
};
};
///////////////////////////////////////////////////////////////////////////////
// 20.12.5.7, duration_cast
///////////////////////////////////////////////////////////////////////////////
namespace Internal
{
template <typename FromDuration,
typename ToDuration,
typename CommonPeriod =
typename ratio_divide<typename FromDuration::period, typename ToDuration::period>::type,
typename CommonRep = typename eastl::decay<typename eastl::common_type<typename ToDuration::rep,
typename FromDuration::rep,
intmax_t>::type>::type,
bool = CommonPeriod::num == 1,
bool = CommonPeriod::den == 1>
struct DurationCastImpl;
template <typename FromDuration, typename ToDuration, typename CommonPeriod, typename CommonRep>
struct DurationCastImpl<FromDuration, ToDuration, CommonPeriod, CommonRep, true, true>
{
inline static ToDuration DoCast(const FromDuration& fd)
{
return ToDuration(static_cast<typename ToDuration::rep>(fd.count()));
}
};
template <typename FromDuration, typename ToDuration, typename CommonPeriod, typename CommonRep>
struct DurationCastImpl<FromDuration, ToDuration, CommonPeriod, CommonRep, false, true>
{
inline static ToDuration DoCast(const FromDuration& d)
{
return ToDuration(static_cast<typename ToDuration::rep>(static_cast<CommonRep>(d.count()) *
static_cast<CommonRep>(CommonPeriod::num)));
}
};
template <typename FromDuration, typename ToDuration, typename CommonPeriod, typename CommonRep>
struct DurationCastImpl<FromDuration, ToDuration, CommonPeriod, CommonRep, true, false>
{
inline static ToDuration DoCast(const FromDuration& d)
{
return ToDuration(static_cast<typename ToDuration::rep>(static_cast<CommonRep>(d.count()) /
static_cast<CommonRep>(CommonPeriod::den)));
}
};
template <typename FromDuration, typename ToDuration, typename CommonPeriod, typename CommonRep>
struct DurationCastImpl<FromDuration, ToDuration, CommonPeriod, CommonRep, false, false>
{
inline static ToDuration DoCast(const FromDuration& d)
{
return ToDuration(static_cast<typename ToDuration::rep>(static_cast<CommonRep>(d.count()) *
static_cast<CommonRep>(CommonPeriod::num) /
static_cast<CommonRep>(CommonPeriod::den)));
}
};
}; // namespace Internal
///////////////////////////////////////////////////////////////////////////////
// duration_cast
///////////////////////////////////////////////////////////////////////////////
template <typename ToDuration, typename Rep, typename Period>
inline typename eastl::enable_if<Internal::IsDuration<ToDuration>::value, ToDuration>::type
duration_cast(const duration<Rep, Period>& d)
{
typedef typename duration<Rep, Period>::this_type FromDuration;
return Internal::DurationCastImpl<FromDuration, ToDuration>::DoCast(d);
}
///////////////////////////////////////////////////////////////////////////////
// duration
///////////////////////////////////////////////////////////////////////////////
template <class Rep, class Period>
class duration
{
Rep mRep;
public:
typedef Rep rep;
typedef Period period;
typedef duration<Rep, Period> this_type;
#if defined(EA_COMPILER_NO_DEFAULTED_FUNCTIONS)
EA_CONSTEXPR duration()
: mRep() {}
duration(const duration& other)
: mRep(Rep(other.mRep)) {}
duration& operator=(const duration& other)
{ mRep = other.mRep; return *this; }
#else
EA_CONSTEXPR duration() = default;
duration(const duration&) = default;
duration& operator=(const duration&) = default;
#endif
///////////////////////////////////////////////////////////////////////////////
// conversion constructors
///////////////////////////////////////////////////////////////////////////////
template <class Rep2>
inline EA_CONSTEXPR explicit duration(
const Rep2& rep2,
typename eastl::enable_if<eastl::is_convertible<Rep2, Rep>::value &&
(treat_as_floating_point<Rep>::value ||
!treat_as_floating_point<Rep2>::value)>::type** = 0)
: mRep(static_cast<Rep>(rep2)) {}
template <class Rep2, class Period2>
EA_CONSTEXPR duration(const duration<Rep2, Period2>& d2,
typename eastl::enable_if<treat_as_floating_point<Rep>::value ||
(eastl::ratio_divide<Period2, Period>::type::den == 1 &&
!treat_as_floating_point<Rep2>::value),
void>::type** = 0)
: mRep(duration_cast<duration>(d2).count()) {}
///////////////////////////////////////////////////////////////////////////////
// returns the count of ticks
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR Rep count() const { return mRep; }
///////////////////////////////////////////////////////////////////////////////
// static accessors of special duration values
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR inline static duration zero() { return duration(duration_values<Rep>::zero()); }
EA_CONSTEXPR inline static duration min() { return duration(duration_values<Rep>::min()); }
EA_CONSTEXPR inline static duration max() { return duration(duration_values<Rep>::max()); }
///////////////////////////////////////////////////////////////////////////////
// const arithmetic operations
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR inline duration operator+() const { return *this; }
EA_CONSTEXPR inline duration operator-() const { return duration(0-mRep); }
///////////////////////////////////////////////////////////////////////////////
// arithmetic operations
///////////////////////////////////////////////////////////////////////////////
inline duration operator++(int) { return duration(mRep++); }
inline duration operator--(int) { return duration(mRep--); }
inline duration& operator++() { ++mRep; return *this; }
inline duration& operator--() { --mRep; return *this; }
inline duration& operator+=(const duration& d) { mRep += d.count(); return *this; }
inline duration& operator-=(const duration& d) { mRep -= d.count(); return *this; }
inline duration& operator*=(const Rep& rhs) { mRep *= rhs; return *this; }
inline duration& operator/=(const Rep& rhs) { mRep /= rhs; return *this; }
inline duration& operator%=(const Rep& rhs) { mRep %= rhs; return *this; }
inline duration& operator%=(const duration& d) { mRep %= d.count(); return *this; }
};
///////////////////////////////////////////////////////////////////////////////
// 20.12.5.5, arithmetic operations with durations as arguments
///////////////////////////////////////////////////////////////////////////////
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type EASTL_FORCE_INLINE
operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(common_duration_t(lhs).count() + common_duration_t(rhs).count());
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type EASTL_FORCE_INLINE
operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(common_duration_t(lhs).count() - common_duration_t(rhs).count());
}
template <typename Rep1, typename Period1, typename Rep2>
duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> EASTL_FORCE_INLINE
operator*(const duration<Rep1, Period1>& lhs, const Rep2& rhs)
{
typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> common_duration_t;
return common_duration_t(common_duration_t(lhs).count() * rhs);
}
template <typename Rep1, typename Rep2, typename Period2>
duration<typename eastl::common_type<Rep1, Rep2>::type, Period2> EASTL_FORCE_INLINE
operator*(const Rep1& lhs, const duration<Rep2, Period2>& rhs)
{
typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period2> common_duration_t;
return common_duration_t(lhs * common_duration_t(rhs).count());
}
template <typename Rep1, typename Period1, typename Rep2>
duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> EASTL_FORCE_INLINE
operator/(const duration<Rep1, Period1>& lhs, const Rep2& rhs)
{
typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> common_duration_t;
return common_duration_t(common_duration_t(lhs).count() / rhs);
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type EASTL_FORCE_INLINE
operator/(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(common_duration_t(lhs).count() / common_duration_t(rhs).count());
}
template <typename Rep1, typename Period1, typename Rep2>
duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> EASTL_FORCE_INLINE
operator%(const duration<Rep1, Period1>& lhs, const Rep2& rhs)
{
typedef duration<typename eastl::common_type<Rep1, Rep2>::type, Period1> common_duration_t;
return common_duration_t(common_duration_t(lhs).count() % rhs);
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type EASTL_FORCE_INLINE
operator%(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(common_duration_t(lhs).count() % common_duration_t(rhs).count());
}
///////////////////////////////////////////////////////////////////////////////
// 20.12.5.6, compares two durations
///////////////////////////////////////////////////////////////////////////////
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator==(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(lhs).count() == common_duration_t(rhs).count();
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator<(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
typedef typename eastl::common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type common_duration_t;
return common_duration_t(lhs).count() < common_duration_t(rhs).count();
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator!=(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
return !(lhs == rhs);
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator<=(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
return !(rhs < lhs);
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator>(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
return rhs < lhs;
}
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
EASTL_FORCE_INLINE bool operator>=(const duration<Rep1, Period1>& lhs,
const duration<Rep2, Period2>& rhs)
{
return !(lhs < rhs);
}
///////////////////////////////////////////////////////////////////////////////
// standard duration units
///////////////////////////////////////////////////////////////////////////////
typedef duration<int64_t, nano> nanoseconds;
typedef duration<int64_t, micro> microseconds;
typedef duration<int64_t, milli> milliseconds;
typedef duration<int64_t> seconds;
typedef duration<int, ratio<60>> minutes;
typedef duration<int, ratio<3600>> hours;
///////////////////////////////////////////////////////////////////////////////
// 20.12.6, time_point
///////////////////////////////////////////////////////////////////////////////
template <typename Clock, typename Duration = typename Clock::duration>
class time_point
{
Duration mDuration;
public:
typedef Clock clock;
typedef Duration duration;
typedef typename Duration::rep rep;
typedef typename Duration::period period;
inline EA_CONSTEXPR time_point() : mDuration(Duration::zero()) {}
EA_CONSTEXPR explicit time_point(const Duration& other) : mDuration(other) {}
template <typename Duration2>
inline EA_CONSTEXPR time_point(
const time_point<Clock, Duration2>& t,
typename eastl::enable_if<eastl::is_convertible<Duration2, Duration>::value>::type** = 0)
: mDuration(t.time_since_epoch()) {}
EA_CONSTEXPR Duration time_since_epoch() const { return mDuration; }
time_point& operator+=(const Duration& d) { mDuration += d; return *this; }
time_point& operator-=(const Duration& d) { mDuration -= d; return *this; }
static EA_CONSTEXPR time_point min() { return time_point(Duration::min()); }
static EA_CONSTEXPR time_point max() { return time_point(Duration::max()); }
};
///////////////////////////////////////////////////////////////////////////////
// 20.12.6.5, time_point arithmetic
///////////////////////////////////////////////////////////////////////////////
template <class Clock, class Duration1, class Rep2, class Period2>
inline EA_CONSTEXPR time_point<Clock, typename eastl::common_type<Duration1, duration<Rep2, Period2>>::type>
operator+(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef time_point<Clock, typename eastl::common_type<Duration1, duration<Rep2, Period2>>::type> common_timepoint_t;
return common_timepoint_t(lhs.time_since_epoch() + rhs);
}
template <class Rep1, class Period1, class Clock, class Duration2>
inline EA_CONSTEXPR time_point<Clock, typename eastl::common_type<Duration2, duration<Rep1, Period1>>::type>
operator+(const duration<Rep1, Period1>& lhs, const time_point<Clock, Duration2>& rhs)
{
typedef time_point<Clock, typename eastl::common_type<Duration2, duration<Rep1, Period1>>::type> common_timepoint_t;
return common_timepoint_t(lhs + rhs.time_since_epoch());
}
template <class Clock, class Duration1, class Rep2, class Period2>
inline EA_CONSTEXPR time_point<Clock, typename eastl::common_type<Duration1, duration<Rep2, Period2>>::type>
operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs)
{
typedef time_point<Clock, typename eastl::common_type<Duration1, duration<Rep2, Period2>>::type> common_timepoint_t;
return common_timepoint_t(lhs.time_since_epoch() - rhs);
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR typename eastl::common_type<Duration1, Duration2>::type operator-(
const time_point<Clock, Duration1>& lhs,
const time_point<Clock, Duration2>& rhs)
{
return lhs.time_since_epoch() - rhs.time_since_epoch();
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator==(const time_point<Clock, Duration1>& lhs,
const time_point<Clock, Duration2>& rhs)
{
return lhs.time_since_epoch() == rhs.time_since_epoch();
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator!=(const time_point<Clock, Duration1>& lhs,
const time_point<Clock, Duration2>& rhs)
{
return !(lhs == rhs);
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator<(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs)
{
return lhs.time_since_epoch() < rhs.time_since_epoch();
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator<=(const time_point<Clock, Duration1>& lhs,
const time_point<Clock, Duration2>& rhs)
{
return !(rhs < lhs);
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator>(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs)
{
return rhs < lhs;
}
template <class Clock, class Duration1, class Duration2>
inline EA_CONSTEXPR bool operator>=(const time_point<Clock, Duration1>& lhs,
const time_point<Clock, Duration2>& rhs)
{
return !(lhs < rhs);
}
///////////////////////////////////////////////////////////////////////////////
// 20.12.6.7, time_point_cast
///////////////////////////////////////////////////////////////////////////////
template <typename ToDuration, typename Clock, typename Duration>
EA_CONSTEXPR time_point<Clock, ToDuration> time_point_cast(
const time_point<Clock, Duration>& t,
typename eastl::enable_if<Internal::IsDuration<ToDuration>::value>::type** = 0)
{
return time_point<Clock, ToDuration>(duration_cast<ToDuration>(t.time_since_epoch()));
}
///////////////////////////////////////////////////////////////////////////////
// 20.12.7, clocks
///////////////////////////////////////////////////////////////////////////////
namespace Internal
{
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
#define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_SONY
#define EASTL_NS_PER_TICK 1
#elif defined EA_PLATFORM_POSIX
#define EASTL_NS_PER_TICK _XTIME_NSECS_PER_TICK
#else
#define EASTL_NS_PER_TICK 100
#endif
#if defined(EA_PLATFORM_POSIX)
typedef chrono::nanoseconds::period SystemClock_Period;
typedef chrono::nanoseconds::period SteadyClock_Period;
#else
typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SystemClock_Period;
typedef eastl::ratio_multiply<eastl::ratio<EASTL_NS_PER_TICK, 1>, nano>::type SteadyClock_Period;
#endif
///////////////////////////////////////////////////////////////////////////////
// Internal::GetTicks
///////////////////////////////////////////////////////////////////////////////
inline uint64_t GetTicks()
{
#if defined EA_PLATFORM_MICROSOFT
auto queryFrequency = []
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return double(1000000000.0L / (long double)frequency.QuadPart); // nanoseconds per tick
};
auto queryCounter = []
{
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return counter.QuadPart;
};
EA_DISABLE_VC_WARNING(4640) // warning C4640: construction of local static object is not thread-safe (VS2013)
static auto frequency = queryFrequency(); // cache cpu frequency on first call
EA_RESTORE_VC_WARNING()
return uint64_t(frequency * (double)queryCounter());
#elif defined EA_PLATFORM_SONY
static_assert(false, "Implementing GetTicks() requires first party support");
return 0;
#elif defined(EA_PLATFORM_APPLE)
auto queryTimeInfo = []
{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
return info;
};
static auto timeInfo = queryTimeInfo();
uint64_t t = mach_absolute_time();
t *= timeInfo.numer;
t /= timeInfo.denom;
return t;
#elif defined(EA_PLATFORM_POSIX) // Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms).
#if (defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC))
timespec ts;
int result = clock_gettime(CLOCK_MONOTONIC, &ts);
if (result == -1 && errno == EINVAL)
result = clock_gettime(CLOCK_REALTIME, &ts);
const uint64_t nNanoseconds = (uint64_t)ts.tv_nsec + ((uint64_t)ts.tv_sec * UINT64_C(1000000000));
return nNanoseconds;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
const uint64_t nMicroseconds = (uint64_t)tv.tv_usec + ((uint64_t)tv.tv_sec * 1000000);
return nMicroseconds;
#endif
#else
#error "chrono not implemented for platform"
#endif
}
} // namespace Internal
///////////////////////////////////////////////////////////////////////////////
// system_clock
///////////////////////////////////////////////////////////////////////////////
class system_clock
{
public:
typedef int64_t rep; // signed arithmetic type representing the number of ticks in the clock's duration
typedef Internal::SystemClock_Period period;
typedef chrono::duration<rep, period> duration; // duration<rep, period>, capable of representing negative durations
typedef chrono::time_point<system_clock> time_point;
// true if the time between ticks is always increases monotonically
EA_CONSTEXPR_OR_CONST static bool is_steady = false;
// returns a time point representing the current point in time.
static time_point now() EA_NOEXCEPT
{
return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
// steady_clock
///////////////////////////////////////////////////////////////////////////////
class steady_clock
{
public:
typedef int64_t rep; // signed arithmetic type representing the number of ticks in the clock's duration
typedef Internal::SteadyClock_Period period;
typedef chrono::duration<rep, period> duration; // duration<rep, period>, capable of representing negative durations
typedef chrono::time_point<steady_clock> time_point;
// true if the time between ticks is always increases monotonically
EA_CONSTEXPR_OR_CONST static bool is_steady = true;
// returns a time point representing the current point in time.
static time_point now() EA_NOEXCEPT
{
return time_point(duration(Internal::GetTicks()));
}
};
///////////////////////////////////////////////////////////////////////////////
// high_resolution_clock
///////////////////////////////////////////////////////////////////////////////
typedef system_clock high_resolution_clock;
} // namespace chrono
///////////////////////////////////////////////////////////////////////////////
// duration common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Rep1, typename Period1, typename Rep2, typename Period2>
struct common_type<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>
{
typedef chrono::duration<typename eastl::decay<typename eastl::common_type<Rep1, Rep2>::type>::type,
typename chrono::Internal::RatioGCD<Period1, Period2>::type> type;
};
///////////////////////////////////////////////////////////////////////////////
// time_point common_type specialization
///////////////////////////////////////////////////////////////////////////////
template <typename Clock, typename Duration1, typename Duration2>
struct common_type<chrono::time_point<Clock, Duration1>, chrono::time_point<Clock, Duration2>>
{
typedef chrono::time_point<Clock, typename eastl::common_type<Duration1, Duration2>::type> type;
};
///////////////////////////////////////////////////////////////////////////////
// chrono_literals
///////////////////////////////////////////////////////////////////////////////
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
// Disabling the Clang/GCC/MSVC warning about using user
// defined literals without a leading '_' as they are reserved
// for standard libary usage.
EA_DISABLE_VC_WARNING(4455)
EA_DISABLE_CLANG_WARNING(-Wuser-defined-literals)
EA_DISABLE_GCC_WARNING(-Wliteral-suffix)
inline namespace literals
{
inline namespace chrono_literals
{
///////////////////////////////////////////////////////////////////////////////
// integer chrono literals
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR chrono::hours operator"" h(unsigned long long h) { return chrono::hours(h); }
EA_CONSTEXPR chrono::minutes operator"" min(unsigned long long m) { return chrono::minutes(m); }
EA_CONSTEXPR chrono::seconds operator"" s(unsigned long long s) { return chrono::seconds(s); }
EA_CONSTEXPR chrono::milliseconds operator"" ms(unsigned long long ms) { return chrono::milliseconds(ms); }
EA_CONSTEXPR chrono::microseconds operator"" us(unsigned long long us) { return chrono::microseconds(us); }
EA_CONSTEXPR chrono::nanoseconds operator"" ns(unsigned long long ns) { return chrono::nanoseconds(ns); }
///////////////////////////////////////////////////////////////////////////////
// float chrono literals
///////////////////////////////////////////////////////////////////////////////
EA_CONSTEXPR chrono::duration<long double, ratio<3600, 1>> operator"" h(long double h)
{ return chrono::duration<long double, ratio<3600, 1>>(h); }
EA_CONSTEXPR chrono::duration<long double, ratio<60, 1>> operator"" min(long double m)
{ return chrono::duration<long double, ratio<60, 1>>(m); }
EA_CONSTEXPR chrono::duration<long double> operator"" s(long double s)
{ return chrono::duration<long double>(s); }
EA_CONSTEXPR chrono::duration<float, milli> operator"" ms(long double ms)
{ return chrono::duration<long double, milli>(ms); }
EA_CONSTEXPR chrono::duration<float, micro> operator"" us(long double us)
{ return chrono::duration<long double, micro>(us); }
EA_CONSTEXPR chrono::duration<float, nano> operator"" ns(long double ns)
{ return chrono::duration<long double, nano>(ns); }
} // namespace chrono_literals
}// namespace literals
EA_RESTORE_GCC_WARNING() // -Wliteral-suffix
EA_RESTORE_CLANG_WARNING() // -Wuser-defined-literals
EA_RESTORE_VC_WARNING() // warning: 4455
#endif
} // namespace eastl
#if EASTL_USER_LITERALS_ENABLED && EASTL_INLINE_NAMESPACES_ENABLED
namespace chrono
{
using namespace eastl::literals::chrono_literals;
} // namespace chrono
#endif
#endif
+45
View File
@@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_COMPARE_H
#define EASTL_COMPARE_H
#include <EABase/eabase.h>
namespace eastl
{
#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
struct synth_three_way
{
template <typename T, typename U>
constexpr auto operator()(const T& t, const U& u) const requires requires
{
{t < u}->std::convertible_to<bool>;
{u < t}->std::convertible_to<bool>;
}
{
if constexpr (std::three_way_comparable_with<T, U>)
{
return t <=> u;
}
else
{
return (t < u) ? std::weak_ordering::less :
(u < t) ? std::weak_ordering::greater :
std::weak_ordering::equivalent;
}
}
};
template <typename T, typename U=T>
using synth_three_way_result = decltype(synth_three_way{}(declval<T&>(), declval<U&>()));
#endif
} // namespace eastl
#endif // Header include guard
+70
View File
@@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_CORE_ALLOCATOR_H
#define EASTL_CORE_ALLOCATOR_H
#if EASTL_CORE_ALLOCATOR_ENABLED
#include <coreallocator/icoreallocator.h>
namespace EA
{
namespace Allocator
{
/// EASTLCoreAllocatorImpl
///
/// EASTL provides an out of the box implementation of the
/// ICoreAllocator interface. This is provided as a convenience for
/// users who wish to provide ICoreAllocator implementations for EASTL to use.
///
/// EASTL has a dependency on coreallocator so to provide an out of
/// the box implementation for EASTLCoreAlloctor and EASTLCoreDeleter
/// that can be used and tested. Historically we could not test
/// ICoreAllocator interface because we relied on the code being linked
/// in user code.
///
class EASTLCoreAllocatorImpl : public ICoreAllocator
{
public:
virtual void* Alloc(size_t size, const char* name, unsigned int flags)
{
return ::operator new[](size, name, flags, 0, __FILE__, __LINE__);
}
virtual void* Alloc(size_t size, const char* name, unsigned int flags, unsigned int alignment, unsigned int alignOffset = 0)
{
return ::operator new[](size, alignment, alignOffset, name, flags, 0, __FILE__, __LINE__);
}
virtual void Free(void* ptr, size_t size = 0)
{
::operator delete(static_cast<char*>(ptr));
}
virtual void* AllocDebug(size_t size, const DebugParams debugParams, unsigned int flags)
{
return Alloc(size, debugParams.mName, flags);
}
virtual void* AllocDebug(size_t size, const DebugParams debugParams, unsigned int flags, unsigned int align, unsigned int alignOffset = 0)
{
return Alloc(size, debugParams.mName, flags, align, alignOffset);
}
static EASTLCoreAllocatorImpl* GetDefaultAllocator();
};
inline EASTLCoreAllocatorImpl* EASTLCoreAllocatorImpl::GetDefaultAllocator()
{
static EASTLCoreAllocatorImpl allocator;
return &allocator;
}
}
}
#endif // EASTL_CORE_ALLOCATOR_ENABLED
#endif // EASTL_CORE_ALLOCATOR_H
+368
View File
@@ -0,0 +1,368 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Implements an EASTL allocator that uses an ICoreAllocator.
// However, this header file is not dependent on ICoreAllocator or its package.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_CORE_ALLOCATOR_ADAPTER_H
#define EASTL_CORE_ALLOCATOR_ADAPTER_H
#if EASTL_CORE_ALLOCATOR_ENABLED
#include <EASTL/internal/config.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
/// EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR
///
/// This allows the application to override the default name for the default global core allocator.
/// However, you must be careful in your usage of this, as if this file is shared between uses then
/// you will need to be careful that your override of this doesn't conflict with others.
///
#ifndef EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR
#define EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR AllocatorType::GetDefaultAllocator
#endif
namespace EA
{
namespace Allocator
{
/// CoreAllocatorAdapter
///
/// Implements the EASTL allocator interface.
/// Allocates memory from an instance of ICoreAllocator or another class with an equivalent interface.
/// ICoreAllocator is a pure-virtual memory allocation interface used by a number of EA games and
/// shared libraries. It's completely unrelated to EASTL, but it's prevalent enough that it's useful
/// for EASTL to have a built-in adapter for this interface. ICoreAllocator is declared in the
/// CoreAllocator package icoreallocator_interface.h header, but CoreAllocatorAdapter can work with
/// any equivalent interface, as defined below.
///
/// Expected interface:
/// enum AllocFlags {
/// kFlagTempMemory = 0,
/// kFlagPermMemory = 1
/// };
///
/// struct CoreAllocator {
/// void* Alloc(size_t size, const char* name, unsigned int allocFlags);
/// void* Alloc(size_t size, const char* name, unsigned int allocFlags, // Not required unless you are working with types that require custom alignment.
/// unsigned int align, unsigned int alignOffset = 0);
/// void Free(void* block, size_t size = 0);
/// static CoreAllocator* GetDefaultAllocator();
/// };
///
/// Example usage:
/// #include <coreallocator/icoreallocator_interface.h>
/// typedef EA::Allocator::CoreAllocatorAdapter<EASTLTestCoreAllocator> Adapter;
/// eastl::list<Widget, Adapter> widgetList(Adapter("UI/WidgetList", pSomeCoreAllocator));
/// widgetList.push_back(Widget());
///
/// Example usage:
/// #include <MyEquivalentCoreAllocatorInterface.h>
/// eastl::list<Widget, CoreAllocatorAdapter<MyCoreAllocatorInterface> > widgetList;
/// widgetList.push_back(Widget());
///
/// Example usage:
/// #include <coreallocator/icoreallocator_interface.h>
/// typedef EA::Allocator::CoreAllocatorAdapter<EASTLTestCoreAllocator> Adapter;
/// typedef eastl::list<Widget, Adapter> WidgetList;
/// CoreAllocatorFixed<WidgetList::node_type> widgetCoreAllocator(pFixedAllocatorForWidgetListValueType); // CoreAllocatorFixed is a hypothetical implementation of the ICoreAllocator interface.
/// WidgetList widgetList(Adapter("UI/WidgetList", &widgetCoreAllocator)); // Note that the widgetCoreAllocator is declared before and thus destroyed after the widget list.
///
template<class AllocatorType>
class CoreAllocatorAdapter
{
public:
typedef CoreAllocatorAdapter<AllocatorType> this_type;
public:
// To do: Make this constructor explicit, when there is no known code dependent on it being otherwise.
CoreAllocatorAdapter(const char* pName = EASTL_NAME_VAL(EASTL_ALLOCATOR_DEFAULT_NAME), AllocatorType* pAllocator = EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR());
CoreAllocatorAdapter(const char* pName, AllocatorType* pAllocator, int flags);
CoreAllocatorAdapter(const CoreAllocatorAdapter& x);
CoreAllocatorAdapter(const CoreAllocatorAdapter& x, const char* pName);
CoreAllocatorAdapter& operator=(const CoreAllocatorAdapter& x);
void* allocate(size_t n, int flags = 0);
void* allocate(size_t n, size_t alignment, size_t offset, int flags = 0);
void deallocate(void* p, size_t n);
AllocatorType* get_allocator() const;
void set_allocator(AllocatorType* pAllocator);
int get_flags() const;
void set_flags(int flags);
const char* get_name() const;
void set_name(const char* pName);
public: // Public because otherwise VC++ generates (possibly invalid) warnings about inline friend template specializations.
AllocatorType* mpCoreAllocator;
int mnFlags; // Allocation flags. See ICoreAllocator/AllocFlags.
#if EASTL_NAME_ENABLED
const char* mpName; // Debug name, used to track memory.
#endif
};
template<class AllocatorType>
bool operator==(const CoreAllocatorAdapter<AllocatorType>& a, const CoreAllocatorAdapter<AllocatorType>& b);
template<class AllocatorType>
bool operator!=(const CoreAllocatorAdapter<AllocatorType>& a, const CoreAllocatorAdapter<AllocatorType>& b);
/// EASTLICoreAllocator
///
/// Provides a standardized typedef for ICoreAllocator;
///
/// Example usage:
/// eastl::list<Widget, EASTLICoreAllocator> widgetList("UI/WidgetList", pSomeCoreAllocator);
/// widgetList.push_back(Widget());
///
class ICoreAllocator;
class EASTLCoreAllocatorImpl;
typedef CoreAllocatorAdapter<ICoreAllocator> EASTLICoreAllocatorAdapter;
typedef CoreAllocatorAdapter<EASTLCoreAllocatorImpl> EASTLCoreAllocatorAdapter;
typedef EASTLICoreAllocatorAdapter EASTLICoreAllocator; // for backwards compatibility
/// EASTLICoreDeleter
///
/// Implements a functor which can free memory from the specified
/// ICoreAllocator interface. This is a convenience object provided for
/// users who wish to have EASTL containers deallocate memory obtained from
/// ICoreAllocator interfaces.
///
template <class AllocatorType>
class CoreDeleterAdapter
{
public:
typedef CoreDeleterAdapter<AllocatorType> this_type;
AllocatorType* mpCoreAllocator;
public:
CoreDeleterAdapter(AllocatorType* pAllocator = EASTL_CORE_ALLOCATOR_ADAPTER_GET_DEFAULT_CORE_ALLOCATOR()) EA_NOEXCEPT
: mpCoreAllocator(pAllocator) {}
~CoreDeleterAdapter() EA_NOEXCEPT {}
template <typename T>
void operator()(T* p)
{
p->~T();
mpCoreAllocator->Free(p);
}
CoreDeleterAdapter(const CoreDeleterAdapter& in) { mpCoreAllocator = in.mpCoreAllocator; }
CoreDeleterAdapter(CoreDeleterAdapter&& in)
{
mpCoreAllocator = in.mpCoreAllocator;
in.mpCoreAllocator = nullptr;
}
CoreDeleterAdapter& operator=(const CoreDeleterAdapter& in)
{
mpCoreAllocator = in.mpCoreAllocator;
return *this;
}
CoreDeleterAdapter& operator=(CoreDeleterAdapter&& in)
{
mpCoreAllocator = in.mpCoreAllocator;
in.mpCoreAllocator = nullptr;
return *this;
}
};
/// EASTLICoreDeleter
///
/// Provides a standardized typedef for ICoreAllocator implementations.
///
/// Example usage:
/// eastl::shared_ptr<A> foo(pA, EASTLCoreDeleter());
///
typedef CoreDeleterAdapter<ICoreAllocator> EASTLICoreDeleterAdapter;
typedef CoreDeleterAdapter<EASTLCoreAllocatorImpl> EASTLCoreDeleterAdapter;
} // namespace Allocator
} // namespace EA
///////////////////////////////////////////////////////////////////////////////
// Inlines
///////////////////////////////////////////////////////////////////////////////
namespace EA
{
namespace Allocator
{
template<class AllocatorType>
inline CoreAllocatorAdapter<AllocatorType>::CoreAllocatorAdapter(const char* EASTL_NAME(pName), AllocatorType* pCoreAllocator)
: mpCoreAllocator(pCoreAllocator), mnFlags(0)
{
#if EASTL_NAME_ENABLED
mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
template<class AllocatorType>
inline CoreAllocatorAdapter<AllocatorType>::CoreAllocatorAdapter(const char* EASTL_NAME(pName), AllocatorType* pCoreAllocator, int flags)
: mpCoreAllocator(pCoreAllocator), mnFlags(flags)
{
#if EASTL_NAME_ENABLED
mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
template<class AllocatorType>
inline CoreAllocatorAdapter<AllocatorType>::CoreAllocatorAdapter(const CoreAllocatorAdapter& x)
: mpCoreAllocator(x.mpCoreAllocator), mnFlags(x.mnFlags)
{
#if EASTL_NAME_ENABLED
mpName = x.mpName;
#endif
}
template<class AllocatorType>
inline CoreAllocatorAdapter<AllocatorType>::CoreAllocatorAdapter(const CoreAllocatorAdapter& x, const char* EASTL_NAME(pName))
: mpCoreAllocator(x.mpCoreAllocator), mnFlags(x.mnFlags)
{
#if EASTL_NAME_ENABLED
mpName = pName ? pName : EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
template<class AllocatorType>
inline CoreAllocatorAdapter<AllocatorType>& CoreAllocatorAdapter<AllocatorType>::operator=(const CoreAllocatorAdapter& x)
{
mpCoreAllocator = x.mpCoreAllocator;
mnFlags = x.mnFlags;
#if EASTL_NAME_ENABLED
mpName = x.mpName;
#endif
return *this;
}
template<class AllocatorType>
inline void* CoreAllocatorAdapter<AllocatorType>::allocate(size_t n, int /*flags*/)
{
// It turns out that EASTL itself doesn't use the flags parameter,
// whereas the user here might well want to specify a flags
// parameter. So we use ours instead of the one passed in.
return mpCoreAllocator->Alloc(n, EASTL_NAME_VAL(mpName), (unsigned)mnFlags);
}
template<class AllocatorType>
inline void* CoreAllocatorAdapter<AllocatorType>::allocate(size_t n, size_t alignment, size_t offset, int /*flags*/)
{
// It turns out that EASTL itself doesn't use the flags parameter,
// whereas the user here might well want to specify a flags
// parameter. So we use ours instead of the one passed in.
return mpCoreAllocator->Alloc(n, EASTL_NAME_VAL(mpName), (unsigned)mnFlags, (unsigned)alignment, (unsigned)offset);
}
template<class AllocatorType>
inline void CoreAllocatorAdapter<AllocatorType>::deallocate(void* p, size_t n)
{
return mpCoreAllocator->Free(p, n);
}
template<class AllocatorType>
inline AllocatorType* CoreAllocatorAdapter<AllocatorType>::get_allocator() const
{
return mpCoreAllocator;
}
template<class AllocatorType>
inline void CoreAllocatorAdapter<AllocatorType>::set_allocator(AllocatorType* pAllocator)
{
mpCoreAllocator = pAllocator;
}
template<class AllocatorType>
inline int CoreAllocatorAdapter<AllocatorType>::get_flags() const
{
return mnFlags;
}
template<class AllocatorType>
inline void CoreAllocatorAdapter<AllocatorType>::set_flags(int flags)
{
mnFlags = flags;
}
template<class AllocatorType>
inline const char* CoreAllocatorAdapter<AllocatorType>::get_name() const
{
#if EASTL_NAME_ENABLED
return mpName;
#else
return EASTL_ALLOCATOR_DEFAULT_NAME;
#endif
}
template<class AllocatorType>
inline void CoreAllocatorAdapter<AllocatorType>::set_name(const char* pName)
{
#if EASTL_NAME_ENABLED
mpName = pName;
#else
(void)pName;
#endif
}
template<class AllocatorType>
inline bool operator==(const CoreAllocatorAdapter<AllocatorType>& a, const CoreAllocatorAdapter<AllocatorType>& b)
{
return (a.mpCoreAllocator == b.mpCoreAllocator) &&
(a.mnFlags == b.mnFlags);
}
template<class AllocatorType>
inline bool operator!=(const CoreAllocatorAdapter<AllocatorType>& a, const CoreAllocatorAdapter<AllocatorType>& b)
{
return (a.mpCoreAllocator != b.mpCoreAllocator) ||
(a.mnFlags != b.mnFlags);
}
} // namespace Allocator
} // namespace EA
#endif // EASTL_CORE_ALLOCATOR_ENABLED
#endif // Header include guard
File diff suppressed because it is too large Load Diff
+93
View File
@@ -0,0 +1,93 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// eastl::finally is an implementation of the popular cpp idiom RAII - Resource
// Acquisition Is Initialization. eastl::finally guarantees that the user
// provided callable will be executed upon whatever mechanism is used to leave
// the current scope. This can guard against user errors but this is a popular
// technique to write robust code in execution environments that have exceptions
// enabled.
//
// Example:
// void foo()
// {
// void* p = malloc(128);
// auto _ = eastl::make_finally([&] { free(p); });
//
// // Code that may throw an exception...
//
// } // eastl::finally guaranteed to call 'free' at scope exit.
//
// References:
// * https://www.bfilipek.com/2017/04/finalact.html
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FINALLY_H
#define EASTL_FINALLY_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/config.h>
#include <EASTL/internal/move_help.h>
#include <EASTL/type_traits.h>
namespace eastl
{
///////////////////////////////////////////////////////////////////////////
// finally
//
// finally is the type that calls the users callback on scope exit.
//
template <typename Functor>
class finally
{
static_assert(!eastl::is_lvalue_reference_v<Functor>, "eastl::finally requires the callable is passed as an rvalue reference.");
Functor m_functor;
bool m_engaged = false;
public:
finally(Functor f) : m_functor(eastl::move(f)), m_engaged(true) {}
finally(finally&& other) : m_functor(eastl::move(other.m_functor)), m_engaged(other.m_engaged)
{
other.dismiss();
}
~finally() { execute(); }
finally(const finally&) = delete;
finally& operator=(const finally&) = delete;
finally& operator=(finally&&) = delete;
inline void dismiss() { m_engaged = false; }
inline void execute()
{
if (m_engaged)
m_functor();
dismiss();
}
};
///////////////////////////////////////////////////////////////////////////
// make_finally
//
// this utility function is the standard mechansim to perform the required
// type deduction on the users provided callback inorder to create a
// 'finally' object.
//
template <typename F>
auto make_finally(F&& f)
{
return finally<F>(eastl::forward<F>(f));
}
}
#endif // EASTL_FINALLY_H
+455
View File
@@ -0,0 +1,455 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements the following
// fixed_allocator
// fixed_allocator_with_overflow
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_ALLOCATOR_H
#define EASTL_FIXED_ALLOCATOR_H
#include <EASTL/internal/config.h>
#include <EASTL/internal/fixed_pool.h>
#include <EASTL/functional.h>
#include <EASTL/memory.h>
#include <EASTL/allocator.h>
#include <EASTL/type_traits.h>
EA_DISABLE_ALL_VC_WARNINGS();
#include <new>
EA_RESTORE_ALL_VC_WARNINGS();
EA_DISABLE_VC_WARNING(4275); // non dll-interface class used as base for DLL-interface classkey 'identifier'
#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
namespace eastl
{
///////////////////////////////////////////////////////////////////////////
// fixed_allocator
///////////////////////////////////////////////////////////////////////////
/// fixed_allocator
///
/// Implements an allocator which allocates a single fixed size where
/// the size, alignment, and memory used for the pool is defined at
/// runtime by the user. This is different from fixed containers
/// such as fixed_list whereby the size and alignment are determined
/// at compile time and the memory is directly built into the container's
/// member data.
///
/// If the pool's memory is exhausted or was never initialized, the
/// allocate function returns NULL. Consider the fixed_allocator_with_overflow
/// class as an alternative in order to deal with this situation.
///
/// This class requires the user to call container.get_allocator().init()
/// after constructing the container. There currently isn't a way to
/// construct the container with the initialization parameters, though
/// with some effort such a thing could probably be made possible.
/// It's not as simple as it might first seem, due to the non-copyable
/// nature of fixed allocators. A side effect of this limitation is that
/// you cannot copy-construct a container using fixed_allocators.
///
/// Another side-effect is that you cannot swap two containers using
/// a fixed_allocator, as a swap requires temporary memory allocated by
/// an equivalent allocator, and such a thing cannot be done implicitly.
/// A workaround for the swap limitation is that you can implement your
/// own swap whereby you provide an explicitly created temporary object.
///
/// Note: Be careful to set the allocator's node size to the size of the
/// container node and not the size of the contained object. Note that the
/// example code below uses IntListNode.
///
/// Example usage:
/// typedef eastl::list<int, fixed_allocator> IntList;
/// typedef IntList::node_type IntListNode;
///
/// IntListNode buffer[200];
/// IntList intList;
/// intList.get_allocator().init(buffer, sizeof(buffer), sizeof(IntListNode), __alignof(IntListNode));
///
class EASTL_API fixed_allocator : public fixed_pool_base
{
public:
/// fixed_allocator
///
/// Default constructor. The user usually will need to call init() after
/// constructing via this constructor.
///
fixed_allocator(const char* /*pName*/ = EASTL_FIXED_POOL_DEFAULT_NAME)
: fixed_pool_base(NULL)
{
}
/// fixed_allocator
///
/// Copy constructor. The user usually will need to call init() after
/// constructing via this constructor. By their nature, fixed-allocators
/// cannot be copied in any useful way, as by their nature the user
/// must manually initialize them.
///
fixed_allocator(const fixed_allocator&)
: fixed_pool_base(NULL)
{
}
/// operator=
///
/// By their nature, fixed-allocators cannot be copied in any
/// useful way, as by their nature the user must manually
/// initialize them.
///
fixed_allocator& operator=(const fixed_allocator&)
{
return *this;
}
// init
//
// No init here, as the base class version is sufficient.
//
//void init(void* pMemory, size_t memorySize, size_t nodeSize,
// size_t alignment, size_t alignmentOffset = 0);
/// allocate
///
/// Allocates a new object of the size specified upon class initialization.
/// Returns NULL if there is no more memory.
///
void* allocate(size_t n, int /*flags*/ = 0)
{
// To consider: Verify that 'n' is what the user initialized us with.
Link* pLink = mpHead;
if(pLink) // If we have space...
{
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
if(++mnCurrentSize > mnPeakSize)
mnPeakSize = mnCurrentSize;
#endif
mpHead = pLink->mpNext;
return pLink;
}
else
{
// If there's no free node in the free list, just
// allocate another from the reserved memory area
if(mpNext != mpCapacity)
{
pLink = mpNext;
mpNext = reinterpret_cast<Link*>(reinterpret_cast<char*>(mpNext) + n);
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
if(++mnCurrentSize > mnPeakSize)
mnPeakSize = mnCurrentSize;
#endif
return pLink;
}
// EASTL_ASSERT(false); To consider: enable this assert. However, we intentionally disable it because this isn't necessarily an assertable error.
return NULL;
}
}
/// allocate
///
void* allocate(size_t n, size_t /*alignment*/, size_t /*offset*/, int flags = 0)
{
return allocate(n, flags);
}
/// deallocate
///
/// Frees the given object which was allocated by allocate().
/// If the given node was not allocated by allocate() then the behaviour
/// is undefined.
///
void deallocate(void* p, size_t)
{
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
--mnCurrentSize;
#endif
((Link*)p)->mpNext = mpHead;
mpHead = ((Link*)p);
}
using fixed_pool_base::can_allocate;
const char* get_name() const
{
return EASTL_FIXED_POOL_DEFAULT_NAME;
}
void set_name(const char*)
{
// Nothing to do. We don't allocate memory.
}
}; // fixed_allocator
bool operator==(const fixed_allocator& a, const fixed_allocator& b);
bool operator!=(const fixed_allocator& a, const fixed_allocator& b);
///////////////////////////////////////////////////////////////////////////
// fixed_allocator_with_overflow
///////////////////////////////////////////////////////////////////////////
/// fixed_allocator_with_overflow
///
/// Implements an allocator which allocates a single fixed size where
/// the size, alignment, and memory used for the pool is defined at
/// runtime by the user. This is different from fixed containers
/// such as fixed_list whereby the size and alignment are determined
/// at compile time and the memory is directly built into the container's
/// member data.
///
/// Note: Be careful to set the allocator's node size to the size of the
/// container node and not the size of the contained object. Note that the
/// example code below uses IntListNode.
///
/// This class requires the user to call container.get_allocator().init()
/// after constructing the container. There currently isn't a way to
/// construct the container with the initialization parameters, though
/// with some effort such a thing could probably be made possible.
/// It's not as simple as it might first seem, due to the non-copyable
/// nature of fixed allocators. A side effect of this limitation is that
/// you cannot copy-construct a container using fixed_allocators.
///
/// Another side-effect is that you cannot swap two containers using
/// a fixed_allocator, as a swap requires temporary memory allocated by
/// an equivalent allocator, and such a thing cannot be done implicitly.
/// A workaround for the swap limitation is that you can implement your
/// own swap whereby you provide an explicitly created temporary object.
///
/// Example usage:
/// typedef eastl::list<int, fixed_allocator_with_overflow> IntList;
/// typedef IntList::node_type IntListNode;
///
/// IntListNode buffer[200];
/// IntList intList;
/// intList.get_allocator().init(buffer, sizeof(buffer), sizeof(IntListNode), __alignof(IntListNode));
///
class EASTL_API fixed_allocator_with_overflow : public fixed_pool_base
{
public:
/// fixed_allocator_with_overflow
///
/// Default constructor. The user usually will need to call init() after
/// constructing via this constructor.
///
fixed_allocator_with_overflow(const char* pName = EASTL_FIXED_POOL_DEFAULT_NAME)
: fixed_pool_base(NULL)
, mOverflowAllocator(pName)
, mpPoolBegin(nullptr)
, mpPoolEnd(nullptr)
, mnNodeSize(0)
{
}
/// fixed_allocator_with_overflow
///
/// Copy constructor. The user usually will need to call init() after
/// constructing via this constructor. By their nature, fixed-allocators
/// cannot be copied in any useful way, as by their nature the user
/// must manually initialize them.
///
fixed_allocator_with_overflow(const fixed_allocator_with_overflow&)
: fixed_pool_base(NULL)
, mpPoolBegin(nullptr)
, mpPoolEnd(nullptr)
, mnNodeSize(0)
{
}
/// operator=
///
/// By their nature, fixed-allocators cannot be copied in any
/// useful way, as by their nature the user must manually
/// initialize them.
///
fixed_allocator_with_overflow& operator=(const fixed_allocator_with_overflow& x)
{
#if EASTL_ALLOCATOR_COPY_ENABLED
mOverflowAllocator = x.mOverflowAllocator;
#else
(void)x;
#endif
return *this;
}
/// init
///
void init(void* pMemory, size_t memorySize, size_t nodeSize,
size_t alignment, size_t alignmentOffset = 0)
{
fixed_pool_base::init(pMemory, memorySize, nodeSize, alignment, alignmentOffset);
mpPoolBegin = pMemory;
mpPoolEnd = (void*)((uintptr_t)pMemory + memorySize);
mnNodeSize = (eastl_size_t)nodeSize;
}
/// allocate
///
/// Allocates a new object of the size specified upon class initialization.
/// Returns NULL if there is no more memory.
///
void* allocate(size_t /*n*/, int /*flags*/ = 0)
{
// To consider: Verify that 'n' is what the user initialized us with.
void* p;
if(mpHead) // If we have space...
{
p = mpHead;
mpHead = mpHead->mpNext;
}
else
{
// If there's no free node in the free list, just
// allocate another from the reserved memory area
if (mpNext != mpCapacity)
{
p = mpNext;
mpNext = reinterpret_cast<Link*>(reinterpret_cast<char*>(mpNext) + mnNodeSize);
}
else
p = mOverflowAllocator.allocate(mnNodeSize);
}
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
if(p && (++mnCurrentSize > mnPeakSize))
mnPeakSize = mnCurrentSize;
#endif
return p;
}
/// allocate
///
void* allocate(size_t n, size_t /*alignment*/, size_t /*offset*/, int flags = 0)
{
return allocate(n, flags);
}
/// deallocate
///
/// Frees the given object which was allocated by allocate().
/// If the given node was not allocated by allocate() then the behaviour
/// is undefined.
///
void deallocate(void* p, size_t)
{
#if EASTL_FIXED_SIZE_TRACKING_ENABLED
--mnCurrentSize;
#endif
if((p >= mpPoolBegin) && (p < mpPoolEnd))
{
((Link*)p)->mpNext = mpHead;
mpHead = ((Link*)p);
}
else
mOverflowAllocator.deallocate(p, (size_t)mnNodeSize);
}
using fixed_pool_base::can_allocate;
const char* get_name() const
{
return mOverflowAllocator.get_name();
}
void set_name(const char* pName)
{
mOverflowAllocator.set_name(pName);
}
protected:
EASTLAllocatorType mOverflowAllocator; // To consider: Allow the user to define the type of this, presumably via a template parameter.
void* mpPoolBegin; // To consider: We have these member variables and ideally we shouldn't need them. The problem is that
void* mpPoolEnd; // the information about the pool buffer and object size is stored in the owning container
eastl_size_t mnNodeSize; // and we can't have access to it without increasing the amount of code we need and by templating
// more code. It may turn out that simply storing data here is smaller in the end.
}; // fixed_allocator_with_overflow // Granted, this class is usually used for debugging purposes, but perhaps there is an elegant solution.
bool operator==(const fixed_allocator_with_overflow& a, const fixed_allocator_with_overflow& b);
bool operator!=(const fixed_allocator_with_overflow& a, const fixed_allocator_with_overflow& b);
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
inline bool operator==(const fixed_allocator&, const fixed_allocator&)
{
return false;
}
inline bool operator!=(const fixed_allocator&, const fixed_allocator&)
{
return false;
}
inline bool operator==(const fixed_allocator_with_overflow&, const fixed_allocator_with_overflow&)
{
return false;
}
inline bool operator!=(const fixed_allocator_with_overflow&, const fixed_allocator_with_overflow&)
{
return false;
}
} // namespace eastl
EA_RESTORE_VC_WARNING();
#endif // Header include guard
+218
View File
@@ -0,0 +1,218 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_FUNCTION_H
#define EASTL_FIXED_FUNCTION_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/function_detail.h>
namespace eastl
{
template <int, typename>
class fixed_function;
namespace internal
{
template <typename>
struct is_fixed_function
: public eastl::false_type {};
template <int SIZE_IN_BYTES, typename R, typename... Args>
struct is_fixed_function<eastl::fixed_function<SIZE_IN_BYTES, R(Args...)>>
: public eastl::true_type {};
template<typename T>
EA_CONSTEXPR bool is_fixed_function_v = is_fixed_function<T>::value;
}
#define EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(TYPE) \
static_assert(sizeof(TYPE) <= sizeof(typename Base::FunctorStorageType), \
"fixed_function local buffer is not large enough to hold the callable object.")
#define EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES) \
static_assert(SIZE_IN_BYTES >= NEW_SIZE_IN_BYTES, \
"fixed_function local buffer is not large enough to hold the new fixed_function type.")
template <typename Functor>
using EASTL_DISABLE_OVERLOAD_IF_FIXED_FUNCTION =
eastl::disable_if_t<internal::is_fixed_function_v<eastl::decay_t<Functor>>>;
// fixed_function
//
template <int SIZE_IN_BYTES, typename R, typename... Args>
class fixed_function<SIZE_IN_BYTES, R(Args...)> : public internal::function_detail<SIZE_IN_BYTES, R(Args...)>
{
using Base = internal::function_detail<SIZE_IN_BYTES, R(Args...)>;
public:
using typename Base::result_type;
fixed_function() EA_NOEXCEPT = default;
fixed_function(std::nullptr_t p) EA_NOEXCEPT
: Base(p)
{
}
fixed_function(const fixed_function& other)
: Base(other)
{
}
fixed_function(fixed_function&& other)
: Base(eastl::move(other))
{
}
template <typename Functor,
typename = EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(Functor, R, Args..., Base, fixed_function),
typename = EASTL_DISABLE_OVERLOAD_IF_FIXED_FUNCTION<Functor>>
fixed_function(Functor functor)
: Base(eastl::move(functor))
{
EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(Functor);
}
template<int NEW_SIZE_IN_BYTES>
fixed_function(const fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>& other)
: Base(other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
}
template<int NEW_SIZE_IN_BYTES>
fixed_function(fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>&& other)
: Base(eastl::move(other))
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
}
~fixed_function() EA_NOEXCEPT = default;
fixed_function& operator=(const fixed_function& other)
{
Base::operator=(other);
return *this;
}
fixed_function& operator=(fixed_function&& other)
{
Base::operator=(eastl::move(other));
return *this;
}
fixed_function& operator=(std::nullptr_t p) EA_NOEXCEPT
{
Base::operator=(p);
return *this;
}
template<int NEW_SIZE_IN_BYTES>
fixed_function& operator=(const fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>& other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
Base::operator=(other);
return *this;
}
template<int NEW_SIZE_IN_BYTES>
fixed_function& operator=(fixed_function<NEW_SIZE_IN_BYTES, R(Args...)>&& other)
{
EASTL_INTERNAL_FIXED_FUNCTION_NEW_SIZE_STATIC_ASSERT(NEW_SIZE_IN_BYTES);
Base::operator=(eastl::move(other));
return *this;
}
template <typename Functor,
typename = EASTL_INTERNAL_FUNCTION_VALID_FUNCTION_ARGS(Functor, R, Args..., Base, fixed_function),
typename = EASTL_DISABLE_OVERLOAD_IF_FIXED_FUNCTION<Functor>>
fixed_function& operator=(Functor&& functor)
{
EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(eastl::decay_t<Functor>);
Base::operator=(eastl::forward<Functor>(functor));
return *this;
}
template <typename Functor>
fixed_function& operator=(eastl::reference_wrapper<Functor> f) EA_NOEXCEPT
{
EASTL_INTERNAL_FIXED_FUNCTION_STATIC_ASSERT(eastl::reference_wrapper<Functor>);
Base::operator=(f);
return *this;
}
void swap(fixed_function& other) EA_NOEXCEPT
{
Base::swap(other);
}
explicit operator bool() const EA_NOEXCEPT
{
return Base::operator bool();
}
R operator ()(Args... args) const
{
return Base::operator ()(eastl::forward<Args>(args)...);
}
#if EASTL_RTTI_ENABLED
const std::type_info& target_type() const EA_NOEXCEPT
{
return Base::target_type();
}
template <typename Functor>
Functor* target() EA_NOEXCEPT
{
return Base::target();
}
template <typename Functor>
const Functor* target() const EA_NOEXCEPT
{
return Base::target();
}
#endif
};
template <int S, typename R, typename... Args>
bool operator==(const fixed_function<S, R(Args...)>& f, std::nullptr_t) EA_NOEXCEPT
{
return !f;
}
template <int S, typename R, typename... Args>
bool operator==(std::nullptr_t, const fixed_function<S, R(Args...)>& f) EA_NOEXCEPT
{
return !f;
}
template <int S, typename R, typename... Args>
bool operator!=(const fixed_function<S, R(Args...)>& f, std::nullptr_t) EA_NOEXCEPT
{
return !!f;
}
template <int S, typename R, typename... Args>
bool operator!=(std::nullptr_t, const fixed_function<S, R(Args...)>& f) EA_NOEXCEPT
{
return !!f;
}
template <int S, typename R, typename... Args>
void swap(fixed_function<S, R(Args...)>& lhs, fixed_function<S, R(Args...)>& rhs)
{
lhs.swap(rhs);
}
} // namespace eastl
#endif // EASTL_FIXED_FUNCTION_H
+828
View File
@@ -0,0 +1,828 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a hash_map and hash_multimap which use a fixed size
// memory pool for its buckets and nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_HASH_MAP_H
#define EASTL_FIXED_HASH_MAP_H
#include <EASTL/hash_map.h>
#include <EASTL/internal/fixed_pool.h>
EA_DISABLE_VC_WARNING(4127) // Conditional expression is constant
#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
namespace eastl
{
/// EASTL_FIXED_HASH_MAP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_HASH_MAP_DEFAULT_NAME
#define EASTL_FIXED_HASH_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_map" // Unless the user overrides something, this is "EASTL fixed_hash_map".
#endif
#ifndef EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME
#define EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_multimap" // Unless the user overrides something, this is "EASTL fixed_hash_multimap".
#endif
/// EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR
/// EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR
#define EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MAP_DEFAULT_NAME)
#endif
#ifndef EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR
#define EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME)
#endif
/// fixed_hash_map
///
/// Implements a hash_map with a fixed block of memory identified by the nodeCount and bucketCount
/// template parameters.
///
/// Template parameters:
/// Key The key type for the map. This is a map of Key to T (value).
/// T The value type for the map.
/// nodeCount The max number of objects to contain. This value must be >= 1.
/// bucketCount The number of buckets to use. This value must be >= 2.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Hash hash_set hash function. See hash_set.
/// Predicate hash_set equality testing function. See hash_set.
///
template <typename Key, typename T, size_t nodeCount, size_t bucketCount = nodeCount + 1, bool bEnableOverflow = true,
typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType>
class fixed_hash_map : public hash_map<Key,
T,
Hash,
Predicate,
fixed_hashtable_allocator<
bucketCount + 1,
sizeof(typename hash_map<Key, T, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
EASTL_ALIGN_OF(eastl::pair<Key, T>),
0,
bEnableOverflow,
OverflowAllocator>,
bCacheHashCode>
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_map<Key, T, Hash, Predicate,
OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(eastl::pair<Key, T>), 0,
bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef hash_map<Key, T, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
typedef fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::mAllocator;
using base_type::clear;
protected:
node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket.
char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
public:
explicit fixed_hash_map(const overflow_allocator_type& overflowAllocator);
explicit fixed_hash_map(const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_map(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator);
template <typename InputIterator>
fixed_hash_map(InputIterator first, InputIterator last,
const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_map(const this_type& x);
fixed_hash_map(this_type&& x);
fixed_hash_map(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_hash_map(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MAP_DEFAULT_ALLOCATOR);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
void clear(bool clearBuckets);
}; // fixed_hash_map
/// fixed_hash_multimap
///
/// Implements a hash_multimap with a fixed block of memory identified by the nodeCount and bucketCount
/// template parameters.
///
/// Template parameters:
/// Key The key type for the map. This is a map of Key to T (value).
/// T The value type for the map.
/// nodeCount The max number of objects to contain. This value must be >= 1.
/// bucketCount The number of buckets to use. This value must be >= 2.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Hash hash_set hash function. See hash_set.
/// Predicate hash_set equality testing function. See hash_set.
///
template <typename Key, typename T, size_t nodeCount, size_t bucketCount = nodeCount + 1, bool bEnableOverflow = true,
typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType>
class fixed_hash_multimap : public hash_multimap<Key,
T,
Hash,
Predicate,
fixed_hashtable_allocator<
bucketCount + 1,
sizeof(typename hash_multimap<Key, T, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
EASTL_ALIGN_OF(eastl::pair<Key, T>),
0,
bEnableOverflow,
OverflowAllocator>,
bCacheHashCode>
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_multimap<Key, T, Hash, Predicate,
OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(eastl::pair<Key, T>), 0,
bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef hash_multimap<Key, T, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
typedef fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::mAllocator;
using base_type::clear;
protected:
node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket.
char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
public:
explicit fixed_hash_multimap(const overflow_allocator_type& overflowAllocator);
explicit fixed_hash_multimap(const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_multimap(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator);
template <typename InputIterator>
fixed_hash_multimap(InputIterator first, InputIterator last,
const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_multimap(const this_type& x);
fixed_hash_multimap(this_type&& x);
fixed_hash_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_hash_multimap(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MULTIMAP_DEFAULT_ALLOCATOR);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
void clear(bool clearBuckets);
}; // fixed_hash_multimap
///////////////////////////////////////////////////////////////////////
// fixed_hash_map
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if (!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if (!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
template <typename InputIterator>
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(InputIterator first, InputIterator last,
const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(first, last);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(const this_type& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(this_type&& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_map(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(ilist.begin(), ilist.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
reset_lose_memory()
{
base_type::mnBucketCount = (size_type)base_type::mRehashPolicy.GetPrevBucketCount((uint32_t)bucketCount);
base_type::mnElementCount = 0;
base_type::mRehashPolicy.mnNextResize = 0;
base_type::get_allocator().reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::size_type
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline const typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
clear(bool clearBuckets)
{
base_type::DoFreeNodes(base_type::mpBucketArray, base_type::mnBucketCount);
if(clearBuckets)
{
base_type::DoFreeBuckets(base_type::mpBucketArray, base_type::mnBucketCount);
reset_lose_memory();
}
base_type::mpBucketArray = (node_type**)mBucketBuffer;
base_type::mnElementCount = 0;
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode>
inline void swap(fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& a,
fixed_hash_map<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
///////////////////////////////////////////////////////////////////////
// fixed_hash_multimap
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if (!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
template <typename InputIterator>
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(InputIterator first, InputIterator last,
const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(first, last);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(const this_type& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(this_type&& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(),fixed_allocator_type(NULL, mBucketBuffer))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multimap(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTIMAP_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(ilist.begin(), ilist.end());
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
reset_lose_memory()
{
base_type::mnBucketCount = (size_type)base_type::mRehashPolicy.GetPrevBucketCount((uint32_t)bucketCount);
base_type::mnElementCount = 0;
base_type::mRehashPolicy.mnNextResize = 0;
base_type::get_allocator().reset(mNodeBuffer);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::size_type
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline const typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
clear(bool clearBuckets)
{
base_type::DoFreeNodes(base_type::mpBucketArray, base_type::mnBucketCount);
if(clearBuckets)
{
base_type::DoFreeBuckets(base_type::mpBucketArray, base_type::mnBucketCount);
reset_lose_memory();
}
base_type::mpBucketArray = (node_type**)mBucketBuffer;
base_type::mnElementCount = 0;
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode>
inline void swap(fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& a,
fixed_hash_multimap<Key, T, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
EA_RESTORE_VC_WARNING()
#endif // Header include guard
+790
View File
@@ -0,0 +1,790 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a hash_set which uses a fixed size memory pool for
// its buckets and nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_HASH_SET_H
#define EASTL_FIXED_HASH_SET_H
#include <EASTL/hash_set.h>
#include <EASTL/internal/fixed_pool.h>
EA_DISABLE_VC_WARNING(4127) // Conditional expression is constant
#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
namespace eastl
{
/// EASTL_FIXED_HASH_SET_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_HASH_SET_DEFAULT_NAME
#define EASTL_FIXED_HASH_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_set" // Unless the user overrides something, this is "EASTL fixed_hash_set".
#endif
#ifndef EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME
#define EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_hash_multiset" // Unless the user overrides something, this is "EASTL fixed_hash_multiset".
#endif
/// EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR
/// EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR
#define EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_SET_DEFAULT_NAME)
#endif
#ifndef EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR
#define EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME)
#endif
/// fixed_hash_set
///
/// Implements a hash_set with a fixed block of memory identified by the nodeCount and bucketCount
/// template parameters.
///
/// Template parameters:
/// Value The type of object the hash_set holds.
/// nodeCount The max number of objects to contain. This value must be >= 1.
/// bucketCount The number of buckets to use. This value must be >= 2.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Hash hash_set hash function. See hash_set.
/// Predicate hash_set equality testing function. See hash_set.
///
template <typename Value, size_t nodeCount, size_t bucketCount = nodeCount + 1, bool bEnableOverflow = true,
typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType>
class fixed_hash_set : public hash_set<Value,
Hash,
Predicate,
fixed_hashtable_allocator<
bucketCount + 1,
sizeof(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
EASTL_ALIGN_OF(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
0,
bEnableOverflow,
OverflowAllocator>,
bCacheHashCode>
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_set<Value, Hash, Predicate,
OverflowAllocator, bCacheHashCode>::node_type), nodeCount,
EASTL_ALIGN_OF(typename hash_set<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator> this_type;
typedef hash_set<Value, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::mAllocator;
protected:
node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket.
char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
public:
explicit fixed_hash_set(const overflow_allocator_type& overflowAllocator);
explicit fixed_hash_set(const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_set(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator);
template <typename InputIterator>
fixed_hash_set(InputIterator first, InputIterator last,
const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_set(const this_type& x);
fixed_hash_set(this_type&& x);
fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_hash_set(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_SET_DEFAULT_ALLOCATOR);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_hash_set
/// fixed_hash_multiset
///
/// Implements a hash_multiset with a fixed block of memory identified by the nodeCount and bucketCount
/// template parameters.
///
/// Value The type of object the hash_set holds.
/// nodeCount The max number of objects to contain. This value must be >= 1.
/// bucketCount The number of buckets to use. This value must be >= 2.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Hash hash_set hash function. See hash_set.
/// Predicate hash_set equality testing function. See hash_set.
///
template <typename Value, size_t nodeCount, size_t bucketCount = nodeCount + 1, bool bEnableOverflow = true,
typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>, bool bCacheHashCode = false, typename OverflowAllocator = EASTLAllocatorType>
class fixed_hash_multiset : public hash_multiset<Value,
Hash,
Predicate,
fixed_hashtable_allocator<
bucketCount + 1,
sizeof(typename hash_multiset<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
nodeCount,
EASTL_ALIGN_OF(typename hash_multiset<Value, Hash, Predicate, OverflowAllocator, bCacheHashCode>::node_type),
0,
bEnableOverflow,
OverflowAllocator>,
bCacheHashCode>
{
public:
typedef fixed_hashtable_allocator<bucketCount + 1, sizeof(typename hash_multiset<Value, Hash, Predicate,
OverflowAllocator, bCacheHashCode>::node_type), nodeCount, EASTL_ALIGN_OF(typename hash_multiset<Value, Hash, Predicate,
OverflowAllocator, bCacheHashCode>::node_type), 0,
bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef hash_multiset<Value, Hash, Predicate, fixed_allocator_type, bCacheHashCode> base_type;
typedef fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::mAllocator;
protected:
node_type** mBucketBuffer[bucketCount + 1]; // '+1' because the hash table needs a null terminating bucket.
char mNodeBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
public:
explicit fixed_hash_multiset(const overflow_allocator_type& overflowAllocator);
explicit fixed_hash_multiset(const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_multiset(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator);
template <typename InputIterator>
fixed_hash_multiset(InputIterator first, InputIterator last,
const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate());
fixed_hash_multiset(const this_type& x);
fixed_hash_multiset(this_type&& x);
fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_hash_multiset(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_HASH_MULTISET_DEFAULT_ALLOCATOR);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_hash_multiset
///////////////////////////////////////////////////////////////////////
// fixed_hash_set
///////////////////////////////////////////////////////////////////////
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount),
Hash(), Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if (!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount),
hashFunction, predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount),
hashFunction, predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if (!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
template <typename InputIterator>
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(InputIterator first, InputIterator last,
const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
{
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
}
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(first, last);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(const this_type& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::fixed_hash_set(this_type&& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::fixed_hash_set(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount),
x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_set(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_SET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(ilist.begin(), ilist.end());
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
typename fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(this_type&& x)
{
operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_set<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
swap(this_type& x)
{
// We must do a brute-force swap, because fixed containers cannot share memory allocations.
// Note that we create a temp value on the stack. This approach may fail if the size of the
// container is too large. We have a rule against allocating memory from the heap, and so
// if the user wants to swap two large objects of this class, the user will currently need
// to implement it manually. To consider: add code to allocate a temporary buffer if the
// size of the container is too large for the stack.
EASTL_ASSERT(sizeof(x) < EASTL_MAX_STACK_USAGE); // It is dangerous to try to create objects that are too big for the stack.
const this_type temp(*this); // Can't call eastl::swap because that would
*this = x; // itself call this member swap function.
x = temp;
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
void fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::size_type
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline const typename fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode>
inline void swap(fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& a,
fixed_hash_set<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& b)
{
a.swap(b);
}
///////////////////////////////////////////////////////////////////////
// fixed_hash_multiset
///////////////////////////////////////////////////////////////////////
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(const Hash& hashFunction,
const Predicate& predicate,
const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
template <typename InputIterator>
inline fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(InputIterator first, InputIterator last,
const Hash& hashFunction,
const Predicate& predicate)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), hashFunction,
predicate, fixed_allocator_type(NULL, mBucketBuffer))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(first, last);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(const this_type& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::fixed_hash_multiset(this_type&& x)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), x.hash_function(),
x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::fixed_hash_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount),
x.hash_function(), x.equal_function(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
// This implementation is the same as above. If we could rely on using C++11 delegating constructor support then we could just call that here.
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
mAllocator.reset(mNodeBuffer);
base_type::insert(x.begin(), x.end());
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
fixed_hash_multiset(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(prime_rehash_policy::GetPrevBucketCountOnly(bucketCount), Hash(),
Predicate(), fixed_allocator_type(NULL, mBucketBuffer, overflowAllocator))
{
EASTL_CT_ASSERT((nodeCount >= 1) && (bucketCount >= 2));
if(!bEnableOverflow)
base_type::set_max_load_factor(10000.f); // Set it so that we will never resize.
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_HASH_MULTISET_DEFAULT_NAME);
#endif
mAllocator.reset(mNodeBuffer);
base_type::insert(ilist.begin(), ilist.end());
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::this_type&
fixed_hash_multiset<Key, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mNodeBuffer);
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::size_type
fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline const typename fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline typename fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::overflow_allocator_type&
fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode, typename OverflowAllocator>
inline void fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode, OverflowAllocator>::
set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Value, size_t nodeCount, size_t bucketCount, bool bEnableOverflow, typename Hash, typename Predicate, bool bCacheHashCode>
inline void swap(fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& a,
fixed_hash_multiset<Value, nodeCount, bucketCount, bEnableOverflow, Hash, Predicate, bCacheHashCode>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
EA_RESTORE_VC_WARNING()
#endif // Header include guard
+388
View File
@@ -0,0 +1,388 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a list which uses a fixed size memory pool for its nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_LIST_H
#define EASTL_FIXED_LIST_H
#include <EASTL/list.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_LIST_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_LIST_DEFAULT_NAME
#define EASTL_FIXED_LIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_list" // Unless the user overrides something, this is "EASTL fixed_list".
#endif
/// EASTL_FIXED_LIST_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_LIST_DEFAULT_ALLOCATOR
#define EASTL_FIXED_LIST_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_LIST_DEFAULT_NAME)
#endif
/// fixed_list
///
/// fixed_list is a list which uses a single block of contiguous memory
/// for its nodes. The purpose of this is to reduce memory usage relative
/// to a conventional memory allocation system (with block headers), to
/// increase allocation speed (often due to avoidance of mutex locks),
/// to increase performance (due to better memory locality), and to decrease
/// memory fragmentation due to the way that fixed block allocators work.
///
/// The primary downside to a fixed_list is that the number of nodes it
/// can contain is fixed upon its declaration. If you want a fixed_list
/// that doesn't have this limitation, then you probably don't want a
/// fixed_list. You can always create your own memory allocator that works
/// the way you want.
///
/// Template parameters:
/// T The type of object the list holds.
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
class fixed_list : public list<T, fixed_node_allocator<sizeof(typename list<T>::node_type),
nodeCount, EASTL_ALIGN_OF(typename list<T>::node_type), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename list<T>::node_type), nodeCount,
EASTL_ALIGN_OF(typename list<T>::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef OverflowAllocator overflow_allocator_type;
typedef list<T, fixed_allocator_type> base_type;
typedef fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::iterator iterator;
enum { kMaxSize = nodeCount };
using base_type::assign;
using base_type::resize;
using base_type::insert;
using base_type::size;
using base_type::get_allocator;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::internalAllocator;
public:
fixed_list();
explicit fixed_list(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
explicit fixed_list(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
fixed_list(size_type n, const value_type& value);
fixed_list(const this_type& x);
fixed_list(this_type&& x);
fixed_list(this_type&&, const overflow_allocator_type& overflowAllocator);
fixed_list(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_LIST_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_list(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter.
bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot.
bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
// OverflowAllocator
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_list
///////////////////////////////////////////////////////////////////////
// fixed_list
///////////////////////////////////////////////////////////////////////
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_LIST_DEFAULT_NAME);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_LIST_DEFAULT_NAME);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(size_type n)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_LIST_DEFAULT_NAME);
#endif
resize(n);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(size_type n, const value_type& value)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_LIST_DEFAULT_NAME);
#endif
resize(n, value);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(const this_type& x)
: base_type(fixed_allocator_type(mBuffer))
{
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(this_type&& x)
: base_type(fixed_allocator_type(mBuffer))
{
// Since we are a fixed_list, we can't normally swap pointers unless both this and
// x are using using overflow and the overflow allocators are equal. To do:
//if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator()))
//{
// We can swap contents and may need to swap the allocators as well.
//}
// The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
// way then we may want to make a shared implementation.
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
// See comments above.
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
assign(ilist.begin(), ilist.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
template <typename InputIterator>
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_list(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_LIST_DEFAULT_NAME);
#endif
assign(first, last);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
{
if(this != &x)
{
base_type::clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
internalAllocator() = x.internalAllocator(); // The primary effect of this is to copy the overflow allocator.
#endif
base_type::assign(x.begin(), x.end()); // It would probably be better to implement this like list::operator=.
}
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
{
return operator=(x);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::assign(ilist.begin(), ilist.end());
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
get_allocator().reset(mBuffer);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::size_type
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
{
// Note: This implementation isn't right in the case of bEnableOverflow = true because it will return
// false for the case that there are free nodes from the buffer but also nodes from the dynamic heap.
// This can happen if the container exceeds the fixed size and then frees some of the nodes from the fixed buffer.
// The only simple fix for this is to take on another member variable which tracks whether this overflow
// has occurred at some point in the past.
return !internalAllocator().can_allocate(); // This is the quickest way of detecting this. has_overflowed uses a different method because it can't use this quick method.
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
{
#if EASTL_FIXED_SIZE_TRACKING_ENABLED // If we can use this faster pathway (as size() may be slow)...
return (internalAllocator().mPool.mnPeakSize > kMaxSize);
#else
return (size() > kMaxSize);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
{
return bEnableOverflow;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline const typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return internalAllocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return internalAllocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
internalAllocator().set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void swap(fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
fixed_list<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
+580
View File
@@ -0,0 +1,580 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a map and multimap which use a fixed size memory
// pool for their nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_MAP_H
#define EASTL_FIXED_MAP_H
#include <EASTL/map.h>
#include <EASTL/fixed_set.h> // Included because fixed_rbtree_base resides here.
#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
namespace eastl
{
/// EASTL_FIXED_MAP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_MAP_DEFAULT_NAME
#define EASTL_FIXED_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_map" // Unless the user overrides something, this is "EASTL fixed_map".
#endif
#ifndef EASTL_FIXED_MULTIMAP_DEFAULT_NAME
#define EASTL_FIXED_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_multimap" // Unless the user overrides something, this is "EASTL fixed_multimap".
#endif
/// EASTL_FIXED_MAP_DEFAULT_ALLOCATOR
/// EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_MAP_DEFAULT_ALLOCATOR
#define EASTL_FIXED_MAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MAP_DEFAULT_NAME)
#endif
#ifndef EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR
#define EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MULTIMAP_DEFAULT_NAME)
#endif
/// fixed_map
///
/// Implements a map with a fixed block of memory identified by the
/// nodeCount template parameter.
///
/// Key The key object (key in the key/value pair).
/// T The mapped object (value in the key/value pair).
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Compare Compare function/object for set ordering.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow = true, typename Compare = eastl::less<Key>, typename OverflowAllocator = EASTLAllocatorType>
class fixed_map : public map<Key, T, Compare, fixed_node_allocator<sizeof(typename map<Key, T>::node_type),
nodeCount, EASTL_ALIGN_OF(eastl::pair<Key, T>), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename map<Key, T>::node_type), nodeCount,
EASTL_ALIGN_OF(eastl::pair<Key, T>), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator> this_type;
typedef map<Key, T, Compare, fixed_allocator_type> base_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::insert;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::mAllocator;
public:
fixed_map();
explicit fixed_map(const overflow_allocator_type& overflowAllocator);
explicit fixed_map(const Compare& compare);
fixed_map(const this_type& x);
fixed_map(this_type&& x);
fixed_map(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_map(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MAP_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_map(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_map
/// fixed_multimap
///
/// Implements a multimap with a fixed block of memory identified by the
/// nodeCount template parameter.
///
/// Key The key object (key in the key/value pair).
/// T The mapped object (value in the key/value pair).
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Compare Compare function/object for set ordering.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow = true, typename Compare = eastl::less<Key>, typename OverflowAllocator = EASTLAllocatorType>
class fixed_multimap : public multimap<Key, T, Compare, fixed_node_allocator<sizeof(typename multimap<Key, T>::node_type),
nodeCount, EASTL_ALIGN_OF(eastl::pair<Key, T>), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename multimap<Key, T>::node_type), nodeCount,
EASTL_ALIGN_OF(eastl::pair<Key, T>), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef multimap<Key, T, Compare, fixed_allocator_type> base_type;
typedef fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::insert;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::mAllocator;
using base_type::get_compare;
public:
fixed_multimap();
fixed_multimap(const overflow_allocator_type& overflowAllocator);
explicit fixed_multimap(const Compare& compare);
fixed_multimap(const this_type& x);
fixed_multimap(this_type&& x);
fixed_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_multimap(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MULTIMAP_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_multimap(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_multimap
///////////////////////////////////////////////////////////////////////
// fixed_map
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(const Compare& compare)
: base_type(compare, fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(const this_type& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(this_type&& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer, overflowAllocator))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME);
#endif
insert(ilist.begin(), ilist.end());
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
template <typename InputIterator>
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_map(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MAP_DEFAULT_NAME);
#endif
insert(first, last);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mBuffer);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::size_type
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline const typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void swap(fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& a,
fixed_map<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
///////////////////////////////////////////////////////////////////////
// fixed_multimap
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(const Compare& compare)
: base_type(compare, fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME);
#endif
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(const this_type& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(this_type&& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer, overflowAllocator))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multimap(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME);
#endif
insert(ilist.begin(), ilist.end());
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
template <typename InputIterator>
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::
fixed_multimap(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTIMAP_DEFAULT_NAME);
#endif
insert(first, last);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mBuffer);
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::size_type
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline const typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void swap(fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& a,
fixed_multimap<Key, T, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
+578
View File
@@ -0,0 +1,578 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a set and multiset which use a fixed size memory
// pool for their nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_SET_H
#define EASTL_FIXED_SET_H
#include <EASTL/set.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_SET_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_SET_DEFAULT_NAME
#define EASTL_FIXED_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_set" // Unless the user overrides something, this is "EASTL fixed_set".
#endif
#ifndef EASTL_FIXED_MULTISET_DEFAULT_NAME
#define EASTL_FIXED_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_multiset" // Unless the user overrides something, this is "EASTL fixed_multiset".
#endif
/// EASTL_FIXED_SET_DEFAULT_ALLOCATOR
/// EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_SET_DEFAULT_ALLOCATOR
#define EASTL_FIXED_SET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_SET_DEFAULT_NAME)
#endif
#ifndef EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR
#define EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_MULTISET_DEFAULT_NAME)
#endif
/// fixed_set
///
/// Implements a set with a fixed block of memory identified by the
/// nodeCount template parameter.
///
/// Template parameters:
/// Key The type of object the set holds (a.k.a. value).
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Compare Compare function/object for set ordering.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename Key, size_t nodeCount, bool bEnableOverflow = true, typename Compare = eastl::less<Key>, typename OverflowAllocator = EASTLAllocatorType>
class fixed_set : public set<Key, Compare, fixed_node_allocator<sizeof(typename set<Key>::node_type),
nodeCount, EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename set<Key>::node_type), nodeCount,
EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef set<Key, Compare, fixed_allocator_type> base_type;
typedef fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::insert;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::mAllocator;
using base_type::get_compare;
public:
fixed_set();
fixed_set(const overflow_allocator_type& overflowAllocator);
explicit fixed_set(const Compare& compare);
fixed_set(const this_type& x);
fixed_set(this_type&& x);
fixed_set(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_set(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SET_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_set(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_set
/// fixed_multiset
///
/// Implements a multiset with a fixed block of memory identified by the
/// nodeCount template parameter.
///
/// Key The type of object the set holds (a.k.a. value).
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the global heap if our object pool is exhausted.
/// Compare Compare function/object for set ordering.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename Key, size_t nodeCount, bool bEnableOverflow = true, typename Compare = eastl::less<Key>, typename OverflowAllocator = EASTLAllocatorType>
class fixed_multiset : public multiset<Key, Compare, fixed_node_allocator<sizeof(typename multiset<Key>::node_type),
nodeCount, EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename multiset<Key>::node_type), nodeCount,
EASTL_ALIGN_OF(Key), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef multiset<Key, Compare, fixed_allocator_type> base_type;
typedef fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator> this_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::size_type size_type;
enum { kMaxSize = nodeCount };
using base_type::insert;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::mAllocator;
public:
fixed_multiset();
fixed_multiset(const overflow_allocator_type& overflowAllocator);
explicit fixed_multiset(const Compare& compare);
fixed_multiset(const this_type& x);
fixed_multiset(this_type&& x);
fixed_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_multiset(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_MULTISET_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_multiset(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_multiset
///////////////////////////////////////////////////////////////////////
// fixed_set
///////////////////////////////////////////////////////////////////////
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(const Compare& compare)
: base_type(compare, fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(const this_type& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(this_type&& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer, overflowAllocator))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME);
#endif
insert(ilist.begin(), ilist.end());
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
template <typename InputIterator>
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_set(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_SET_DEFAULT_NAME);
#endif
insert(first, last);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mBuffer);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::size_type
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline const typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void swap(fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& a,
fixed_set<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
///////////////////////////////////////////////////////////////////////
// fixed_multiset
///////////////////////////////////////////////////////////////////////
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(const Compare& compare)
: base_type(compare, fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME);
#endif
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(const this_type& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(this_type&& x)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(x.get_compare(), fixed_allocator_type(mBuffer, overflowAllocator))
{
mAllocator.copy_overflow_allocator(x.mAllocator);
#if EASTL_NAME_ENABLED
mAllocator.set_name(x.mAllocator.get_name());
#endif
base_type::operator=(x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME);
#endif
insert(ilist.begin(), ilist.end());
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
template <typename InputIterator>
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::fixed_multiset(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
mAllocator.set_name(EASTL_FIXED_MULTISET_DEFAULT_NAME);
#endif
insert(first, last);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(const this_type& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
insert(ilist.begin(), ilist.end());
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::this_type&
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::operator=(this_type&& x)
{
base_type::operator=(x);
return *this;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mBuffer);
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::size_type
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline const typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline typename fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::overflow_allocator_type&
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return mAllocator.get_overflow_allocator();
}
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
mAllocator.set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, size_t nodeCount, bool bEnableOverflow, typename Compare, typename OverflowAllocator>
inline void swap(fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& a,
fixed_multiset<Key, nodeCount, bEnableOverflow, Compare, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
+389
View File
@@ -0,0 +1,389 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements an slist which uses a fixed size memory pool for its nodes.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_SLIST_H
#define EASTL_FIXED_SLIST_H
#include <EASTL/slist.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_SLIST_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_SLIST_DEFAULT_NAME
#define EASTL_FIXED_SLIST_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_slist" // Unless the user overrides something, this is "EASTL fixed_slist".
#endif
/// EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR
#define EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_SLIST_DEFAULT_NAME)
#endif
/// fixed_slist
///
/// fixed_slist is an slist which uses a single block of contiguous memory
/// for its nodes. The purpose of this is to reduce memory usage relative
/// to a conventional memory allocation system (with block headers), to
/// increase allocation speed (often due to avoidance of mutex locks),
/// to increase performance (due to better memory locality), and to decrease
/// memory fragmentation due to the way that fixed block allocators work.
///
/// The primary downside to a fixed_slist is that the number of nodes it
/// can contain is fixed upon its declaration. If you want a fixed_slist
/// that doesn't have this limitation, then you probably don't want a
/// fixed_slist. You can always create your own memory allocator that works
/// the way you want.
///
/// Template parameters:
/// T The type of object the slist holds.
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
class fixed_slist : public slist<T, fixed_node_allocator<sizeof(typename slist<T>::node_type),
nodeCount, EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_node_allocator<sizeof(typename slist<T>::node_type), nodeCount,
EASTL_ALIGN_OF(typename slist<T>::node_type), 0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef OverflowAllocator overflow_allocator_type;
typedef slist<T, fixed_allocator_type> base_type;
typedef fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::node_type node_type;
enum { kMaxSize = nodeCount };
using base_type::assign;
using base_type::resize;
using base_type::size;
protected:
char mBuffer[fixed_allocator_type::kBufferSize]; // kBufferSize will take into account alignment requirements.
using base_type::internalAllocator;
public:
fixed_slist();
explicit fixed_slist(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
explicit fixed_slist(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
fixed_slist(size_type n, const value_type& value);
fixed_slist(const this_type& x);
fixed_slist(this_type&& x);
fixed_slist(this_type&&, const overflow_allocator_type&);
fixed_slist(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_SLIST_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_slist(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<value_type> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter.
bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot.
bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
// OverflowAllocator
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_slist
///////////////////////////////////////////////////////////////////////
// slist
///////////////////////////////////////////////////////////////////////
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist()
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(size_type n)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
resize(n);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(size_type n, const value_type& value)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
resize(n, value);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(const this_type& x)
: base_type(fixed_allocator_type(mBuffer))
{
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(this_type&& x)
: base_type(fixed_allocator_type(mBuffer))
{
// Since we are a fixed_list, we can't normally swap pointers unless both this and
// x are using using overflow and the overflow allocators are equal. To do:
//if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator()))
//{
// We can swap contents and may need to swap the allocators as well.
//}
// The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
// way then we may want to make a shared implementation.
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
// See comments above.
internalAllocator().copy_overflow_allocator(x.internalAllocator());
#if EASTL_NAME_ENABLED
internalAllocator().set_name(x.internalAllocator().get_name());
#endif
assign(x.begin(), x.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(std::initializer_list<value_type> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
assign(ilist.begin(), ilist.end());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
template <typename InputIterator>
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_slist(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer))
{
#if EASTL_NAME_ENABLED
internalAllocator().set_name(EASTL_FIXED_SLIST_DEFAULT_NAME);
#endif
assign(first, last);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
{
if(this != &x)
{
base_type::clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
internalAllocator() = x.internalAllocator(); // The primary effect of this is to copy the overflow allocator.
#endif
base_type::assign(x.begin(), x.end()); // It would probably be better to implement this like slist::operator=.
}
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
{
return operator=(x);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<value_type> ilist)
{
base_type::clear();
base_type::assign(ilist.begin(), ilist.end());
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
{
base_type::reset_lose_memory();
base_type::get_allocator().reset(mBuffer);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::size_type
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
{
// Note: This implementation isn't right in the case of bEnableOverflow = true because it will return
// false for the case that there are free nodes from the buffer but also nodes from the dynamic heap.
// This can happen if the container exceeds the fixed size and then frees some of the nodes from the fixed buffer.
return !internalAllocator().can_allocate(); // This is the quickest way of detecting this. has_overflowed uses a different method because it can't use this quick method.
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
{
#if EASTL_FIXED_SIZE_TRACKING_ENABLED // If we can use this faster pathway (as size() may be slow)...
return (internalAllocator().mPool.mnPeakSize > kMaxSize);
#else
return (size() > kMaxSize);
#endif
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
{
return bEnableOverflow;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline const typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return internalAllocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return internalAllocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
internalAllocator().set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void swap(fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
fixed_slist<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
+805
View File
@@ -0,0 +1,805 @@
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a string which uses a fixed size memory pool.
// The bEnableOverflow template parameter allows the container to resort to
// heap allocations if the memory pool is exhausted.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_STRING_H
#define EASTL_FIXED_STRING_H
#include <EASTL/internal/config.h>
#include <EASTL/string.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_STRING_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_STRING_DEFAULT_NAME
#define EASTL_FIXED_STRING_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_string" // Unless the user overrides something, this is "EASTL fixed_string".
#endif
/// fixed_string
///
/// A fixed_string with bEnableOverflow == true is identical to a regular
/// string in terms of its behavior. All the expectations of regular string
/// apply to it and no additional expectations come from it. When bEnableOverflow
/// is false, fixed_string behaves like regular string with the exception that
/// its capacity can never increase. All operations you do on such a fixed_string
/// which require a capacity increase will result in undefined behavior or an
/// C++ allocation exception, depending on the configuration of EASTL.
///
/// Note: The nodeCount value is the amount of characters to allocate, which needs to
/// take into account a terminating zero. Thus if you want to store strings with a strlen
/// of 30, the nodeCount value must be at least 31.
///
/// Template parameters:
/// T The type of object the string holds (char, wchar_t, char8_t, char16_t, char32_t).
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
/// Notes:
/// The nodeCount value must be at least 2, one for a character and one for a terminating 0.
///
/// As of this writing, the string class necessarily reallocates when an insert of
/// self is done into self. As a result, the fixed_string class doesn't support
/// inserting self into self unless the bEnableOverflow template parameter is true.
///
/// Example usage:
/// fixed_string<char, 128 + 1, true> fixedString("hello world"); // Can hold up to a strlen of 128.
///
/// fixedString = "hola mundo";
/// fixedString.clear();
/// fixedString.resize(200);
/// fixedString.sprintf("%f", 1.5f);
///
template <typename T, int nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = EASTLAllocatorType>
class fixed_string : public basic_string<T, fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T),
0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef typename fixed_allocator_type::overflow_allocator_type overflow_allocator_type;
typedef basic_string<T, fixed_allocator_type> base_type;
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::CtorDoNotInitialize CtorDoNotInitialize;
typedef typename base_type::CtorSprintf CtorSprintf;
typedef aligned_buffer<nodeCount * sizeof(T), EASTL_ALIGN_OF(T)> aligned_buffer_type;
enum { kMaxSize = nodeCount - 1 }; // -1 because we need to save one element for the silent terminating null.
using base_type::npos;
using base_type::mPair;
using base_type::append;
using base_type::resize;
using base_type::clear;
using base_type::capacity;
using base_type::size;
using base_type::sprintf_va_list;
using base_type::DoAllocate;
using base_type::DoFree;
using base_type::internalLayout;
using base_type::get_allocator;
protected:
union // We define a union in order to avoid strict pointer aliasing issues with compilers like GCC.
{
value_type mArray[1];
aligned_buffer_type mBuffer; // Question: Why are we doing this aligned_buffer thing? Why not just do an array of value_type, given that we are using just strings of char types.
};
public:
fixed_string();
explicit fixed_string(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
fixed_string(const base_type& x, size_type position, size_type n = base_type::npos); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
fixed_string(const value_type* p, size_type n);
fixed_string(const value_type* p);
fixed_string(size_type n, const value_type& value);
fixed_string(const this_type& x);
fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator);
fixed_string(const base_type& x);
fixed_string(const value_type* pBegin, const value_type* pEnd);
fixed_string(CtorDoNotInitialize, size_type n);
fixed_string(CtorSprintf, const value_type* pFormat, ...);
fixed_string(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator);
fixed_string(this_type&& x);
fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator);
this_type& operator=(const this_type& x);
this_type& operator=(const base_type& x);
this_type& operator=(const value_type* p);
this_type& operator=(const value_type c);
this_type& operator=(std::initializer_list<T> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void set_capacity(size_type n);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const;
bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot.
bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
// The inherited versions of substr/left/right call the basic_string constructor,
// which will call the overflow allocator and fail if bEnableOverflow == false
this_type substr(size_type position, size_type n) const;
this_type left(size_type n) const;
this_type right(size_type n) const;
// OverflowAllocator
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
}; // fixed_string
///////////////////////////////////////////////////////////////////////
// fixed_string
///////////////////////////////////////////////////////////////////////
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string()
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const this_type& x)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
get_allocator().copy_overflow_allocator(x.get_allocator());
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const this_type& x, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
get_allocator().copy_overflow_allocator(x.get_allocator());
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const base_type& x)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const base_type& x, size_type position, size_type n)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x, position, n);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* p, size_type n)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(p, n);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* p)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(p); // There better be enough space to hold the assigned string.
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(size_type n, const value_type& value)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(n, value); // There better be enough space to hold the assigned string.
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(const value_type* pBegin, const value_type* pEnd)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(pBegin, pEnd);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(CtorDoNotInitialize, size_type n)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
if(n < nodeCount)
{
internalLayout().SetHeapSize(n);
*internalLayout().HeapEndPtr() = 0;
}
else
{
internalLayout().SetHeapSize(0);
*internalLayout().HeapEndPtr() = 0;
resize(n);
}
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(CtorSprintf, const value_type* pFormat, ...)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
va_list arguments;
va_start(arguments, pFormat);
sprintf_va_list(pFormat, arguments);
va_end(arguments);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_STRING_DEFAULT_NAME);
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(ilist.begin(), ilist.end());
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(this_type&& x)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
// We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x); // Let x destruct its own items.
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_string(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
// We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapCapacity(nodeCount - 1);
internalLayout().SetHeapSize(0);
*internalLayout().HeapBeginPtr() = 0;
append(x); // Let x destruct its own items.
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
{
if(this != &x)
{
clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
get_allocator() = x.get_allocator();
#endif
append(x);
}
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const base_type& x)
{
if(static_cast<base_type*>(this) != &x)
{
clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
get_allocator() = x.get_allocator();
#endif
append(x);
}
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const value_type* p)
{
if(internalLayout().HeapBeginPtr() != p)
{
clear();
append(p);
}
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const value_type c)
{
clear();
append((size_type)1, c);
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<T> ilist)
{
clear();
append(ilist.begin(), ilist.end());
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
{
// We copy from x instead of trade with it. We need to do so because fixed_ containers use local memory buffers.
// if(static_cast<base_type*>(this) != &x) This should be impossible, so we disable it until proven otherwise.
{
clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
get_allocator() = x.get_allocator();
#endif
append(x); // Let x destruct its own items.
}
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_capacity(size_type n)
{
const size_type nPrevSize = internalLayout().GetSize();
const size_type nPrevCapacity = capacity();
if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)...
n = nPrevSize;
if(n != nPrevCapacity) // If the request results in a capacity change...
{
const size_type allocSize = (n + 1); // +1 because the terminating 0 isn't included in the supplied capacity value. So now n refers the amount of memory we need.
if(can_overflow() && (((uintptr_t)internalLayout().HeapBeginPtr() != (uintptr_t)mBuffer.buffer) || (allocSize > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer...
{
T* const pNewData = (allocSize <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(allocSize);
T* const pCopyEnd = (n < nPrevSize) ? (internalLayout().HeapBeginPtr() + n) : internalLayout().HeapEndPtr();
CharStringUninitializedCopy(internalLayout().HeapBeginPtr(), pCopyEnd, pNewData); // Copy [internalLayout().heap.mpBegin, pCopyEnd) to pNewData.
if((uintptr_t)internalLayout().HeapBeginPtr() != (uintptr_t)mBuffer.buffer)
DoFree(internalLayout().HeapBeginPtr(), internalLayout().GetHeapCapacity() + 1);
internalLayout().SetHeapSize((size_type)(pCopyEnd - internalLayout().HeapBeginPtr()));
internalLayout().SetHeapBeginPtr(pNewData);
internalLayout().SetHeapCapacity(allocSize - 1);
} // Else the new capacity would be within our fixed buffer.
else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity.
resize(n);
}
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
{
internalLayout().SetHeapBeginPtr(mArray);
internalLayout().SetHeapSize(0);
internalLayout().SetHeapCapacity(nodeCount - 1);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
size_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
{
// If size >= capacity, then we are definitely full.
// Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full.
return ((size_t)(internalLayout().HeapEndPtr() - internalLayout().HeapBeginPtr()) >= kMaxSize) || ((void*)internalLayout().HeapBeginPtr() != (void*)mBuffer.buffer);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
{
// This will be incorrect for the case that bOverflowEnabled is true and the container was resized
// down to a small size where the fixed buffer could take over ownership of the data again.
// The only simple fix for this is to take on another member variable which tracks whether this overflow
// has occurred at some point in the past.
return ((void*)internalLayout().HeapBeginPtr() != (void*)mBuffer.buffer);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
{
return bEnableOverflow;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::substr(size_type position, size_type n) const
{
#if EASTL_STRING_OPT_RANGE_ERRORS
if(position > internalLayout().GetSize())
base_type::ThrowRangeException();
#endif
return fixed_string(internalLayout().HeapBeginPtr() + position,
internalLayout().HeapBeginPtr() + position + eastl::min_alt(n, internalLayout().GetSize() - position));
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::left(size_type n) const
{
const size_type nLength = size();
if(n < nLength)
return fixed_string(internalLayout().HeapBeginPtr(), internalLayout().HeapBeginPtr() + n);
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
this_type fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::right(size_type n) const
{
const size_type nLength = size();
if(n < nLength)
return fixed_string(internalLayout().HeapEndPtr() - n, internalLayout().HeapEndPtr());
return *this;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
overflow_allocator_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return get_allocator().get_overflow_allocator();
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::
overflow_allocator_type& fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return get_allocator().get_overflow_allocator();
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
get_allocator().set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
// Operator +
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
// We have a problem here because need to return an fixed_string by value. This will typically result in it
// using stack space equal to its size. That size may be too large to be workable.
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
this_type result(const_cast<this_type&>(a).get_overflow_allocator());
result.append(a);
result.append(b);
return result;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p,
const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p);
this_type result(const_cast<this_type&>(b).get_overflow_allocator());
result.append(p, p + n);
result.append(b);
return result;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c,
const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
this_type result(const_cast<this_type&>(b).get_overflow_allocator());
result.push_back(c);
result.append(b);
return result;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p)
{
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
const typename this_type::size_type n = (typename this_type::size_type)CharStrlen(p);
this_type result(const_cast<this_type&>(a).get_overflow_allocator());
result.append(a);
result.append(p, p + n);
return result;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c)
{
typedef fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
this_type result(const_cast<this_type&>(a).get_overflow_allocator());
result.append(a);
result.push_back(c);
return result;
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& b)
{
a.append(b); // Using an rvalue by name results in it becoming an lvalue.
return eastl::move(a);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
const fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
a.append(b);
return eastl::move(a);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p,
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& b)
{
b.insert(0, p);
return eastl::move(b);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
const typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type* p)
{
a.append(p);
return eastl::move(a);
}
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator> operator+(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>&& a,
typename fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>::value_type c)
{
a.push_back(c);
return eastl::move(a);
}
// operator ==, !=, <, >, <=, >= come from the string implementations.
template <typename T, int nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void swap(fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
fixed_string<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
+275
View File
@@ -0,0 +1,275 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_SUBSTRING_H
#define EASTL_FIXED_SUBSTRING_H
#include <EASTL/string.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
namespace eastl
{
/// fixed_substring
///
/// Implements a string which is a reference to a segment of characters.
/// This class is efficient because it allocates no memory and copies no
/// memory during construction and assignment, but rather refers directly
/// to the segment of chracters. A common use of this is to have a
/// fixed_substring efficiently refer to a substring within another string.
///
/// You cannot directly resize a fixed_substring (e.g. via resize, insert,
/// append, erase), but you can assign a different substring to it.
/// You can modify the characters within a substring in place.
/// As of this writing, in the name of being lean and simple it is the
/// user's responsibility to not call unsupported resizing functions
/// such as those listed above. A detailed listing of the functions which
/// are not supported is given below in the class declaration.
///
/// The c_str function doesn't act as one might hope, as it simply
/// returns the pointer to the beginning of the string segment and the
/// 0-terminator may be beyond the end of the segment. If you want to
/// always be able to use c_str as expected, use the fixed string solution
/// we describe below.
///
/// Another use of fixed_substring is to provide C++ string-like functionality
/// with a C character array. This allows you to work on a C character array
/// as if it were a C++ string as opposed using the C string API. Thus you
/// can do this:
///
/// void DoSomethingForUser(char* timeStr, size_t timeStrCapacity)
/// {
/// fixed_substring tmp(timeStr, timeStrCapacity);
/// tmp = "hello ";
/// tmp += "world";
/// }
///
/// Note that this class constructs and assigns from const string pointers
/// and const string objects, yet this class does not declare its member
/// data as const. This is a concession in order to allow this implementation
/// to be simple and lean. It is the user's responsibility to make sure
/// that strings that should not or can not be modified are either not
/// used by fixed_substring or are not modified by fixed_substring.
///
/// A more flexible alternative to fixed_substring is fixed_string.
/// fixed_string has none of the functional limitations that fixed_substring
/// has and like fixed_substring it doesn't allocate memory. However,
/// fixed_string makes a *copy* of the source string and uses local
/// memory to store that copy. Also, fixed_string objects on the stack
/// are going to have a limit as to their maximum size.
///
/// Notes:
/// As of this writing, the string class necessarily reallocates when
/// an insert of self is done into self. As a result, the fixed_substring
/// class doesn't support inserting self into self.
///
/// Example usage:
/// basic_string<char> str("hello world");
/// fixed_substring<char> sub(str, 2, 5); // sub == "llo w"
///
template <typename T>
class fixed_substring : public basic_string<T>
{
public:
typedef basic_string<T> base_type;
typedef fixed_substring<T> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
using base_type::npos;
using base_type::mPair;
using base_type::AllocateSelf;
using base_type::internalLayout;
using base_type::get_allocator;
private:
void SetInternalHeapLayout(value_type* pBeginPtr, size_type nSize, size_type nCap)
{
internalLayout().SetHeapBeginPtr(pBeginPtr);
internalLayout().SetHeapSize(nSize);
internalLayout().SetHeapCapacity(nCap);
}
public:
fixed_substring()
: base_type()
{
}
fixed_substring(const fixed_substring& x)
: fixed_substring(static_cast<const base_type&>(x))
{}
fixed_substring(const base_type& x)
: base_type()
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
assign(x);
}
// We gain no benefit from having an rvalue move constructor or assignment operator,
// as this class is a const class.
fixed_substring(const base_type& x, size_type position, size_type n = base_type::npos)
: base_type()
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
assign(x, position, n);
}
fixed_substring(const value_type* p, size_type n)
: base_type()
{
assign(p, n);
}
fixed_substring(const value_type* p)
: base_type()
{
assign(p);
}
fixed_substring(const value_type* pBegin, const value_type* pEnd)
: base_type()
{
assign(pBegin, pEnd);
}
~fixed_substring()
{
// We need to reset, as otherwise the parent destructor will
// attempt to free our memory.
AllocateSelf();
}
this_type& operator=(const this_type& x)
{
assign(x);
return *this;
}
this_type& operator=(const base_type& x)
{
assign(x);
return *this;
}
this_type& operator=(const value_type* p)
{
assign(p);
return *this;
}
this_type& assign(const base_type& x)
{
// By design, we need to cast away const-ness here.
SetInternalHeapLayout(const_cast<value_type*>(x.data()), x.size(), x.size());
return *this;
}
this_type& assign(const base_type& x, size_type position, size_type n)
{
// By design, we need to cast away const-ness here.
SetInternalHeapLayout(const_cast<value_type*>(x.data()) + position, n, n);
return *this;
}
this_type& assign(const value_type* p, size_type n)
{
// By design, we need to cast away const-ness here.
SetInternalHeapLayout(const_cast<value_type*>(p), n, n);
return *this;
}
this_type& assign(const value_type* p)
{
// By design, we need to cast away const-ness here.
SetInternalHeapLayout(const_cast<value_type*>(p), (size_type)CharStrlen(p), (size_type)CharStrlen(p));
return *this;
}
this_type& assign(const value_type* pBegin, const value_type* pEnd)
{
// By design, we need to cast away const-ness here.
SetInternalHeapLayout(const_cast<value_type*>(pBegin), (size_type)(pEnd - pBegin), (size_type)(pEnd - pBegin));
return *this;
}
// Partially supported functionality
//
// When using fixed_substring on a character sequence that is within another
// string, the following functions may do one of two things:
// 1 Attempt to reallocate
// 2 Write a 0 char at the end of the fixed_substring
//
// Item #1 will result in a crash, due to the attempt by the underlying
// string class to free the substring memory. Item #2 will result in a 0
// char being written to the character array. Item #2 may or may not be
// a problem, depending on how you use fixed_substring. Thus the following
// functions cannot be used safely.
#if 0 // !defined(EA_COMPILER_NO_DELETED_FUNCTIONS) We may want to enable these deletions after some investigation of possible user impact.
this_type& operator=(value_type c) = delete;
void resize(size_type n, value_type c) = delete;
void resize(size_type n) = delete;
void reserve(size_type = 0) = delete;
void set_capacity(size_type n) = delete;
void clear() = delete;
this_type& operator+=(const base_type& x) = delete;
this_type& operator+=(const value_type* p) = delete;
this_type& operator+=(value_type c) = delete;
this_type& append(const base_type& x) = delete;
this_type& append(const base_type& x, size_type position, size_type n) = delete;
this_type& append(const value_type* p, size_type n) = delete;
this_type& append(const value_type* p) = delete;
this_type& append(size_type n) = delete;
this_type& append(size_type n, value_type c) = delete;
this_type& append(const value_type* pBegin, const value_type* pEnd) = delete;
this_type& append_sprintf_va_list(const value_type* pFormat, va_list arguments) = delete;
this_type& append_sprintf(const value_type* pFormat, ...) = delete;
void push_back(value_type c) = delete;
void pop_back() = delete;
this_type& assign(size_type n, value_type c) = delete;
this_type& insert(size_type position, const base_type& x) = delete;
this_type& insert(size_type position, const base_type& x, size_type beg, size_type n) = delete;
this_type& insert(size_type position, const value_type* p, size_type n) = delete;
this_type& insert(size_type position, const value_type* p) = delete;
this_type& insert(size_type position, size_type n, value_type c) = delete;
iterator insert(const_iterator p, value_type c) = delete;
void insert(const_iterator p, size_type n, value_type c) = delete;
void insert(const_iterator p, const value_type* pBegin, const value_type* pEnd) = delete;
this_type& erase(size_type position = 0, size_type n = npos) = delete;
iterator erase(const_iterator p) = delete;
iterator erase(const_iterator pBegin, const_iterator pEnd) = delete;
void swap(base_type& x) = delete;
this_type& sprintf_va_list(const value_type* pFormat, va_list arguments) = delete;
this_type& sprintf(const value_type* pFormat, ...) = delete;
#endif
}; // fixed_substring
} // namespace eastl
#endif // Header include guard
+625
View File
@@ -0,0 +1,625 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements a vector which uses a fixed size memory pool.
// The bEnableOverflow template parameter allows the container to resort to
// heap allocations if the memory pool is exhausted.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_FIXED_VECTOR_H
#define EASTL_FIXED_VECTOR_H
#include <EASTL/vector.h>
#include <EASTL/internal/fixed_pool.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
namespace eastl
{
/// EASTL_FIXED_VECTOR_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
/// In the case of fixed-size containers, the allocator name always refers
/// to overflow allocations.
///
#ifndef EASTL_FIXED_VECTOR_DEFAULT_NAME
#define EASTL_FIXED_VECTOR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " fixed_vector" // Unless the user overrides something, this is "EASTL fixed_vector".
#endif
/// EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR
///
#ifndef EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR
#define EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR overflow_allocator_type(EASTL_FIXED_VECTOR_DEFAULT_NAME)
#endif
/// fixed_vector
///
/// A fixed_vector with bEnableOverflow == true is identical to a regular
/// vector in terms of its behavior. All the expectations of regular vector
/// apply to it and no additional expectations come from it. When bEnableOverflow
/// is false, fixed_vector behaves like regular vector with the exception that
/// its capacity can never increase. All operations you do on such a fixed_vector
/// which require a capacity increase will result in undefined behavior or an
/// C++ allocation exception, depending on the configuration of EASTL.
///
/// Template parameters:
/// T The type of object the vector holds.
/// nodeCount The max number of objects to contain.
/// bEnableOverflow Whether or not we should use the overflow heap if our object pool is exhausted.
/// OverflowAllocator Overflow allocator, which is only used if bEnableOverflow == true. Defaults to the global heap.
///
/// Note: The nodeCount value must be at least 1.
///
/// Example usage:
/// fixed_vector<Widget, 128, true> fixedVector);
///
/// fixedVector.push_back(Widget());
/// fixedVector.resize(200);
/// fixedVector.clear();
///
template <typename T, size_t nodeCount, bool bEnableOverflow = true, typename OverflowAllocator = typename eastl::type_select<bEnableOverflow, EASTLAllocatorType, EASTLDummyAllocatorType>::type>
class fixed_vector : public vector<T, fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T), 0, bEnableOverflow, OverflowAllocator> >
{
public:
typedef fixed_vector_allocator<sizeof(T), nodeCount, EASTL_ALIGN_OF(T),
0, bEnableOverflow, OverflowAllocator> fixed_allocator_type;
typedef OverflowAllocator overflow_allocator_type;
typedef vector<T, fixed_allocator_type> base_type;
typedef fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::reference reference;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef aligned_buffer<nodeCount * sizeof(T), EASTL_ALIGN_OF(T)> aligned_buffer_type;
enum { kMaxSize = nodeCount };
using base_type::get_allocator;
using base_type::mpBegin;
using base_type::mpEnd;
using base_type::internalCapacityPtr;
using base_type::resize;
using base_type::clear;
using base_type::size;
using base_type::assign;
using base_type::npos;
using base_type::DoAllocate;
using base_type::DoFree;
using base_type::DoAssign;
using base_type::DoAssignFromIterator;
protected:
aligned_buffer_type mBuffer;
public:
fixed_vector();
explicit fixed_vector(const overflow_allocator_type& overflowAllocator); // Only applicable if bEnableOverflow is true.
explicit fixed_vector(size_type n); // Currently we don't support overflowAllocator specification for other constructors, for simplicity.
fixed_vector(size_type n, const value_type& value);
fixed_vector(const this_type& x);
fixed_vector(this_type&& x);
fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator);
fixed_vector(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator = EASTL_FIXED_VECTOR_DEFAULT_ALLOCATOR);
template <typename InputIterator>
fixed_vector(InputIterator first, InputIterator last);
this_type& operator=(const this_type& x);
this_type& operator=(std::initializer_list<T> ilist);
this_type& operator=(this_type&& x);
void swap(this_type& x);
void set_capacity(size_type n);
void clear(bool freeOverflow);
void reset_lose_memory(); // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
size_type max_size() const; // Returns the max fixed size, which is the user-supplied nodeCount parameter.
bool full() const; // Returns true if the fixed space has been fully allocated. Note that if overflow is enabled, the container size can be greater than nodeCount but full() could return true because the fixed space may have a recently freed slot.
bool has_overflowed() const; // Returns true if the allocations spilled over into the overflow allocator. Meaningful only if overflow is enabled.
bool can_overflow() const; // Returns the value of the bEnableOverflow template parameter.
void* push_back_uninitialized();
void push_back(const value_type& value); // We implement push_back here because we have a specialization that's
reference push_back(); // smaller for the case of overflow being disabled.
void push_back(value_type&& value);
// OverflowAllocator
const overflow_allocator_type& get_overflow_allocator() const EA_NOEXCEPT;
overflow_allocator_type& get_overflow_allocator() EA_NOEXCEPT;
void set_overflow_allocator(const overflow_allocator_type& allocator);
protected:
void* DoPushBackUninitialized(true_type);
void* DoPushBackUninitialized(false_type);
void DoPushBack(true_type, const value_type& value);
void DoPushBack(false_type, const value_type& value);
void DoPushBackMove(true_type, value_type&& value);
void DoPushBackMove(false_type, value_type&& value);
reference DoPushBack(false_type);
reference DoPushBack(true_type);
}; // fixed_vector
///////////////////////////////////////////////////////////////////////
// fixed_vector
///////////////////////////////////////////////////////////////////////
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector()
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(size_type n)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
resize(n);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(size_type n, const value_type& value)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
resize(n, value);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(const this_type& x)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
get_allocator().copy_overflow_allocator(x.get_allocator());
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
base_type::template DoAssign<const_iterator, false>(x.begin(), x.end(), false_type());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(this_type&& x)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
// Since we are a fixed_vector, we can't swap pointers. We can possibly so something like fixed_swap or
// we can just do an assignment from x. If we want to do the former then we need to have some complicated
// code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in
// the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case
// a simple assignment is no worse than the fancy pathway.
// Since we are a fixed_list, we can't normally swap pointers unless both this and
// x are using using overflow and the overflow allocators are equal. To do:
//if(has_overflowed() && x.has_overflowed() && (get_overflow_allocator() == x.get_overflow_allocator()))
//{
// We can swap contents and may need to swap the allocators as well.
//}
// The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
// way then we may want to make a shared implementation.
get_allocator().copy_overflow_allocator(x.get_allocator());
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
base_type::template DoAssign<move_iterator<iterator>, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(this_type&& x, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
// See the discussion above.
// The following is currently identical to the fixed_vector(const this_type& x) code above. If it stays that
// way then we may want to make a shared implementation.
get_allocator().copy_overflow_allocator(x.get_allocator());
#if EASTL_NAME_ENABLED
get_allocator().set_name(x.get_allocator().get_name());
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
base_type::template DoAssign<iterator, true>(x.begin(), x.end(), false_type());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(std::initializer_list<T> ilist, const overflow_allocator_type& overflowAllocator)
: base_type(fixed_allocator_type(mBuffer.buffer, overflowAllocator))
{
typedef typename std::initializer_list<value_type>::iterator InputIterator;
typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
base_type::template DoAssignFromIterator<InputIterator, false>(ilist.begin(), ilist.end(), IC());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
template <typename InputIterator>
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::fixed_vector(InputIterator first, InputIterator last)
: base_type(fixed_allocator_type(mBuffer.buffer))
{
#if EASTL_NAME_ENABLED
get_allocator().set_name(EASTL_FIXED_VECTOR_DEFAULT_NAME);
#endif
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
base_type::template DoAssign<InputIterator, false>(first, last, is_integral<InputIterator>());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(const this_type& x)
{
if(this != &x)
{
clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator.
#endif
base_type::template DoAssign<const_iterator, false>(x.begin(), x.end(), false_type()); // Shorter route.
}
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(std::initializer_list<T> ilist)
{
typedef typename std::initializer_list<value_type>::iterator InputIterator;
typedef typename eastl::iterator_traits<InputIterator>::iterator_category IC;
clear();
base_type::template DoAssignFromIterator<InputIterator, false>(ilist.begin(), ilist.end(), IC());
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::this_type&
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::operator=(this_type&& x)
{
// Since we are a fixed_vector, we can't swap pointers. We can possibly do something like fixed_swap or
// we can just do an assignment from x. If we want to do the former then we need to have some complicated
// code to deal with overflow or no overflow, and whether the memory is in the fixed-size buffer or in
// the overflow allocator. 90% of the time the memory should be in the fixed buffer, in which case
// a simple assignment is no worse than the fancy pathway.
if (this != &x)
{
clear();
#if EASTL_ALLOCATOR_COPY_ENABLED
get_allocator() = x.get_allocator(); // The primary effect of this is to copy the overflow allocator.
#endif
base_type::template DoAssign<move_iterator<iterator>, true>(eastl::make_move_iterator(x.begin()), eastl::make_move_iterator(x.end()), false_type()); // Shorter route.
}
return *this;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::swap(this_type& x)
{
if((has_overflowed() && x.has_overflowed()) && (get_overflow_allocator() == x.get_overflow_allocator())) // If both containers are using the heap instead of local memory
{ // then we can do a fast pointer swap instead of content swap.
eastl::swap(mpBegin, x.mpBegin);
eastl::swap(mpEnd, x.mpEnd);
eastl::swap(internalCapacityPtr(), x.internalCapacityPtr());
}
else
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(*this, x);
}
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_capacity(size_type n)
{
const size_type nPrevSize = (size_type)(mpEnd - mpBegin);
const size_type nPrevCapacity = (size_type)(internalCapacityPtr() - mpBegin);
if(n == npos) // If the user means to set the capacity so that it equals the size (i.e. free excess capacity)...
n = nPrevSize;
if(n != nPrevCapacity) // If the request results in a capacity change...
{
if(can_overflow() && (((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer) || (n > kMaxSize))) // If we are or would be using dynamically allocated memory instead of our fixed-size member buffer...
{
T* const pNewData = (n <= kMaxSize) ? (T*)&mBuffer.buffer[0] : DoAllocate(n);
T* const pCopyEnd = (n < nPrevSize) ? (mpBegin + n) : mpEnd;
eastl::uninitialized_move_ptr(mpBegin, pCopyEnd, pNewData); // Move [mpBegin, pCopyEnd) to p.
eastl::destruct(mpBegin, mpEnd);
if((uintptr_t)mpBegin != (uintptr_t)mBuffer.buffer)
DoFree(mpBegin, (size_type)(internalCapacityPtr() - mpBegin));
mpEnd = pNewData + (pCopyEnd - mpBegin);
mpBegin = pNewData;
internalCapacityPtr() = mpBegin + n;
} // Else the new capacity would be within our fixed buffer.
else if(n < nPrevSize) // If the newly requested capacity is less than our size, we do what vector::set_capacity does and resize, even though we actually aren't reducing the capacity.
resize(n);
}
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename Allocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, Allocator>::clear(bool freeOverflow)
{
base_type::clear();
if (freeOverflow && mpBegin != (value_type*)&mBuffer.buffer[0])
{
EASTLFree(get_allocator(), mpBegin, (internalCapacityPtr() - mpBegin) * sizeof(T));
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
}
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reset_lose_memory()
{
mpBegin = mpEnd = (value_type*)&mBuffer.buffer[0];
internalCapacityPtr() = mpBegin + nodeCount;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::size_type
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::max_size() const
{
return kMaxSize;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::full() const
{
// If size >= capacity, then we are definitely full.
// Also, if our size is smaller but we've switched away from mBuffer due to a previous overflow, then we are considered full.
return ((size_t)(mpEnd - mpBegin) >= kMaxSize) || ((void*)mpBegin != (void*)mBuffer.buffer);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::has_overflowed() const
{
// This will be incorrect for the case that bOverflowEnabled is true and the container was resized
// down to a small size where the fixed buffer could take over ownership of the data again.
// The only simple fix for this is to take on another member variable which tracks whether this overflow
// has occurred at some point in the past.
return ((void*)mpBegin != (void*)mBuffer.buffer);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline bool fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::can_overflow() const
{
return bEnableOverflow;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back_uninitialized()
{
return DoPushBackUninitialized(typename type_select<bEnableOverflow, true_type, false_type>::type());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackUninitialized(true_type)
{
return base_type::push_back_uninitialized();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void* fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackUninitialized(false_type)
{
EASTL_ASSERT(mpEnd < internalCapacityPtr());
return mpEnd++;
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back(const value_type& value)
{
DoPushBack(typename type_select<bEnableOverflow, true_type, false_type>::type(), value);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(true_type, const value_type& value)
{
base_type::push_back(value);
}
// This template specializes for overflow NOT enabled.
// In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(false_type, const value_type& value)
{
EASTL_ASSERT(mpEnd < internalCapacityPtr());
::new((void*)mpEnd++) value_type(value);
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back()
{
return DoPushBack(typename type_select<bEnableOverflow, true_type, false_type>::type());
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(true_type)
{
return base_type::push_back();
}
// This template specializes for overflow NOT enabled.
// In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::reference fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBack(false_type)
{
EASTL_ASSERT(mpEnd < internalCapacityPtr());
::new((void*)mpEnd++) value_type; // Note that this isn't value_type() as that syntax doesn't work on all compilers for POD types.
return *(mpEnd - 1); // Same as return back();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::push_back(value_type&& value)
{
DoPushBackMove(typename type_select<bEnableOverflow, true_type, false_type>::type(), eastl::move(value));
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackMove(true_type, value_type&& value)
{
base_type::push_back(eastl::move(value)); // This will call vector::push_back(value_type &&), and possibly swap value with *mpEnd.
}
// This template specializes for overflow NOT enabled.
// In this configuration, there is no need for the heavy weight push_back() which tests to see if the container should grow (it never will)
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::DoPushBackMove(false_type, value_type&& value)
{
EASTL_ASSERT(mpEnd < internalCapacityPtr());
::new((void*)mpEnd++) value_type(eastl::move(value)); // This will call the value_type(value_type&&) constructor, and possibly swap value with *mpEnd.
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline const typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() const EA_NOEXCEPT
{
return get_allocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline typename fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::overflow_allocator_type&
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::get_overflow_allocator() EA_NOEXCEPT
{
return get_allocator().get_overflow_allocator();
}
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>::set_overflow_allocator(const overflow_allocator_type& allocator)
{
get_allocator().set_overflow_allocator(allocator);
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
// operator ==, !=, <, >, <=, >= come from the vector implementations.
template <typename T, size_t nodeCount, bool bEnableOverflow, typename OverflowAllocator>
inline void swap(fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>& a,
fixed_vector<T, nodeCount, bEnableOverflow, OverflowAllocator>& b)
{
// Fixed containers use a special swap that can deal with excessively large buffers.
eastl::fixed_swap(a, b);
}
} // namespace eastl
#endif // Header include guard
File diff suppressed because it is too large Load Diff
+636
View File
@@ -0,0 +1,636 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file is based on the TR1 (technical report 1) reference implementation
// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely
// many or all C++ library vendors' implementations of this classes will be
// based off of the reference version and so will look pretty similar to this
// file as well as other vendors' versions.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_HASH_MAP_H
#define EASTL_HASH_MAP_H
#include <EASTL/internal/config.h>
#include <EASTL/internal/hashtable.h>
#include <EASTL/functional.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
namespace eastl
{
/// EASTL_HASH_MAP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_HASH_MAP_DEFAULT_NAME
#define EASTL_HASH_MAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_map" // Unless the user overrides something, this is "EASTL hash_map".
#endif
/// EASTL_HASH_MULTIMAP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_HASH_MULTIMAP_DEFAULT_NAME
#define EASTL_HASH_MULTIMAP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multimap" // Unless the user overrides something, this is "EASTL hash_multimap".
#endif
/// EASTL_HASH_MAP_DEFAULT_ALLOCATOR
///
#ifndef EASTL_HASH_MAP_DEFAULT_ALLOCATOR
#define EASTL_HASH_MAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MAP_DEFAULT_NAME)
#endif
/// EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR
///
#ifndef EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR
#define EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTIMAP_DEFAULT_NAME)
#endif
/// hash_map
///
/// Implements a hash_map, which is a hashed associative container.
/// Lookups are O(1) (that is, they are fast) but the container is
/// not sorted. Note that lookups are only O(1) if the hash table
/// is well-distributed (non-colliding). The lookup approaches
/// O(n) behavior as the table becomes increasingly poorly distributed.
///
/// set_max_load_factor
/// If you want to make a hashtable never increase its bucket usage,
/// call set_max_load_factor with a very high value such as 100000.f.
///
/// bCacheHashCode
/// We provide the boolean bCacheHashCode template parameter in order
/// to allow the storing of the hash code of the key within the map.
/// When this option is disabled, the rehashing of the table will
/// call the hash function on the key. Setting bCacheHashCode to true
/// is useful for cases whereby the calculation of the hash value for
/// a contained object is very expensive.
///
/// find_as
/// In order to support the ability to have a hashtable of strings but
/// be able to do efficiently lookups via char pointers (i.e. so they
/// aren't converted to string objects), we provide the find_as
/// function. This function allows you to do a find with a key of a
/// type other than the hashtable key type.
///
/// Example find_as usage:
/// hash_map<string, int> hashMap;
/// i = hashMap.find_as("hello"); // Use default hash and compare.
///
/// Example find_as usage (namespaces omitted for brevity):
/// hash_map<string, int> hashMap;
/// i = hashMap.find_as("hello", hash<char*>(), equal_to_2<string, char*>());
///
template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_map
: public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, true>
{
public:
typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
eastl::use_first<eastl::pair<const Key, T> >,
Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, true> base_type;
typedef hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::key_type key_type;
typedef T mapped_type;
typedef typename base_type::value_type value_type; // NOTE: 'value_type = pair<const key_type, mapped_type>'.
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::insert_return_type insert_return_type;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
using base_type::insert;
public:
/// hash_map
///
/// Default constructor.
///
hash_map()
: this_type(EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
{
// Empty
}
/// hash_map
///
/// Constructor which creates an empty container with allocator.
///
explicit hash_map(const allocator_type& allocator)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
/// hash_map
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
/// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
explicit hash_map(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
: base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
hash_map(const this_type& x)
: base_type(x)
{
}
hash_map(this_type&& x)
: base_type(eastl::move(x))
{
}
hash_map(this_type&& x, const allocator_type& allocator)
: base_type(eastl::move(x), allocator)
{
}
/// hash_map
///
/// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_map<int, char*> hm = { {3,"c"}, {4,"d"}, {5,"e"} }; )
///
hash_map(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
: base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
/// hash_map
///
/// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
hash_map(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MAP_DEFAULT_ALLOCATOR)
: base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
this_type& operator=(const this_type& x)
{
return static_cast<this_type&>(base_type::operator=(x));
}
this_type& operator=(std::initializer_list<value_type> ilist)
{
return static_cast<this_type&>(base_type::operator=(ilist));
}
this_type& operator=(this_type&& x)
{
return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
}
/// insert
///
/// This is an extension to the C++ standard. We insert a default-constructed
/// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
{
return base_type::DoInsertKey(true_type(), key);
}
T& at(const key_type& k)
{
iterator it = base_type::find(k);
if (it == base_type::end())
{
#if EASTL_EXCEPTIONS_ENABLED
// throw exeption if exceptions enabled
throw std::out_of_range("invalid hash_map<K, T> key");
#else
// assert false if asserts enabled
EASTL_ASSERT_MSG(false, "invalid hash_map<K, T> key");
#endif
}
// undefined behaviour if exceptions and asserts are disabled and it == end()
return it->second;
}
const T& at(const key_type& k) const
{
const_iterator it = base_type::find(k);
if (it == base_type::end())
{
#if EASTL_EXCEPTIONS_ENABLED
// throw exeption if exceptions enabled
throw std::out_of_range("invalid hash_map<K, T> key");
#else
// assert false if asserts enabled
EASTL_ASSERT_MSG(false, "invalid hash_map<K, T> key");
#endif
}
// undefined behaviour if exceptions and asserts are disabled and it == end()
return it->second;
}
insert_return_type insert(key_type&& key)
{
return base_type::DoInsertKey(true_type(), eastl::move(key));
}
mapped_type& operator[](const key_type& key)
{
return (*base_type::DoInsertKey(true_type(), key).first).second;
// Slower reference version:
//const typename base_type::iterator it = base_type::find(key);
//if(it != base_type::end())
// return (*it).second;
//return (*base_type::insert(value_type(key, mapped_type())).first).second;
}
mapped_type& operator[](key_type&& key)
{
// The Standard states that this function "inserts the value value_type(std::move(key), mapped_type())"
return (*base_type::DoInsertKey(true_type(), eastl::move(key)).first).second;
}
// try_emplace API added in C++17
template <class... Args>
inline insert_return_type try_emplace(const key_type& k, Args&&... args)
{
return try_emplace_forwarding(k, eastl::forward<Args>(args)...);
}
template <class... Args>
inline insert_return_type try_emplace(key_type&& k, Args&&... args) {
return try_emplace_forwarding(eastl::move(k), eastl::forward<Args>(args)...);
}
template <class... Args>
inline iterator try_emplace(const_iterator, const key_type& k, Args&&... args) {
// Currently, the first parameter is ignored.
insert_return_type result = try_emplace(k, eastl::forward<Args>(args)...);
return base_type::DoGetResultIterator(true_type(), result);
}
template <class... Args>
inline iterator try_emplace(const_iterator, key_type&& k, Args&&... args) {
// Currently, the first parameter is ignored.
insert_return_type result = try_emplace(eastl::move(k), eastl::forward<Args>(args)...);
return base_type::DoGetResultIterator(true_type(), result);
}
private:
template <class K, class... Args>
insert_return_type try_emplace_forwarding(K&& k, Args&&... args)
{
const auto key_data = base_type::DoFindKeyData(k);
if (key_data.node)
{ // Node exists, no insertion needed.
return eastl::pair<iterator, bool>(
iterator(key_data.node, base_type::mpBucketArray + key_data.bucket_index), false);
}
else
{
node_type* const pNodeNew =
base_type::DoAllocateNode(piecewise_construct, eastl::forward_as_tuple(eastl::forward<K>(k)),
forward_as_tuple(eastl::forward<Args>(args)...));
// the key might have been moved from above, so we can't use `k` anymore.
const auto& key = base_type::mExtractKey(pNodeNew->mValue);
return base_type::template DoInsertUniqueNode<true>(key, key_data.code, key_data.bucket_index, pNodeNew);
}
}
}; // hash_map
/// hash_map erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_map/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
typename eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
{
i = c.erase(i);
}
else
{
++i;
}
}
return oldSize - c.size();
}
/// hash_multimap
///
/// Implements a hash_multimap, which is the same thing as a hash_map
/// except that contained elements need not be unique. See the
/// documentation for hash_set for details.
///
template <typename Key, typename T, typename Hash = eastl::hash<Key>, typename Predicate = eastl::equal_to<Key>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_multimap
: public hashtable<Key, eastl::pair<const Key, T>, Allocator, eastl::use_first<eastl::pair<const Key, T> >, Predicate,
Hash, mod_range_hashing, default_ranged_hash, prime_rehash_policy, bCacheHashCode, true, false>
{
public:
typedef hashtable<Key, eastl::pair<const Key, T>, Allocator,
eastl::use_first<eastl::pair<const Key, T> >,
Predicate, Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, true, false> base_type;
typedef hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::key_type key_type;
typedef T mapped_type;
typedef typename base_type::value_type value_type; // Note that this is pair<const key_type, mapped_type>.
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::node_type node_type;
typedef typename base_type::insert_return_type insert_return_type;
typedef typename base_type::iterator iterator;
using base_type::insert;
private:
using base_type::insert_or_assign;
public:
/// hash_multimap
///
/// Default constructor.
///
explicit hash_multimap(const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(),
Predicate(), eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
/// hash_multimap
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
/// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
explicit hash_multimap(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
: base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
hash_multimap(const this_type& x)
: base_type(x)
{
}
hash_multimap(this_type&& x)
: base_type(eastl::move(x))
{
}
hash_multimap(this_type&& x, const allocator_type& allocator)
: base_type(eastl::move(x), allocator)
{
}
/// hash_multimap
///
/// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_multimap<int, char*> hm = { {3,"c"}, {3,"C"}, {4,"d"} }; )
///
hash_multimap(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
: base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
/// hash_multimap
///
/// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename ForwardIterator>
hash_multimap(ForwardIterator first, ForwardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTIMAP_DEFAULT_ALLOCATOR)
: base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(),
predicate, eastl::use_first<eastl::pair<const Key, T> >(), allocator)
{
// Empty
}
this_type& operator=(const this_type& x)
{
return static_cast<this_type&>(base_type::operator=(x));
}
this_type& operator=(std::initializer_list<value_type> ilist)
{
return static_cast<this_type&>(base_type::operator=(ilist));
}
this_type& operator=(this_type&& x)
{
return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
}
/// insert
///
/// This is an extension to the C++ standard. We insert a default-constructed
/// element with the given key. The reason for this is that we can avoid the
/// potentially expensive operation of creating and/or copying a mapped_type
/// object on the stack.
insert_return_type insert(const key_type& key)
{
return base_type::DoInsertKey(false_type(), key);
}
insert_return_type insert(key_type&& key)
{
return base_type::DoInsertKey(false_type(), eastl::move(key));
}
}; // hash_multimap
/// hash_multimap erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_multimap/erase_if
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
typename eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
auto oldSize = c.size();
// Erases all elements that satisfy the predicate from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
{
i = c.erase(i);
}
else
{
++i;
}
}
return oldSize - c.size();
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
// We implement branching with the assumption that the return value is usually false.
if(a.size() != b.size())
return false;
// For map (with its unique keys), we need only test that each element in a can be found in b,
// as there can be only one such pairing per element. multimap needs to do a something more elaborate.
for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai)
{
const_iterator bi = b.find(ai->first);
if((bi == biEnd) || !(*ai == *bi)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values.
}
return true;
}
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_map<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
#endif
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
typedef typename eastl::iterator_traits<const_iterator>::difference_type difference_type;
// We implement branching with the assumption that the return value is usually false.
if(a.size() != b.size())
return false;
// We can't simply search for each element of a in b, as it may be that the bucket for
// two elements in a has those same two elements in b but in different order (which should
// still result in equality). Also it's possible that one bucket in a has two elements which
// both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
eastl::pair<const_iterator, const_iterator> aRange;
eastl::pair<const_iterator, const_iterator> bRange;
for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a...
{
aRange = a.equal_range(ai->first); // Get the range of elements in a that are equal to ai.
bRange = b.equal_range(ai->first); // Get the range of elements in b that are equal to ai.
// We need to verify that aRange == bRange. First make sure the range sizes are equivalent...
const difference_type aDistance = eastl::distance(aRange.first, aRange.second);
const difference_type bDistance = eastl::distance(bRange.first, bRange.second);
if(aDistance != bDistance)
return false;
// At this point, aDistance > 0 and aDistance == bDistance.
// Implement a fast pathway for the case that there's just a single element.
if(aDistance == 1)
{
if(!(*aRange.first == *bRange.first)) // We have to compare the values, because lookups are done by keys alone but the full value_type of a map is a key/value pair.
return false; // It's possible that two elements in the two containers have identical keys but different values. Ditto for the permutation case below.
}
else
{
// Check to see if these aRange and bRange are any permutation of each other.
// This check gets slower as there are more elements in the range.
if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
return false;
}
}
return true;
}
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Key, typename T, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multimap<Key, T, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
#endif
} // namespace eastl
#endif // Header include guard
+486
View File
@@ -0,0 +1,486 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file is based on the TR1 (technical report 1) reference implementation
// of the unordered_set/unordered_map C++ classes as of about 4/2005. Most likely
// many or all C++ library vendors' implementations of this classes will be
// based off of the reference version and so will look pretty similar to this
// file as well as other vendors' versions.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_HASH_SET_H
#define EASTL_HASH_SET_H
#include <EASTL/internal/config.h>
#include <EASTL/internal/hashtable.h>
#include <EASTL/functional.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
namespace eastl
{
/// EASTL_HASH_SET_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_HASH_SET_DEFAULT_NAME
#define EASTL_HASH_SET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_set" // Unless the user overrides something, this is "EASTL hash_set".
#endif
/// EASTL_HASH_MULTISET_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_HASH_MULTISET_DEFAULT_NAME
#define EASTL_HASH_MULTISET_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " hash_multiset" // Unless the user overrides something, this is "EASTL hash_multiset".
#endif
/// EASTL_HASH_SET_DEFAULT_ALLOCATOR
///
#ifndef EASTL_HASH_SET_DEFAULT_ALLOCATOR
#define EASTL_HASH_SET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_SET_DEFAULT_NAME)
#endif
/// EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR
///
#ifndef EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR
#define EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR allocator_type(EASTL_HASH_MULTISET_DEFAULT_NAME)
#endif
/// hash_set
///
/// Implements a hash_set, which is a hashed unique-item container.
/// Lookups are O(1) (that is, they are fast) but the container is
/// not sorted. Note that lookups are only O(1) if the hash table
/// is well-distributed (non-colliding). The lookup approaches
/// O(n) behavior as the table becomes increasingly poorly distributed.
///
/// set_max_load_factor
/// If you want to make a hashtable never increase its bucket usage,
/// call set_max_load_factor with a very high value such as 100000.f.
///
/// bCacheHashCode
/// We provide the boolean bCacheHashCode template parameter in order
/// to allow the storing of the hash code of the key within the map.
/// When this option is disabled, the rehashing of the table will
/// call the hash function on the key. Setting bCacheHashCode to true
/// is useful for cases whereby the calculation of the hash value for
/// a contained object is very expensive.
///
/// find_as
/// In order to support the ability to have a hashtable of strings but
/// be able to do efficiently lookups via char pointers (i.e. so they
/// aren't converted to string objects), we provide the find_as
/// function. This function allows you to do a find with a key of a
/// type other than the hashtable key type.
///
/// Example find_as usage:
/// hash_set<string> hashSet;
/// i = hashSet.find_as("hello"); // Use default hash and compare.
///
/// Example find_as usage (namespaces omitted for brevity):
/// hash_set<string> hashSet;
/// i = hashSet.find_as("hello", hash<char*>(), equal_to_2<string, char*>());
///
template <typename Value, typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_set
: public hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, false, true>
{
public:
typedef hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, false, true> base_type;
typedef hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::node_type node_type;
public:
/// hash_set
///
/// Default constructor.
///
hash_set()
: this_type(EASTL_HASH_SET_DEFAULT_ALLOCATOR)
{
// Empty
}
/// hash_set
///
/// Constructor which creates an empty container with allocator.
///
explicit hash_set(const allocator_type& allocator)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
{
// Empty
}
/// hash_set
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
/// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
explicit hash_set(size_type nBucketCount, const Hash& hashFunction = Hash(), const Predicate& predicate = Predicate(),
const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
: base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
hash_set(const this_type& x)
: base_type(x)
{
}
hash_set(this_type&& x)
: base_type(eastl::move(x))
{
}
hash_set(this_type&& x, const allocator_type& allocator)
: base_type(eastl::move(x), allocator)
{
}
/// hash_set
///
/// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_set<int> hs = { 3, 4, 5, }; )
///
hash_set(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
: base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
/// hash_set
///
/// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename FowardIterator>
hash_set(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_SET_DEFAULT_ALLOCATOR)
: base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
this_type& operator=(const this_type& x)
{
return static_cast<this_type&>(base_type::operator=(x));
}
this_type& operator=(std::initializer_list<value_type> ilist)
{
return static_cast<this_type&>(base_type::operator=(ilist));
}
this_type& operator=(this_type&& x)
{
return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
}
}; // hash_set
/// hash_set erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_set/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
typename eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
{
i = c.erase(i);
}
else
{
++i;
}
}
return oldSize - c.size();
}
/// hash_multiset
///
/// Implements a hash_multiset, which is the same thing as a hash_set
/// except that contained elements need not be unique. See the documentation
/// for hash_set for details.
///
template <typename Value, typename Hash = eastl::hash<Value>, typename Predicate = eastl::equal_to<Value>,
typename Allocator = EASTLAllocatorType, bool bCacheHashCode = false>
class hash_multiset
: public hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, false, false>
{
public:
typedef hashtable<Value, Value, Allocator, eastl::use_self<Value>, Predicate,
Hash, mod_range_hashing, default_ranged_hash,
prime_rehash_policy, bCacheHashCode, false, false> base_type;
typedef hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode> this_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::value_type value_type;
typedef typename base_type::allocator_type allocator_type;
typedef typename base_type::node_type node_type;
public:
/// hash_multiset
///
/// Default constructor.
///
explicit hash_multiset(const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
: base_type(0, Hash(), mod_range_hashing(), default_ranged_hash(), Predicate(), eastl::use_self<Value>(), allocator)
{
// Empty
}
/// hash_multiset
///
/// Constructor which creates an empty container, but start with nBucketCount buckets.
/// We default to a small nBucketCount value, though the user really should manually
/// specify an appropriate value in order to prevent memory from being reallocated.
///
explicit hash_multiset(size_type nBucketCount, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
: base_type(nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
hash_multiset(const this_type& x)
: base_type(x)
{
}
hash_multiset(this_type&& x)
: base_type(eastl::move(x))
{
}
hash_multiset(this_type&& x, const allocator_type& allocator)
: base_type(eastl::move(x), allocator)
{
}
/// hash_multiset
///
/// initializer_list-based constructor.
/// Allows for initializing with brace values (e.g. hash_set<int> hs = { 3, 3, 4, }; )
///
hash_multiset(std::initializer_list<value_type> ilist, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
: base_type(ilist.begin(), ilist.end(), nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
/// hash_multiset
///
/// An input bucket count of <= 1 causes the bucket count to be equal to the number of
/// elements in the input range.
///
template <typename FowardIterator>
hash_multiset(FowardIterator first, FowardIterator last, size_type nBucketCount = 0, const Hash& hashFunction = Hash(),
const Predicate& predicate = Predicate(), const allocator_type& allocator = EASTL_HASH_MULTISET_DEFAULT_ALLOCATOR)
: base_type(first, last, nBucketCount, hashFunction, mod_range_hashing(), default_ranged_hash(), predicate, eastl::use_self<Value>(), allocator)
{
// Empty
}
this_type& operator=(const this_type& x)
{
return static_cast<this_type&>(base_type::operator=(x));
}
this_type& operator=(std::initializer_list<value_type> ilist)
{
return static_cast<this_type&>(base_type::operator=(ilist));
}
this_type& operator=(this_type&& x)
{
return static_cast<this_type&>(base_type::operator=(eastl::move(x)));
}
}; // hash_multiset
/// hash_multiset erase_if
///
/// https://en.cppreference.com/w/cpp/container/unordered_multiset/erase_if
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode, typename UserPredicate>
typename eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>::size_type erase_if(eastl::hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& c, UserPredicate predicate)
{
auto oldSize = c.size();
// Erases all elements that satisfy the predicate pred from the container.
for (auto i = c.begin(), last = c.end(); i != last;)
{
if (predicate(*i))
{
i = c.erase(i);
}
else
{
++i;
}
}
return oldSize - c.size();
}
///////////////////////////////////////////////////////////////////////
// global operators
///////////////////////////////////////////////////////////////////////
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
// We implement branching with the assumption that the return value is usually false.
if(a.size() != b.size())
return false;
// For set (with its unique keys), we need only test that each element in a can be found in b,
// as there can be only one such pairing per element. multiset needs to do a something more elaborate.
for(const_iterator ai = a.begin(), aiEnd = a.end(), biEnd = b.end(); ai != aiEnd; ++ai)
{
const_iterator bi = b.find(*ai);
if((bi == biEnd) || !(*ai == *bi)) // We have to compare values in addition to making sure the lookups succeeded. This is because the lookup is done via the user-supplised Predicate
return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so.
}
return true;
}
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_set<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
#endif
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator==(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
typedef typename hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>::const_iterator const_iterator;
typedef typename eastl::iterator_traits<const_iterator>::difference_type difference_type;
// We implement branching with the assumption that the return value is usually false.
if(a.size() != b.size())
return false;
// We can't simply search for each element of a in b, as it may be that the bucket for
// two elements in a has those same two elements in b but in different order (which should
// still result in equality). Also it's possible that one bucket in a has two elements which
// both match a solitary element in the equivalent bucket in b (which shouldn't result in equality).
eastl::pair<const_iterator, const_iterator> aRange;
eastl::pair<const_iterator, const_iterator> bRange;
for(const_iterator ai = a.begin(), aiEnd = a.end(); ai != aiEnd; ai = aRange.second) // For each element in a...
{
aRange = a.equal_range(*ai); // Get the range of elements in a that are equal to ai.
bRange = b.equal_range(*ai); // Get the range of elements in b that are equal to ai.
// We need to verify that aRange == bRange. First make sure the range sizes are equivalent...
const difference_type aDistance = eastl::distance(aRange.first, aRange.second);
const difference_type bDistance = eastl::distance(bRange.first, bRange.second);
if(aDistance != bDistance)
return false;
// At this point, aDistance > 0 and aDistance == bDistance.
// Implement a fast pathway for the case that there's just a single element.
if(aDistance == 1)
{
if(!(*aRange.first == *bRange.first)) // We have to compare values in addition to making sure the distance (element count) was equal. This is because the lookup is done via the user-supplised Predicate
return false; // which isn't strictly required to be identical to the Value operator==, though 99% of the time it will be so. Ditto for the is_permutation usage below.
}
else
{
// Check to see if these aRange and bRange are any permutation of each other.
// This check gets slower as there are more elements in the range.
if(!eastl::is_permutation(aRange.first, aRange.second, bRange.first))
return false;
}
}
return true;
}
#if !defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON)
template <typename Value, typename Hash, typename Predicate, typename Allocator, bool bCacheHashCode>
inline bool operator!=(const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& a,
const hash_multiset<Value, Hash, Predicate, Allocator, bCacheHashCode>& b)
{
return !(a == b);
}
#endif
} // namespace eastl
#endif // Header include guard
+685
View File
@@ -0,0 +1,685 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements heap functionality much like the std C++ heap algorithms.
// Such heaps are not the same thing as memory heaps or pools, but rather are
// semi-sorted random access containers which have the primary purpose of
// supporting the implementation of priority_queue and similar data structures.
//
// The primary distinctions between this heap functionality and std::heap are:
// - This heap exposes some extra functionality such as is_heap and change_heap.
// - This heap is more efficient than versions found in typical STL
// implementations such as STLPort, Microsoft, and Metrowerks. This comes
// about due to better use of array dereferencing and branch prediction.
// You should expect of 5-30%, depending on the usage and platform.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// The publicly usable functions we define are:
// push_heap -- Adds an entry to a heap. Same as C++ std::push_heap.
// pop_heap -- Removes the top entry from a heap. Same as C++ std::pop_heap.
// make_heap -- Converts an array to a heap. Same as C++ std::make_heap.
// sort_heap -- Sorts a heap in place. Same as C++ std::sort_heap.
// remove_heap -- Removes an arbitrary entry from a heap.
// change_heap -- Changes the priority of an entry in the heap.
// is_heap -- Returns true if an array appears is in heap format. Same as C++11 std::is_heap.
// is_heap_until -- Returns largest part of the range which is a heap. Same as C++11 std::is_heap_until.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_HEAP_H
#define EASTL_HEAP_H
#include <EASTL/internal/config.h>
#include <EASTL/iterator.h>
#include <stddef.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
namespace eastl
{
///////////////////////////////////////////////////////////////////////
// promote_heap (internal function)
///////////////////////////////////////////////////////////////////////
template <typename RandomAccessIterator, typename Distance, typename T, typename ValueType>
inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value)
{
for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
(position > topPosition) && eastl::less<ValueType>()(*(first + parentPosition), value);
parentPosition = (position - 1) >> 1)
{
*(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
position = parentPosition;
}
*(first + position) = eastl::forward<ValueType>(value);
}
/// promote_heap
///
/// Moves a value in the heap from a given position upward until
/// it is sorted correctly. It's kind of like bubble-sort, except that
/// instead of moving linearly from the back of a list to the front,
/// it moves from the bottom of the tree up the branches towards the
/// top. But otherwise is just like bubble-sort.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T>
inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
promote_heap_impl<RandomAccessIterator, Distance, const T&, const value_type>(first, topPosition, position, value);
}
/// promote_heap
///
/// Moves a value in the heap from a given position upward until
/// it is sorted correctly. It's kind of like bubble-sort, except that
/// instead of moving linearly from the back of a list to the front,
/// it moves from the bottom of the tree up the branches towards the
/// top. But otherwise is just like bubble-sort.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T>
inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, T&& value)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
promote_heap_impl<RandomAccessIterator, Distance, T&&, value_type>(first, topPosition, position, eastl::forward<T>(value));
}
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare, typename ValueType>
inline void promote_heap_impl(RandomAccessIterator first, Distance topPosition, Distance position, T value, Compare compare)
{
for(Distance parentPosition = (position - 1) >> 1; // This formula assumes that (position > 0). // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
(position > topPosition) && compare(*(first + parentPosition), value);
parentPosition = (position - 1) >> 1)
{
*(first + position) = eastl::forward<ValueType>(*(first + parentPosition)); // Swap the node with its parent.
position = parentPosition;
}
*(first + position) = eastl::forward<ValueType>(value);
}
/// promote_heap
///
/// Takes a Compare(a, b) function (or function object) which returns true if a < b.
/// For example, you could use the standard 'less' comparison object.
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, const T& value, Compare compare)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
promote_heap_impl<RandomAccessIterator, Distance, const T&, Compare, const value_type>(first, topPosition, position, value, compare);
}
/// promote_heap
///
/// Takes a Compare(a, b) function (or function object) which returns true if a < b.
/// For example, you could use the standard 'less' comparison object.
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
inline void promote_heap(RandomAccessIterator first, Distance topPosition, Distance position, T&& value, Compare compare)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
promote_heap_impl<RandomAccessIterator, Distance, T&&, Compare, value_type>(first, topPosition, position, eastl::forward<T>(value), compare);
}
///////////////////////////////////////////////////////////////////////
// adjust_heap (internal function)
///////////////////////////////////////////////////////////////////////
template <typename RandomAccessIterator, typename Distance, typename T, typename ValueType>
void adjust_heap_impl(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T value)
{
// We do the conventional approach of moving the position down to the
// bottom then inserting the value at the back and moving it up.
Distance childPosition = (2 * position) + 2;
for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
{
if(eastl::less<ValueType>()(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
--childPosition;
*(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
position = childPosition;
}
if(childPosition == heapSize) // If we are at the very last index of the bottom...
{
*(first + position) = eastl::forward<ValueType>(*(first + (childPosition - 1)));
position = childPosition - 1;
}
eastl::promote_heap<RandomAccessIterator, Distance, T>(first, topPosition, position, eastl::forward<ValueType>(value));
}
/// adjust_heap
///
/// Given a position that has just been vacated, this function moves
/// new values into that vacated position appropriately. The value
/// argument is an entry which will be inserted into the heap after
/// we move nodes into the positions that were vacated.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T>
void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
adjust_heap_impl<RandomAccessIterator, Distance, const T&, const value_type>(first, topPosition, heapSize, position, eastl::forward<const T&>(value));
}
/// adjust_heap
///
/// Given a position that has just been vacated, this function moves
/// new values into that vacated position appropriately. The value
/// argument is an entry which will be inserted into the heap after
/// we move nodes into the positions that were vacated.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T>
void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T&& value)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
adjust_heap_impl<RandomAccessIterator, Distance, T&&, value_type>(first, topPosition, heapSize, position, eastl::forward<T>(value));
}
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare, typename ValueType>
void adjust_heap_impl(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T value, Compare compare)
{
// We do the conventional approach of moving the position down to the
// bottom then inserting the value at the back and moving it up.
Distance childPosition = (2 * position) + 2;
for(; childPosition < heapSize; childPosition = (2 * childPosition) + 2)
{
if(compare(*(first + childPosition), *(first + (childPosition - 1)))) // Choose the larger of the two children.
--childPosition;
*(first + position) = eastl::forward<ValueType>(*(first + childPosition)); // Swap positions with this child.
position = childPosition;
}
if(childPosition == heapSize) // If we are at the bottom...
{
*(first + position) = eastl::forward<ValueType>(*(first + (childPosition - 1)));
position = childPosition - 1;
}
eastl::promote_heap<RandomAccessIterator, Distance, T, Compare>(first, topPosition, position, eastl::forward<ValueType>(value), compare);
}
/// adjust_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, const T& value, Compare compare)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
adjust_heap_impl<RandomAccessIterator, Distance, const T&, Compare, const value_type>(first, topPosition, heapSize, position, eastl::forward<const T&>(value), compare);
}
/// adjust_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
/// This function requires that the value argument refer to a value
/// that is currently not within the heap.
///
template <typename RandomAccessIterator, typename Distance, typename T, typename Compare>
void adjust_heap(RandomAccessIterator first, Distance topPosition, Distance heapSize, Distance position, T&& value, Compare compare)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
adjust_heap_impl<RandomAccessIterator, Distance, T&&, Compare, value_type>(first, topPosition, heapSize, position, eastl::forward<T>(value), compare);
}
///////////////////////////////////////////////////////////////////////
// push_heap
///////////////////////////////////////////////////////////////////////
/// push_heap
///
/// Adds an item to a heap (which is an array). The item necessarily
/// comes from the back of the heap (array). Thus, the insertion of a
/// new item in a heap is a two step process: push_back and push_heap.
///
/// Example usage:
/// vector<int> heap;
///
/// heap.push_back(3);
/// push_heap(heap.begin(), heap.end()); // Places '3' appropriately.
///
template <typename RandomAccessIterator>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
eastl::promote_heap<RandomAccessIterator, difference_type, value_type>
(first, (difference_type)0, (difference_type)(last - first - 1), eastl::forward<const value_type>(tempBottom));
}
/// push_heap
///
/// This version is useful for cases where your object comparison is unusual
/// or where you want to have the heap store pointers to objects instead of
/// storing the objects themselves (often in order to improve cache coherency
/// while doing sorting).
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Compare>
inline void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type tempBottom(*(last - 1));
eastl::promote_heap<RandomAccessIterator, difference_type, value_type, Compare>
(first, (difference_type)0, (difference_type)(last - first - 1), tempBottom, compare);
}
///////////////////////////////////////////////////////////////////////
// pop_heap
///////////////////////////////////////////////////////////////////////
/// pop_heap
///
/// Removes the first item from the heap (which is an array), and adjusts
/// the heap so that the highest priority item becomes the new first item.
///
/// Example usage:
/// vector<int> heap;
///
/// heap.push_back(2);
/// heap.push_back(3);
/// heap.push_back(1);
/// <use heap[0], which is the highest priority item in the heap>
/// pop_heap(heap.begin(), heap.end()); // Moves heap[0] to the back of the heap and adjusts the heap.
/// heap.pop_back(); // Remove value that was just at the top of the heap
///
template <typename RandomAccessIterator>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
*(last - 1) = eastl::forward<value_type>(*first);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
(first, (difference_type)0, (difference_type)(last - first - 1), 0, eastl::forward<value_type>(tempBottom));
}
/// pop_heap
///
/// This version is useful for cases where your object comparison is unusual
/// or where you want to have the heap store pointers to objects instead of
/// storing the objects themselves (often in order to improve cache coherency
/// while doing sorting).
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Compare>
inline void pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
value_type tempBottom(eastl::forward<value_type>(*(last - 1)));
*(last - 1) = eastl::forward<value_type>(*first);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
(first, (difference_type)0, (difference_type)(last - first - 1), 0, eastl::forward<value_type>(tempBottom), compare);
}
///////////////////////////////////////////////////////////////////////
// make_heap
///////////////////////////////////////////////////////////////////////
/// make_heap
///
/// Given an array, this function converts it into heap format.
/// The complexity is O(n), where n is count of the range.
/// The input range is not required to be in any order.
///
template <typename RandomAccessIterator>
void make_heap(RandomAccessIterator first, RandomAccessIterator last)
{
// We do bottom-up heap construction as per Sedgewick. Such construction is O(n).
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const difference_type heapSize = last - first;
if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below).
{
difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
do{
--parentPosition;
value_type temp(eastl::forward<value_type>(*(first + parentPosition)));
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
(first, parentPosition, heapSize, parentPosition, eastl::forward<value_type>(temp));
} while(parentPosition != 0);
}
}
template <typename RandomAccessIterator, typename Compare>
void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const difference_type heapSize = last - first;
if(heapSize >= 2) // If there is anything to do... (we need this check because otherwise the math fails below).
{
difference_type parentPosition = ((heapSize - 2) >> 1) + 1; // We use '>> 1' instead of '/ 2' because we have seen VC++ generate better code with >>.
do{
--parentPosition;
value_type temp(eastl::forward<value_type>(*(first + parentPosition)));
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
(first, parentPosition, heapSize, parentPosition, eastl::forward<value_type>(temp), compare);
} while(parentPosition != 0);
}
}
///////////////////////////////////////////////////////////////////////
// sort_heap
///////////////////////////////////////////////////////////////////////
/// sort_heap
///
/// After the application if this algorithm, the range it was applied to
/// is no longer a heap, though it will be a reverse heap (smallest first).
/// The item with the lowest priority will be first, and the highest last.
/// This is not a stable sort because the relative order of equivalent
/// elements is not necessarily preserved.
/// The range referenced must be valid; all pointers must be dereferenceable
/// and within the sequence the last position is reachable from the first
/// by incrementation.
/// The complexity is at most O(n * log(n)), where n is count of the range.
///
template <typename RandomAccessIterator>
inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last)
{
for(; (last - first) > 1; --last) // We simply use the heap to sort itself.
eastl::pop_heap<RandomAccessIterator>(first, last);
}
/// sort_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Compare>
inline void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
for(; (last - first) > 1; --last) // We simply use the heap to sort itself.
eastl::pop_heap<RandomAccessIterator, Compare>(first, last, compare);
}
///////////////////////////////////////////////////////////////////////
// remove_heap
///////////////////////////////////////////////////////////////////////
/// remove_heap
///
/// Removes an arbitrary entry from the heap and adjusts the heap appropriately.
/// This function is unlike pop_heap in that pop_heap moves the top item
/// to the back of the heap, whereas remove_heap moves an arbitrary item to
/// the back of the heap.
///
/// Note: Since this function moves the element to the back of the heap and
/// doesn't actually remove it from the given container, the user must call
/// the container erase function if the user wants to erase the element
/// from the container.
///
template <typename RandomAccessIterator, typename Distance>
inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type tempBottom(*(first + heapSize - 1));
*(first + heapSize - 1) = *(first + position);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type>
(first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom);
}
/// remove_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
/// Note: Since this function moves the element to the back of the heap and
/// doesn't actually remove it from the given container, the user must call
/// the container erase function if the user wants to erase the element
/// from the container.
///
template <typename RandomAccessIterator, typename Distance, typename Compare>
inline void remove_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type tempBottom(*(first + heapSize - 1));
*(first + heapSize - 1) = *(first + position);
eastl::adjust_heap<RandomAccessIterator, difference_type, value_type, Compare>
(first, (difference_type)0, (difference_type)(heapSize - 1), (difference_type)position, tempBottom, compare);
}
///////////////////////////////////////////////////////////////////////
// change_heap
///////////////////////////////////////////////////////////////////////
/// change_heap
///
/// Given a value in the heap that has changed in priority, this function
/// adjusts the heap appropriately. The heap size remains unchanged after
/// this operation.
///
template <typename RandomAccessIterator, typename Distance>
inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
eastl::remove_heap<RandomAccessIterator, Distance>(first, heapSize, position);
value_type tempBottom(*(first + heapSize - 1));
eastl::promote_heap<RandomAccessIterator, difference_type, value_type>
(first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom);
}
/// change_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Distance, typename Compare>
inline void change_heap(RandomAccessIterator first, Distance heapSize, Distance position, Compare compare)
{
typedef typename eastl::iterator_traits<RandomAccessIterator>::difference_type difference_type;
typedef typename eastl::iterator_traits<RandomAccessIterator>::value_type value_type;
eastl::remove_heap<RandomAccessIterator, Distance, Compare>(first, heapSize, position, compare);
value_type tempBottom(*(first + heapSize - 1));
eastl::promote_heap<RandomAccessIterator, difference_type, value_type, Compare>
(first, (difference_type)0, (difference_type)(heapSize - 1), tempBottom, compare);
}
///////////////////////////////////////////////////////////////////////
// is_heap_until
///////////////////////////////////////////////////////////////////////
/// is_heap_until
///
template <typename RandomAccessIterator>
inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last)
{
int counter = 0;
for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1)
{
if(*first < *child) // We must use operator <, and are not allowed to use > or >= here.
return child;
first += counter; // counter switches between 0 and 1 every time through.
}
return last;
}
/// is_heap_until
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Compare>
inline RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
int counter = 0;
for(RandomAccessIterator child = first + 1; child < last; ++child, counter ^= 1)
{
if(compare(*first, *child))
return child;
first += counter; // counter switches between 0 and 1 every time through.
}
return last;
}
///////////////////////////////////////////////////////////////////////
// is_heap
///////////////////////////////////////////////////////////////////////
/// is_heap
///
/// This is a useful debugging algorithm for verifying that a random
/// access container is in heap format.
///
template <typename RandomAccessIterator>
inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
{
return (eastl::is_heap_until(first, last) == last);
}
/// is_heap
///
/// The Compare function must work equivalently to the compare function used
/// to make and maintain the heap.
///
template <typename RandomAccessIterator, typename Compare>
inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare compare)
{
return (eastl::is_heap_until(first, last, compare) == last);
}
// To consider: The following may be a faster implementation for most cases.
//
// template <typename RandomAccessIterator>
// inline bool is_heap(RandomAccessIterator first, RandomAccessIterator last)
// {
// if(((uintptr_t)(last - first) & 1) == 0) // If the range has an even number of elements...
// --last;
//
// RandomAccessIterator parent = first, child = (first + 1);
//
// for(; child < last; child += 2, ++parent)
// {
// if((*parent < *child) || (*parent < *(child + 1)))
// return false;
// }
//
// if((((uintptr_t)(last - first) & 1) == 0) && (*parent < *child))
// return false;
//
// return true;
// }
} // namespace eastl
#endif // Header include guard
+96
View File
@@ -0,0 +1,96 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
//
// This file #includes <initializer_list> if it's available, else it defines
// its own version of std::initializer_list. It does not define eastl::initializer_list
// because that would not provide any use, due to how the C++11 Standard works.
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_INITIALIZER_LIST_H
#define EASTL_INITIALIZER_LIST_H
#include <EASTL/internal/config.h>
#include <EABase/eahave.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
#if defined(EA_HAVE_CPP11_INITIALIZER_LIST) // If the compiler can generate calls to std::initializer_list...
// The initializer_list type must be declared in the std namespace, as that's the
// namespace the compiler uses when generating code to use it.
EA_DISABLE_ALL_VC_WARNINGS()
#include <initializer_list>
EA_RESTORE_ALL_VC_WARNINGS()
#else
// If you get an error here about initializer_list being already defined, then the EA_HAVE_CPP11_INITIALIZER_LIST define from <EABase/eahave.h> needs to be updated.
namespace std
{
// See the C++11 Standard, section 18.9.
template<class E>
class initializer_list
{
public:
typedef E value_type;
typedef const E& reference;
typedef const E& const_reference;
typedef size_t size_type;
typedef const E* iterator; // Must be const, as initializer_list (and its mpArray) is an immutable temp object.
typedef const E* const_iterator;
private:
iterator mpArray;
size_type mArraySize;
// This constructor is private, but the C++ compiler has the ability to call it, as per the C++11 Standard.
initializer_list(const_iterator pArray, size_type arraySize)
: mpArray(pArray), mArraySize(arraySize) { }
public:
initializer_list() EA_NOEXCEPT // EA_NOEXCEPT requires a recent version of EABase.
: mpArray(NULL), mArraySize(0) { }
size_type size() const EA_NOEXCEPT { return mArraySize; }
const_iterator begin() const EA_NOEXCEPT { return mpArray; } // Must be const_iterator, as initializer_list (and its mpArray) is an immutable temp object.
const_iterator end() const EA_NOEXCEPT { return mpArray + mArraySize; }
};
template<class T>
const T* begin(std::initializer_list<T> ilist) EA_NOEXCEPT
{
return ilist.begin();
}
template<class T>
const T* end(std::initializer_list<T> ilist) EA_NOEXCEPT
{
return ilist.end();
}
}
#endif
#endif // Header include guard
+65
View File
@@ -0,0 +1,65 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// Include the architecture specific implementations
//
#if defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)
#include "x86/arch_x86.h"
#elif defined(EA_PROCESSOR_ARM32) || defined(EA_PROCESSOR_ARM64)
#include "arm/arch_arm.h"
#endif
/////////////////////////////////////////////////////////////////////////////////
#include "arch_fetch_add.h"
#include "arch_fetch_sub.h"
#include "arch_fetch_and.h"
#include "arch_fetch_xor.h"
#include "arch_fetch_or.h"
#include "arch_add_fetch.h"
#include "arch_sub_fetch.h"
#include "arch_and_fetch.h"
#include "arch_xor_fetch.h"
#include "arch_or_fetch.h"
#include "arch_exchange.h"
#include "arch_cmpxchg_weak.h"
#include "arch_cmpxchg_strong.h"
#include "arch_load.h"
#include "arch_store.h"
#include "arch_compiler_barrier.h"
#include "arch_cpu_pause.h"
#include "arch_memory_barrier.h"
#include "arch_signal_fence.h"
#include "arch_thread_fence.h"
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ADD_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ADD_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_ADD_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_8)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_8)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_16)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_16)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_32)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_32)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_64)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_64)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_128)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_128)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ADD_FETCH_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_AND_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_AND_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_AND_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_8)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_8)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_16)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_16)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_32)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_32)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_64)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_64)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_128)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_128)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_AND_FETCH_H */
@@ -0,0 +1,430 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_STRONG_H
#define EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_STRONG_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128_AVAILABLE 0
#endif
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128(type, ret, ptr, expected, desired)
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_STRONG_H */
@@ -0,0 +1,430 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_WEAK_H
#define EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_WEAK_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128_AVAILABLE 0
#endif
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_8_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_8_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_8(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_8(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_16_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_16_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_16(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_16(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_32_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_32_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_32(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_32(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_64_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_64_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_64(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_64(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_128_AVAILABLE \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128_AVAILABLE
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128(type, ret, ptr, expected, desired)
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_CMPXCHG_WEAK_H */
@@ -0,0 +1,19 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_COMPILER_BARRIER_H
#define EASTL_ATOMIC_INTERNAL_ARCH_COMPILER_BARRIER_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#define EASTL_ARCH_ATOMIC_COMPILER_BARRIER_AVAILABLE 0
#define EASTL_ARCH_ATOMIC_COMPILER_BARRIER_DATA_DEPENDENCY_AVAILABLE 0
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_COMPILER_BARRIER_H */
@@ -0,0 +1,25 @@
/////////////////////////////////////////////////////////////////////////////////
// copyright (c) electronic arts inc. all rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_CPU_PAUSE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_CPU_PAUSE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_PAUSE()
//
#if defined(EASTL_ARCH_ATOMIC_CPU_PAUSE)
#define EASTL_ARCH_ATOMIC_CPU_PAUSE_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CPU_PAUSE_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_CPU_PAUSE_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_EXCHANGE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_EXCHANGE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_EXCHANGE_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_8)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_16)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_32)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_64)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_128)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_EXCHANGE_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_FETCH_ADD_H
#define EASTL_ATOMIC_INTERNAL_ARCH_FETCH_ADD_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_ADD_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_8)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_8)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_16)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_16)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_32)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_32)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_64)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_64)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_128)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_128)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_FETCH_ADD_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_FETCH_AND_H
#define EASTL_ATOMIC_INTERNAL_ARCH_FETCH_AND_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_AND_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_8)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_8)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_16)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_16)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_32)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_32)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_64)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_64)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_128)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_128)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_FETCH_AND_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_FETCH_OR_H
#define EASTL_ATOMIC_INTERNAL_ARCH_FETCH_OR_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_OR_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_8)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_8)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_16)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_16)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_32)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_32)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_64)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_64)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_128)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_128)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_FETCH_OR_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_FETCH_SUB_H
#define EASTL_ATOMIC_INTERNAL_ARCH_FETCH_SUB_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_SUB_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_8)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_8)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_16)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_16)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_32)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_32)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_64)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_64)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_128)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_128)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_FETCH_SUB_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_FETCH_XOR_H
#define EASTL_ATOMIC_INTERNAL_ARCH_FETCH_XOR_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_XOR_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_8)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_8)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_16)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_16)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_32)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_32)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_64)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_64)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_128)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_128)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_FETCH_XOR_H */
@@ -0,0 +1,125 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_LOAD_H
#define EASTL_ATOMIC_INTERNAL_ARCH_LOAD_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr)
//
#if defined(EASTL_ARCH_ATOMIC_LOAD_RELAXED_8)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_RELAXED_16)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_RELAXED_32)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_32)
#define EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_RELAXED_64)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_64)
#define EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_READ_DEPENDS_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_RELAXED_128)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_LOAD_H */
@@ -0,0 +1,47 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_MEMORY_BARRIER_H
#define EASTL_ATOMIC_INTERNAL_ARCH_MEMORY_BARRIER_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_MB()
//
#if defined(EASTL_ARCH_ATOMIC_CPU_MB)
#define EASTL_ARCH_ATOMIC_CPU_MB_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CPU_MB_AVAILABLE 0
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_WMB()
//
#if defined(EASTL_ARCH_ATOMIC_CPU_WMB)
#define EASTL_ARCH_ATOMIC_CPU_WMB_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CPU_WMB_AVAILABLE 0
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_RMB()
//
#if defined(EASTL_ARCH_ATOMIC_CPU_RMB)
#define EASTL_ARCH_ATOMIC_CPU_RMB_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_CPU_RMB_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_MEMORY_BARRIER_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_OR_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_OR_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_OR_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_8)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_8)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_16)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_16)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_32)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_32)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_64)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_64)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_128)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_128)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_OR_FETCH_H */
@@ -0,0 +1,21 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_SIGNAL_FENCE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_SIGNAL_FENCE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#define EASTL_ARCH_ATOMIC_SIGNAL_FENCE_RELAXED_AVAILABLE 0
#define EASTL_ARCH_ATOMIC_SIGNAL_FENCE_ACQUIRE_AVAILABLE 0
#define EASTL_ARCH_ATOMIC_SIGNAL_FENCE_RELEASE_AVAILABLE 0
#define EASTL_ARCH_ATOMIC_SIGNAL_FENCE_ACQ_REL_AVAILABLE 0
#define EASTL_ARCH_ATOMIC_SIGNAL_FENCE_SEQ_CST_AVAILABLE 0
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_SIGNAL_FENCE_H */
@@ -0,0 +1,113 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_STORE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_STORE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_STORE_*_N(type, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_STORE_RELAXED_8)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELEASE_8)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELAXED_16)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELEASE_16)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELAXED_32)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELEASE_32)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELAXED_64)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELEASE_64)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELAXED_128)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_RELEASE_128)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_STORE_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_SUB_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_SUB_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_SUB_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_8)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_8)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_16)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_16)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_32)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_32)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_64)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_64)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_128)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_128)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_SUB_FETCH_H */
@@ -0,0 +1,49 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_THREAD_FENCE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_THREAD_FENCE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_THREAD_FENCE_*()
//
#if defined(EASTL_ARCH_ATOMIC_THREAD_FENCE_RELAXED)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELAXED_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELAXED_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQUIRE)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQUIRE_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQUIRE_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_THREAD_FENCE_RELEASE)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELEASE_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELEASE_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQ_REL)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQ_REL_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQ_REL_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_THREAD_FENCE_H */
@@ -0,0 +1,173 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_XOR_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_XOR_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_XOR_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_8)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_8)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_8)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_8)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_8)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_8_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_8_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_16)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_16)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_16)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_16)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_16)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_16_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_16_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_32)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_32)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_32)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_32)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_32)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_32_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_32_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_64)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_64)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_64)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_64)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_64)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_64_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_64_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_128)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_128)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_128)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_128)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_128_AVAILABLE 0
#endif
#if defined(EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_128)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_128_AVAILABLE 1
#else
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_128_AVAILABLE 0
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_XOR_FETCH_H */
@@ -0,0 +1,89 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ARM_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ARM_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/**
* NOTE: We use this mapping
*
* ARMv7 Mapping 'trailing sync;':
*
* Load Relaxed : ldr
* Load Acquire : ldr; dmb ish
* Load Seq_Cst : ldr; dmb ish
*
* Store Relaxed : str
* Store Release : dmb ish; str
* Store Seq_Cst : dmb ish; str; dmb ish
*
* Relaxed Fence :
* Acquire Fence : dmb ish
* Release Fence : dmb ish
* Acq_Rel Fence : dmb ish
* Seq_Cst Fence : dmb ish
*/
/**
* ARMv7 Mapping 'leading sync;';
*
* Load Relaxed : ldr
* Load Acquire : ldr; dmb ish
* Load Seq_Cst : dmb ish; ldr; dmb ish
*
* Store Relaxed : str
* Store Release : dmb ish; str
* Store Seq_Cst : dmb ish: str
*
* Relaxed Fence :
* Acquire Fence : dmb ish
* Release Fence : dmb ish
* Acq_Rel Fence : dmb ish
* Seq_Cst Fence : dmb ish
*/
/**
* NOTE:
*
* On ARM32/64, we use the 'trailing sync;' convention with the stricter load acquire that uses
* a dmb instead of a control dependency + isb to ensure the IRIW litmus test is satisfied
* as one reason. See EASTL/atomic.h for futher explanation and deep-dive.
*
* For ARMv8 we could move to use the new proper store release and load acquire, RCsc variant.
* All ARMv7 approaches work on ARMv8 and this code path is only used on msvc which isn't used
* heavily. Most of the ARM code will end up going thru clang or gcc since microsoft arm devices
* aren't that abundant.
*/
/////////////////////////////////////////////////////////////////////////////////
#if defined(EA_COMPILER_MSVC)
#if EA_PLATFORM_PTR_SIZE == 8
#define EASTL_ARCH_ATOMIC_HAS_128BIT
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////
#include "arch_arm_load.h"
#include "arch_arm_store.h"
#include "arch_arm_memory_barrier.h"
#include "arch_arm_thread_fence.h"
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ARM_H */
@@ -0,0 +1,156 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ARM_LOAD_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ARM_LOAD_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr)
//
#if defined(EA_COMPILER_MSVC)
/**
* NOTE:
*
* Even 8-byte aligned 64-bit memory accesses on ARM32 are not
* guaranteed to be atomic on all ARM32 cpus. Only guaranteed on
* cpus with the LPAE extension. We need to use a
* ldrexd instruction in order to ensure no shearing is observed
* for all ARM32 processors.
*/
#if defined(EA_PROCESSOR_ARM32)
#define EASTL_ARCH_ATOMIC_ARM32_LDREXD(ret, ptr) \
ret = __ldrexd((ptr))
#endif
#define EASTL_ARCH_ATOMIC_ARM_LOAD_N(integralType, bits, type, ret, ptr) \
{ \
integralType retIntegral; \
retIntegral = EA_PREPROCESSOR_JOIN(__iso_volatile_load, bits)(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr))); \
\
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, retIntegral); \
}
#define EASTL_ARCH_ATOMIC_ARM_LOAD_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_N(__int8, 8, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_ARM_LOAD_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_N(__int16, 16, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_ARM_LOAD_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_N(__int32, 32, type, ret, ptr)
#if defined(EA_PROCESSOR_ARM32)
#define EASTL_ARCH_ATOMIC_LOAD_64(type, ret, ptr) \
{ \
__int64 loadRet64; \
EASTL_ARCH_ATOMIC_ARM32_LDREXD(loadRet64, EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__int64, (ptr))); \
\
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, loadRet64); \
}
#else
#define EASTL_ARCH_ATOMIC_ARM_LOAD_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_N(__int64, 64, type, ret, ptr)
#endif
/**
* NOTE:
*
* The ARM documentation states the following:
* A 64-bit pair requires the address to be quadword aligned and is single-copy atomic for each doubleword at doubleword granularity
*
* Thus we must ensure the store succeeds inorder for the load to be observed as atomic.
* Thus we must use the full cmpxchg in order to do a proper atomic load.
*/
#define EASTL_ARCH_ATOMIC_ARM_LOAD_128(type, ret, ptr, MemoryOrder) \
{ \
bool cmpxchgRetBool; \
ret = *(ptr); \
do \
{ \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_CMPXCHG_STRONG_, MemoryOrder), _128)(type, cmpxchgRetBool, \
ptr, &(ret), ret); \
} while (!cmpxchgRetBool); \
}
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_8(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_16(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_32(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_64(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_128(type, ret, ptr, RELAXED)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_8(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_16(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_32(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_64(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_128(type, ret, ptr, ACQUIRE)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_8(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_16(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_32(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_64(type, ret, ptr); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_ARM_LOAD_128(type, ret, ptr, SEQ_CST)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ARM_LOAD_H */
@@ -0,0 +1,97 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ARM_MEMORY_BARRIER_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ARM_MEMORY_BARRIER_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#if defined(EA_COMPILER_MSVC) && !defined(EA_COMPILER_CLANG_CL)
#if defined(EA_PROCESSOR_ARM32)
#define EASTL_ARM_DMB_ISH _ARM_BARRIER_ISH
#define EASTL_ARM_DMB_ISHST _ARM_BARRIER_ISHST
#define EASTL_ARM_DMB_ISHLD _ARM_BARRIER_ISH
#elif defined(EA_PROCESSOR_ARM64)
#define EASTL_ARM_DMB_ISH _ARM64_BARRIER_ISH
#define EASTL_ARM_DMB_ISHST _ARM64_BARRIER_ISHST
#define EASTL_ARM_DMB_ISHLD _ARM64_BARRIER_ISHLD
#endif
/**
* NOTE:
*
* While it makes no sense for a hardware memory barrier to not imply a compiler barrier.
* MSVC docs do not explicitly state that, so better to be safe than sorry chasing down
* hard to find bugs due to the compiler deciding to reorder things.
*/
#define EASTL_ARCH_ATOMIC_ARM_EMIT_DMB(option) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
__dmb(option); \
EASTL_ATOMIC_COMPILER_BARRIER()
#elif defined(EA_COMPILER_GNUC) || defined(__clang__)
#define EASTL_ARM_DMB_ISH ish
#define EASTL_ARM_DMB_ISHST ishst
#if defined(EA_PROCESSOR_ARM32)
#define EASTL_ARM_DMB_ISHLD ish
#elif defined(EA_PROCESSOR_ARM64)
#define EASTL_ARM_DMB_ISHLD ishld
#endif
#define EASTL_ARCH_ATOMIC_ARM_EMIT_DMB(option) \
__asm__ __volatile__ ("dmb " EA_STRINGIFY(option) ::: "memory")
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_MB()
//
#define EASTL_ARCH_ATOMIC_CPU_MB() \
EASTL_ARCH_ATOMIC_ARM_EMIT_DMB(EASTL_ARM_DMB_ISH)
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_WMB()
//
#define EASTL_ARCH_ATOMIC_CPU_WMB() \
EASTL_ARCH_ATOMIC_ARM_EMIT_DMB(EASTL_ARM_DMB_ISHST)
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_RMB()
//
#define EASTL_ARCH_ATOMIC_CPU_RMB() \
EASTL_ARCH_ATOMIC_ARM_EMIT_DMB(EASTL_ARM_DMB_ISHLD)
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ARM_MEMORY_BARRIER_H */
@@ -0,0 +1,142 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ARM_STORE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ARM_STORE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_STORE_*_N(type, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC)
#define EASTL_ARCH_ATOMIC_ARM_STORE_N(integralType, bits, type, ptr, val) \
EA_PREPROCESSOR_JOIN(__iso_volatile_store, bits)(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr)), EASTL_ATOMIC_TYPE_PUN_CAST(integralType, (val)))
#define EASTL_ARCH_ATOMIC_ARM_STORE_8(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_N(__int8, 8, type, ptr, val)
#define EASTL_ARCH_ATOMIC_ARM_STORE_16(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_N(__int16, 16, type, ptr, val)
#define EASTL_ARCH_ATOMIC_ARM_STORE_32(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_N(__int32, 32, type, ptr, val)
#if defined(EA_PROCESSOR_ARM64)
#define EASTL_ARCH_ATOMIC_ARM_STORE_64(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_N(__int64, 64, type, ptr, val)
#endif
#define EASTL_ARCH_ATOMIC_ARM_STORE_128(type, ptr, val, MemoryOrder) \
{ \
type exchange128; EA_UNUSED(exchange128); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_EXCHANGE_, MemoryOrder), _128)(type, exchange128, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_8(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_8(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_16(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_16(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_32(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_32(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_128(type, ptr, val, RELAXED)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_8(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_8(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_16(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_16(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_32(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_32(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_128(type, ptr, val, RELEASE)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_8(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_8(type, ptr, val) ; \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_16(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_16(type, ptr, val); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_32(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_32(type, ptr, val); \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_128(type, ptr, val, SEQ_CST)
#if defined(EA_PROCESSOR_ARM32)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_64(type, ptr, val) \
{ \
type retExchange64; EA_UNUSED(retExchange64); \
EASTL_ATOMIC_EXCHANGE_RELAXED_64(type, retExchange64, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_64(type, ptr, val) \
{ \
type retExchange64; EA_UNUSED(retExchange64); \
EASTL_ATOMIC_EXCHANGE_RELEASE_64(type, retExchange64, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64(type, ptr, val) \
{ \
type retExchange64; EA_UNUSED(retExchange64); \
EASTL_ATOMIC_EXCHANGE_SEQ_CST_64(type, retExchange64, ptr, val); \
}
#elif defined(EA_PROCESSOR_ARM64)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_64(type, ptr, val) \
EASTL_ARCH_ATOMIC_ARM_STORE_64(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_64(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_64(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64(type, ptr, val) \
EASTL_ATOMIC_CPU_MB(); \
EASTL_ARCH_ATOMIC_ARM_STORE_64(type, ptr, val); \
EASTL_ATOMIC_CPU_MB()
#endif
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ARM_STORE_H */
@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_ARM_THREAD_FENCE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_ARM_THREAD_FENCE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_THREAD_FENCE_*()
//
#if defined(EA_COMPILER_MSVC)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELAXED()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQUIRE() \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELEASE() \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQ_REL() \
EASTL_ATOMIC_CPU_MB()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST() \
EASTL_ATOMIC_CPU_MB()
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_ARM_THREAD_FENCE_H */
@@ -0,0 +1,158 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/**
* x86 && x64 Mappings
*
* Load Relaxed : MOV
* Load Acquire : MOV; COMPILER_BARRIER;
* Load Seq_Cst : MOV; COMPILER_BARRIER;
*
* Store Relaxed : MOV
* Store Release : COMPILER_BARRIER; MOV;
* Store Seq_Cst : LOCK XCHG : MOV; MFENCE;
*
* Relaxed Fence :
* Acquire Fence : COMPILER_BARRIER
* Release Fence : COMPILER_BARRIER
* Acq_Rel Fence : COMPILER_BARRIER
* Seq_Cst FENCE : MFENCE
*/
/////////////////////////////////////////////////////////////////////////////////
#if (defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64)
#define EASTL_ARCH_ATOMIC_HAS_128BIT
#elif defined(EA_COMPILER_MSVC)
#if EA_PLATFORM_PTR_SIZE == 8
#define EASTL_ARCH_ATOMIC_HAS_128BIT
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////
/**
* NOTE:
*
* On 32-bit x86 CPUs Intel Pentium and newer, AMD K5 and newer
* and any i586 class of x86 CPUs support only 64-bit cmpxchg
* known as cmpxchg8b.
*
* On these class of cpus we can guarantee that 64-bit loads/stores are
* also atomic by using the SSE2 movq, SSE1 movlps, or x87 fild/fstp instructions.
*
* We support all other atomic operations
* on compilers that only provide this 64-bit cmpxchg instruction
* by wrapping them around the 64-bit cmpxchg8b instruction.
*/
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED(ret, observed, val) \
static_assert(false, "EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED() must be implmented!");
#define EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET(ret, prevObserved, val)
#define EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
EASTL_ATOMIC_LOAD_RELAXED_64(type, ret, ptr); \
do \
{ \
type computedDesired; \
PRE_COMPUTE_DESIRED(computedDesired, ret, (val)); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_CMPXCHG_STRONG_, MemoryOrder), _64)(type, cmpxchgRet, ptr, &(ret), computedDesired); \
} while (!cmpxchgRet); \
POST_COMPUTE_RET(ret, ret, (val)); \
}
#endif
/**
* NOTE:
*
* 64-bit x64 CPUs support only 128-bit cmpxchg known as cmpxchg16b.
*
* We support all other atomic operations by wrapping them around
* the 128-bit cmpxchg16b instruction.
*
* 128-bit loads are only atomic by using the cmpxchg16b instruction.
* SSE 128-bit loads are not guaranteed to be atomic even though some CPUs
* make them atomic such as AMD Ryzen or Intel SandyBridge.
*/
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED(ret, observed, val) \
static_assert(false, "EASTL_ARCH_ATOMIC_X86_NOP_PRE_COMPUTE_DESIRED() must be implmented!");
#define EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET(ret, prevObserved, val)
#define EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, MemoryOrder, PRE_COMPUTE_DESIRED, POST_COMPUTE_RET) \
{ \
EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
/* because the observed value equals the value in *(ptr) thus we optimistically do a non-atomic load. */ \
ret = *(ptr); \
do \
{ \
type computedDesired; \
PRE_COMPUTE_DESIRED(computedDesired, ret, (val)); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_CMPXCHG_STRONG_, MemoryOrder), _128)(type, cmpxchgRet, ptr, &(ret), computedDesired); \
} while (!cmpxchgRet); \
POST_COMPUTE_RET(ret, ret, (val)); \
}
#endif
/////////////////////////////////////////////////////////////////////////////////
#include "arch_x86_fetch_add.h"
#include "arch_x86_fetch_sub.h"
#include "arch_x86_fetch_and.h"
#include "arch_x86_fetch_xor.h"
#include "arch_x86_fetch_or.h"
#include "arch_x86_add_fetch.h"
#include "arch_x86_sub_fetch.h"
#include "arch_x86_and_fetch.h"
#include "arch_x86_xor_fetch.h"
#include "arch_x86_or_fetch.h"
#include "arch_x86_exchange.h"
#include "arch_x86_cmpxchg_weak.h"
#include "arch_x86_cmpxchg_strong.h"
#include "arch_x86_memory_barrier.h"
#include "arch_x86_thread_fence.h"
#include "arch_x86_load.h"
#include "arch_x86_store.h"
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_H */
@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_ADD_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_ADD_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_ADD_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) + (val))
#define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) + (val))
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) + (val))
#define EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) + (val))
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_ADD_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_ADD_FETCH_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_ADD_FETCH_H */
@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_AND_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_AND_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_AND_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) & (val))
#define EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) & (val))
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) & (val))
#define EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) & (val))
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_AND_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_AND_FETCH_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_AND_FETCH_H */
@@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_STRONG_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_STRONG_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired) \
{ \
/* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \
__asm__ __volatile__ ("lock; cmpxchg16b %2\n" /* cmpxchg16b sets/clears ZF */ \
"sete %3" /* If ZF == 1, set the return value to 1 */ \
/* Output Operands */ \
: "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, (expected)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, (expected)))[1]), \
"+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))), \
"=rm"((ret)) \
/* Input Operands */ \
: "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(desired)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(desired)))[1]), \
"a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, (expected)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, (expected)))[1]) \
/* Clobbers */ \
: "memory", "cc"); \
}
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128(type, ret, ptr, expected, desired) \
EASTL_ARCH_ATOMIC_X86_CMPXCHG_STRONG_128_IMPL(type, ret, ptr, expected, desired)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_STRONG_H */
@@ -0,0 +1,52 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_WEAK_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_WEAK_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_*_*_N(type, bool ret, type * ptr, type * expected, type desired)
//
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELAXED_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_RELAXED_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_ACQUIRE_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQUIRE_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_ACQUIRE_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_RELEASE_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_RELEASE_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_ACQ_REL_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_ACQ_REL_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_ACQ_REL_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_RELAXED_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_SEQ_CST_RELAXED_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_ACQUIRE_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_SEQ_CST_ACQUIRE_128(type, ret, ptr, expected, desired)
#define EASTL_ARCH_ATOMIC_CMPXCHG_WEAK_SEQ_CST_SEQ_CST_128(type, ret, ptr, expected, desired) \
EASTL_ATOMIC_CMPXCHG_STRONG_SEQ_CST_SEQ_CST_128(type, ret, ptr, expected, desired)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_CMPXCHG_WEAK_H */
@@ -0,0 +1,91 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_EXCHANGE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_EXCHANGE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_EXCHANGE_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = (val)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, MemoryOrder) \
{ \
EASTL_ATOMIC_DEFAULT_INIT(bool, cmpxchgRet); \
/* This is intentionally a non-atomic 128-bit load which may observe shearing. */ \
/* Either we do not observe *(ptr) but then the cmpxchg will fail and the observed */ \
/* atomic load will be returned. Or the non-atomic load got lucky and the cmpxchg succeeds */ \
/* because the observed value equals the value in *(ptr) thus we optimistically do a non-atomic load. */ \
ret = *(ptr); \
do \
{ \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_CMPXCHG_STRONG_, MemoryOrder), _128)(type, cmpxchgRet, ptr, &(ret), val); \
} while (!cmpxchgRet); \
}
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, RELAXED)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, ACQUIRE)
#define EASTL_ARCH_ATOMIC_EXCHANGE_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, RELEASE)
#define EASTL_ARCH_ATOMIC_EXCHANGE_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, ACQ_REL)
#define EASTL_ARCH_ATOMIC_EXCHANGE_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_EXCHANGE_128(type, ret, ptr, val, SEQ_CST)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_EXCHANGE_H */
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_ADD_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_ADD_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_ADD_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) + (val))
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) + (val))
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_ADD_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_ADD_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_ADD_H */
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_AND_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_AND_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_AND_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) & (val))
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) & (val))
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_AND_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_AND_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_AND_H */
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_OR_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_OR_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_OR_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) | (val))
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) | (val))
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_OR_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_OR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_OR_H */
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_SUB_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_SUB_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_SUB_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) - (val))
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) - (val))
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_SUB_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_SUB_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_SUB_H */
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_XOR_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_XOR_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_FETCH_XOR_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) ^ (val))
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) ^ (val))
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_FETCH_XOR_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_FETCH_XOR_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_NOP_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_FETCH_XOR_H */
@@ -0,0 +1,164 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_LOAD_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_LOAD_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_LOAD_*_N(type, type ret, type * ptr)
//
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
/**
* NOTE:
*
* Since the cmpxchg 128-bit inline assembly does a sete in the asm to set the return boolean,
* it doesn't get dead-store removed even though we don't care about the success of the
* cmpxchg since the compiler cannot reason about what is inside asm blocks.
* Thus this variant just does the minimum required to do an atomic load.
*/
#define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \
{ \
EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected = 0; \
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \
\
/* Compare RDX:RAX with m128. If equal, set ZF and load RCX:RBX into m128. Else, clear ZF and load m128 into RDX:RAX. */ \
__asm__ __volatile__ ("lock; cmpxchg16b %2" /* cmpxchg16b sets/clears ZF */ \
/* Output Operands */ \
: "=a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "=d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
"+m"(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(__uint128_t, (ptr)))) \
/* Input Operands */ \
: "b"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "c"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]), \
"a"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[0]), "d"((EASTL_ATOMIC_TYPE_CAST(uint64_t, &(ret)))[1]) \
/* Clobbers */ \
: "memory", "cc"); \
}
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST)
#elif defined(EA_COMPILER_MSVC)
#if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // >= VS2019
#define EASTL_ARCH_ATOMIC_X86_LOAD_N(integralType, bits, type, ret, ptr) \
{ \
integralType retIntegral; \
retIntegral = EA_PREPROCESSOR_JOIN(__iso_volatile_load, bits)(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr))); \
\
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, retIntegral); \
}
#else
#define EASTL_ARCH_ATOMIC_X86_LOAD_N(integralType, bits, type, ret, ptr) \
{ \
integralType retIntegral; \
retIntegral = (*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr)))); \
\
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, retIntegral); \
}
#endif
#define EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, MemoryOrder) \
{ \
EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 expected{0, 0}; \
ret = EASTL_ATOMIC_TYPE_PUN_CAST(type, expected); \
\
bool cmpxchgRetBool; EA_UNUSED(cmpxchgRetBool); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_CMPXCHG_STRONG_, MemoryOrder), _128)(type, cmpxchgRetBool, ptr, &(ret), ret); \
}
#define EASTL_ARCH_ATOMIC_X86_LOAD_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_N(__int8, 8, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_X86_LOAD_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_N(__int16, 16, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_X86_LOAD_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_N(__int32, 32, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_X86_LOAD_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_N(__int64, 64, type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_8(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_16(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_32(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_64(type, ret, ptr)
#define EASTL_ARCH_ATOMIC_LOAD_RELAXED_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, RELAXED)
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_8(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_16(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_32(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_64(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_ACQUIRE_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, ACQUIRE)
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_8(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_8(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_16(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_16(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_32(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_32(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_64(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_64(type, ret, ptr); \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_LOAD_SEQ_CST_128(type, ret, ptr) \
EASTL_ARCH_ATOMIC_X86_LOAD_128(type, ret, ptr, SEQ_CST)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_LOAD_H */
@@ -0,0 +1,104 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_MEMORY_BARRIER_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_MEMORY_BARRIER_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_MB()
//
#if defined(EA_COMPILER_MSVC)
/**
* NOTE:
* While it makes no sense for a hardware memory barrier to not imply a compiler barrier.
* MSVC docs do not explicitly state that, so better to be safe than sorry chasing down
* hard to find bugs due to the compiler deciding to reorder things.
*/
#if 1
// 4459 : declaration of 'identifier' hides global declaration
// 4456 : declaration of 'identifier' hides previous local declaration
#define EASTL_ARCH_ATOMIC_CPU_MB() \
{ \
EA_DISABLE_VC_WARNING(4459 4456); \
volatile long _; \
_InterlockedExchangeAdd(&_, 0); \
EA_RESTORE_VC_WARNING(); \
}
#else
#define EASTL_ARCH_ATOMIC_CPU_MB() \
EASTL_ATOMIC_COMPILER_BARRIER(); \
_mm_mfence(); \
EASTL_ATOMIC_COMPILER_BARRIER()
#endif
#elif defined(__clang__) || defined(EA_COMPILER_GNUC)
/**
* NOTE:
*
* mfence orders all loads/stores to/from all memory types.
* We only care about ordinary cacheable memory so lighter weight locked instruction
* is far faster than a mfence to get a full memory barrier.
* lock; addl against the top of the stack is good because:
* distinct for every thread so prevents false sharing
* that cacheline is most likely cache hot
*
* We intentionally do it below the stack pointer to avoid false RAW register dependencies,
* in cases where the compiler reads from the stack pointer after the lock; addl instruction
*
* Accounting for Red Zones or Cachelines doesn't provide extra benefit.
*/
#if defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_CPU_MB() \
__asm__ __volatile__ ("lock; addl $0, -4(%%esp)" ::: "memory", "cc")
#elif defined(EA_PROCESSOR_X86_64)
#define EASTL_ARCH_ATOMIC_CPU_MB() \
__asm__ __volatile__ ("lock; addl $0, -8(%%rsp)" ::: "memory", "cc")
#else
#define EASTL_ARCH_ATOMIC_CPU_MB() \
__asm__ __volatile__ ("mfence" ::: "memory")
#endif
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_WMB()
//
#define EASTL_ARCH_ATOMIC_CPU_WMB() \
EASTL_ATOMIC_COMPILER_BARRIER()
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_CPU_RMB()
//
#define EASTL_ARCH_ATOMIC_CPU_RMB() \
EASTL_ATOMIC_COMPILER_BARRIER()
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_MEMORY_BARRIER_H */
@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_OR_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_OR_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_OR_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) | (val))
#define EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) | (val))
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) | (val))
#define EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) | (val))
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_OR_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_OR_FETCH_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_OR_FETCH_H */
@@ -0,0 +1,171 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_STORE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_STORE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_STORE_*_N(type, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC)
#if defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1920) // >= VS2019
#define EASTL_ARCH_ATOMIC_X86_STORE_N(integralType, bits, type, ptr, val) \
EA_PREPROCESSOR_JOIN(__iso_volatile_store, bits)(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr)), EASTL_ATOMIC_TYPE_PUN_CAST(integralType, (val)))
#else
#define EASTL_ARCH_ATOMIC_X86_STORE_N(integralType, bits, type, ptr, val) \
{ \
integralType valIntegral = EASTL_ATOMIC_TYPE_PUN_CAST(integralType, (val)); \
\
(*(EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(integralType, (ptr)))) = valIntegral; \
}
#endif
#define EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, MemoryOrder) \
{ \
type exchange128; EA_UNUSED(exchange128); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_EXCHANGE_, MemoryOrder), _128)(type, exchange128, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_X86_STORE_8(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_N(__int8, 8, type, ptr, val)
#define EASTL_ARCH_ATOMIC_X86_STORE_16(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_N(__int16, 16, type, ptr, val)
#define EASTL_ARCH_ATOMIC_X86_STORE_32(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_N(__int32, 32, type, ptr, val)
#define EASTL_ARCH_ATOMIC_X86_STORE_64(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_N(__int64, 64, type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_8(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_8(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_16(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_16(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_32(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_32(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_64(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_64(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, RELAXED)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_8(type, ptr, val) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
EASTL_ARCH_ATOMIC_X86_STORE_8(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_16(type, ptr, val) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
EASTL_ARCH_ATOMIC_X86_STORE_16(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_32(type, ptr, val) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
EASTL_ARCH_ATOMIC_X86_STORE_32(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_64(type, ptr, val) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
EASTL_ARCH_ATOMIC_X86_STORE_64(type, ptr, val)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, RELEASE)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_8(type, ptr, val) \
{ \
type exchange8; EA_UNUSED(exchange8); \
EASTL_ATOMIC_EXCHANGE_SEQ_CST_8(type, exchange8, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_16(type, ptr, val) \
{ \
type exchange16; EA_UNUSED(exchange16); \
EASTL_ATOMIC_EXCHANGE_SEQ_CST_16(type, exchange16, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_32(type, ptr, val) \
{ \
type exchange32; EA_UNUSED(exchange32); \
EASTL_ATOMIC_EXCHANGE_SEQ_CST_32(type, exchange32, ptr, val); \
}
/**
* NOTE:
*
* Since 64-bit exchange is wrapped around a cmpxchg8b on 32-bit x86, it is
* faster to just do a mov; mfence.
*/
#if defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64(type, ptr, val) \
EASTL_ATOMIC_COMPILER_BARRIER(); \
EASTL_ARCH_ATOMIC_X86_STORE_64(type, ptr, val); \
EASTL_ATOMIC_CPU_MB()
#elif defined(EA_PROCESSOR_X86_64)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_64(type, ptr, val) \
{ \
type exchange64; EA_UNUSED(exchange64); \
EASTL_ATOMIC_EXCHANGE_SEQ_CST_64(type, exchange64, ptr, val); \
}
#endif
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, SEQ_CST)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, MemoryOrder) \
{ \
type exchange128; EA_UNUSED(exchange128); \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_EXCHANGE_, MemoryOrder), _128)(type, exchange128, ptr, val); \
}
#define EASTL_ARCH_ATOMIC_STORE_RELAXED_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, RELAXED)
#define EASTL_ARCH_ATOMIC_STORE_RELEASE_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, RELEASE)
#define EASTL_ARCH_ATOMIC_STORE_SEQ_CST_128(type, ptr, val) \
EASTL_ARCH_ATOMIC_X86_STORE_128(type, ptr, val, SEQ_CST)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_STORE_H */
@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_SUB_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_SUB_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_SUB_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) - (val))
#define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) - (val))
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) - (val))
#define EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) - (val))
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_SUB_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_SUB_FETCH_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_SUB_FETCH_H */
@@ -0,0 +1,42 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_THREAD_FENCE_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_THREAD_FENCE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_THREAD_FENCE_*()
//
#if defined(EA_COMPILER_MSVC)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELAXED()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQUIRE() \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_RELEASE() \
EASTL_ATOMIC_COMPILER_BARRIER()
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_ACQ_REL() \
EASTL_ATOMIC_COMPILER_BARRIER()
#endif
#if defined(EA_COMPILER_MSVC) || defined(__clang__) || defined(EA_COMPILER_GNUC)
#define EASTL_ARCH_ATOMIC_THREAD_FENCE_SEQ_CST() \
EASTL_ATOMIC_CPU_MB()
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_THREAD_FENCE_H */
@@ -0,0 +1,96 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ARCH_X86_XOR_FETCH_H
#define EASTL_ATOMIC_INTERNAL_ARCH_X86_XOR_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ARCH_ATOMIC_XOR_FETCH_*_N(type, type ret, type * ptr, type val)
//
#if defined(EA_COMPILER_MSVC) && defined(EA_PROCESSOR_X86)
#define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) ^ (val))
#define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) ^ (val))
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_64_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#endif
#if ((defined(__clang__) || defined(EA_COMPILER_GNUC)) && defined(EA_PROCESSOR_X86_64))
#define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED(ret, observed, val) \
ret = ((observed) ^ (val))
#define EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET(ret, prevObserved, val) \
ret = ((prevObserved) ^ (val))
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELAXED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQUIRE, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, RELEASE, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, ACQ_REL, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#define EASTL_ARCH_ATOMIC_XOR_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ARCH_ATOMIC_X86_OP_128_IMPL(type, ret, ptr, val, SEQ_CST, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_PRE_COMPUTE_DESIRED, \
EASTL_ARCH_ATOMIC_X86_XOR_FETCH_POST_COMPUTE_RET)
#endif
#endif /* EASTL_ATOMIC_INTERNAL_ARCH_X86_XOR_FETCH_H */
+252
View File
@@ -0,0 +1,252 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_H
#define EASTL_ATOMIC_INTERNAL_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/config.h>
#include <EASTL/internal/move_help.h>
#include <EASTL/internal/memory_base.h>
#include <EASTL/type_traits.h>
#include "atomic_macros.h"
#include "atomic_casts.h"
#include "atomic_memory_order.h"
#include "atomic_asserts.h"
#include "atomic_size_aligned.h"
#include "atomic_base_width.h"
#include "atomic_integral.h"
#include "atomic_pointer.h"
/////////////////////////////////////////////////////////////////////////////////
/**
* NOTE:
*
* All of the actual implementation is done via the ATOMIC_MACROS in the compiler or arch sub folders.
* The C++ code is merely boilerplate around these macros that actually implement the atomic operations.
* The C++ boilerplate is also hidden behind macros.
* This may seem more complicated but this is all meant to reduce copy-pasting and to ensure all operations
* all end up going down to one macro that does the actual implementation.
* The reduced code duplication makes it easier to verify the implementation and reason about it.
* Ensures we do not have to re-implement the same code for compilers that do not support generic builtins such as MSVC.
* Ensures for compilers that have separate intrinsics for different widths, that C++ boilerplate isn't copy-pasted leading to programmer errors.
* Ensures if we ever have to implement a new platform, only the low-level leaf macros have to be implemented, everything else will be generated for you.
*/
#include "atomic_push_compiler_options.h"
namespace eastl
{
namespace internal
{
template <typename T>
struct is_atomic_lockfree_size
{
static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = false ||
#if defined(EASTL_ATOMIC_HAS_8BIT)
sizeof(T) == 1 ||
#endif
#if defined(EASTL_ATOMIC_HAS_16BIT)
sizeof(T) == 2 ||
#endif
#if defined(EASTL_ATOMIC_HAS_32BIT)
sizeof(T) == 4 ||
#endif
#if defined(EASTL_ATOMIC_HAS_64BIT)
sizeof(T) == 8 ||
#endif
#if defined(EASTL_ATOMIC_HAS_128BIT)
sizeof(T) == 16 ||
#endif
false;
};
template <typename T>
struct is_user_type_suitable_for_primary_template
{
static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool value = eastl::internal::is_atomic_lockfree_size<T>::value;
};
template <typename T>
using select_atomic_inherit_0 = typename eastl::conditional<eastl::is_same_v<bool, T> || eastl::internal::is_user_type_suitable_for_primary_template<T>::value,
eastl::internal::atomic_base_width<T>, /* True */
eastl::internal::atomic_invalid_type<T> /* False */
>::type;
template <typename T>
using select_atomic_inherit = select_atomic_inherit_0<T>;
} // namespace internal
#define EASTL_ATOMIC_CLASS_IMPL(type, base, valueType, differenceType) \
private: \
\
EASTL_ATOMIC_STATIC_ASSERT_TYPE(type); \
\
using Base = base; \
\
public: \
\
typedef valueType value_type; \
typedef differenceType difference_type; \
\
public: \
\
static EASTL_CPP17_INLINE_VARIABLE EA_CONSTEXPR_OR_CONST bool is_always_lock_free = eastl::internal::is_atomic_lockfree_size<type>::value; \
\
public: /* deleted ctors && assignment operators */ \
\
atomic(const atomic&) EA_NOEXCEPT = delete; \
\
atomic& operator=(const atomic&) EA_NOEXCEPT = delete; \
atomic& operator=(const atomic&) volatile EA_NOEXCEPT = delete; \
\
public: /* ctors */ \
\
EA_CONSTEXPR atomic(type desired) EA_NOEXCEPT \
: Base{ desired } \
{ \
} \
\
EA_CONSTEXPR atomic() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v<type>) = default; \
\
public: \
\
bool is_lock_free() const EA_NOEXCEPT \
{ \
return eastl::internal::is_atomic_lockfree_size<type>::value; \
} \
\
bool is_lock_free() const volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(type); \
return false; \
}
#define EASTL_ATOMIC_USING_ATOMIC_BASE(type) \
public: \
\
using Base::operator=; \
using Base::store; \
using Base::load; \
using Base::exchange; \
using Base::compare_exchange_weak; \
using Base::compare_exchange_strong; \
\
public: \
\
operator type() const volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
} \
\
operator type() const EA_NOEXCEPT \
{ \
return load(eastl::memory_order_seq_cst); \
}
#define EASTL_ATOMIC_USING_ATOMIC_INTEGRAL() \
public: \
\
using Base::fetch_add; \
using Base::add_fetch; \
\
using Base::fetch_sub; \
using Base::sub_fetch; \
\
using Base::fetch_and; \
using Base::and_fetch; \
\
using Base::fetch_or; \
using Base::or_fetch; \
\
using Base::fetch_xor; \
using Base::xor_fetch; \
\
using Base::operator++; \
using Base::operator--; \
using Base::operator+=; \
using Base::operator-=; \
using Base::operator&=; \
using Base::operator|=; \
using Base::operator^=;
#define EASTL_ATOMIC_USING_ATOMIC_POINTER() \
public: \
\
using Base::fetch_add; \
using Base::add_fetch; \
using Base::fetch_sub; \
using Base::sub_fetch; \
\
using Base::operator++; \
using Base::operator--; \
using Base::operator+=; \
using Base::operator-=;
template <typename T, typename = void>
struct atomic : protected eastl::internal::select_atomic_inherit<T>
{
EASTL_ATOMIC_CLASS_IMPL(T, eastl::internal::select_atomic_inherit<T>, T, T)
EASTL_ATOMIC_USING_ATOMIC_BASE(T)
};
template <typename T>
struct atomic<T, eastl::enable_if_t<eastl::is_integral_v<T> && !eastl::is_same_v<bool, T>>> : protected eastl::internal::atomic_integral_width<T>
{
EASTL_ATOMIC_CLASS_IMPL(T, eastl::internal::atomic_integral_width<T>, T, T)
EASTL_ATOMIC_USING_ATOMIC_BASE(T)
EASTL_ATOMIC_USING_ATOMIC_INTEGRAL()
};
template <typename T>
struct atomic<T*> : protected eastl::internal::atomic_pointer_width<T*>
{
EASTL_ATOMIC_CLASS_IMPL(T*, eastl::internal::atomic_pointer_width<T*>, T*, ptrdiff_t)
EASTL_ATOMIC_USING_ATOMIC_BASE(T*)
EASTL_ATOMIC_USING_ATOMIC_POINTER()
};
} // namespace eastl
#include "atomic_pop_compiler_options.h"
#endif /* EASTL_ATOMIC_INTERNAL_H */
@@ -0,0 +1,75 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_STATIC_ASSERTS_H
#define EASTL_ATOMIC_INTERNAL_STATIC_ASSERTS_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#define EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(type) \
static_assert(!eastl::is_same<type, type>::value, "eastl::atomic<T> : volatile eastl::atomic<T> is not what you expect! Read the docs in EASTL/atomic.h! Use the memory orders to access the atomic object!");
#define EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(type) \
static_assert(!eastl::is_same<type, type>::value, "eastl::atomic<T> : invalid memory order for the given operation!");
#define EASTL_ATOMIC_STATIC_ASSERT_TYPE(type) \
/* User Provided T must not be cv qualified */ \
static_assert(!eastl::is_const<type>::value, "eastl::atomic<T> : Template Typename T cannot be const!"); \
static_assert(!eastl::is_volatile<type>::value, "eastl::atomic<T> : Template Typename T cannot be volatile! Use the memory orders to access the underlying type for the guarantees you need."); \
/* T must satisfy StandardLayoutType */ \
static_assert(eastl::is_standard_layout<type>::value, "eastl::atomic<T> : Must have standard layout!"); \
/* T must be TriviallyCopyable but it does not have to be TriviallyConstructible */ \
static_assert(eastl::is_trivially_copyable<type>::value, "eastl::atomci<T> : Template Typename T must be trivially copyable!"); \
static_assert(eastl::is_copy_constructible<type>::value, "eastl::atomic<T> : Template Typename T must be copy constructible!"); \
static_assert(eastl::is_move_constructible<type>::value, "eastl::atomic<T> : Template Typename T must be move constructible!"); \
static_assert(eastl::is_copy_assignable<type>::value, "eastl::atomic<T> : Template Typename T must be copy assignable!"); \
static_assert(eastl::is_move_assignable<type>::value, "eastl::atomic<T> : Template Typename T must be move assignable!"); \
static_assert(eastl::is_trivially_destructible<type>::value, "eastl::atomic<T> : Must be trivially destructible!"); \
static_assert(eastl::internal::is_atomic_lockfree_size<type>::value, "eastl::atomic<T> : Template Typename T must be a lockfree size!");
#define EASTL_ATOMIC_STATIC_ASSERT_TYPE_IS_OBJECT(type) \
static_assert(eastl::is_object<type>::value, "eastl::atomic<T> : Template Typename T must be an object type!");
#define EASTL_ATOMIC_ASSERT_ALIGNED(alignment) \
EASTL_ASSERT((alignment & (alignment - 1)) == 0); \
EASTL_ASSERT((reinterpret_cast<uintptr_t>(this) & (alignment - 1)) == 0)
namespace eastl
{
namespace internal
{
template <typename T>
struct atomic_invalid_type
{
/**
* class Test { int i; int j; int k; }; sizeof(Test) == 96 bits
*
* std::atomic allows non-primitive types to be used for the template type.
* This causes the api to degrade to locking for types that cannot fit into the lockfree size
* of the target platform such as std::atomic<Test> leading to performance traps.
*
* If this static_assert() fired, this means your template type T is larger than any atomic instruction
* supported on the given platform.
*/
static_assert(!eastl::is_same<T, T>::value, "eastl::atomic<T> : invalid template type T!");
};
} // namespace internal
} // namespace eastl
#endif /* EASTL_ATOMIC_INTERNAL_STATIC_ASSERTS_H */
@@ -0,0 +1,346 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_BASE_WIDTH_H
#define EASTL_ATOMIC_INTERNAL_BASE_WIDTH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include "atomic_push_compiler_options.h"
namespace eastl
{
namespace internal
{
template <typename T, unsigned width = sizeof(T)>
struct atomic_base_width;
/**
* NOTE:
*
* T does not have to be trivially default constructible but it still
* has to be a trivially copyable type for the primary atomic template.
* Thus we must type pun into whatever storage type of the given fixed width
* the platform designates. This ensures T does not have to be trivially constructible.
*/
#define EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) \
EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_FIXED_WIDTH_TYPE_, bits)
#define EASTL_ATOMIC_STORE_FUNC_IMPL(op, bits) \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) fixedWidthDesired = EASTL_ATOMIC_TYPE_PUN_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), desired); \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
EASTL_ATOMIC_TYPE_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), this->GetAtomicAddress()), \
fixedWidthDesired)
#define EASTL_ATOMIC_LOAD_FUNC_IMPL(op, bits) \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) retVal; \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
retVal, \
EASTL_ATOMIC_TYPE_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), this->GetAtomicAddress())); \
return EASTL_ATOMIC_TYPE_PUN_CAST(T, retVal);
#define EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(op, bits) \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) retVal; \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) fixedWidthDesired = EASTL_ATOMIC_TYPE_PUN_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), desired); \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
retVal, \
EASTL_ATOMIC_TYPE_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), this->GetAtomicAddress()), \
fixedWidthDesired); \
return EASTL_ATOMIC_TYPE_PUN_CAST(T, retVal);
#define EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(op, bits) \
EASTL_ATOMIC_DEFAULT_INIT(bool, retVal); \
EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits) fixedWidthDesired = EASTL_ATOMIC_TYPE_PUN_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), desired); \
EA_PREPROCESSOR_JOIN(op, bits)(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), \
retVal, \
EASTL_ATOMIC_TYPE_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), this->GetAtomicAddress()), \
EASTL_ATOMIC_TYPE_CAST(EASTL_ATOMIC_BASE_FIXED_WIDTH_TYPE(bits), &expected), \
fixedWidthDesired); \
return retVal;
#define EASTL_ATOMIC_BASE_OP_JOIN(op, Order) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_, op), Order)
#define EASTL_ATOMIC_BASE_CMPXCHG_FUNCS_IMPL(funcName, cmpxchgOp, bits) \
using Base::funcName; \
\
bool funcName(T& expected, T desired) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _SEQ_CST_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acquire_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQUIRE_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_release_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _RELEASE_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acq_rel_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQ_REL_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _SEQ_CST_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_relaxed_s, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _RELAXED_RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acquire_s, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQUIRE_RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acquire_s, \
eastl::internal::memory_order_acquire_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQUIRE_ACQUIRE_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_release_s, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _RELEASE_RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acq_rel_s, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQ_REL_RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_acq_rel_s, \
eastl::internal::memory_order_acquire_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _ACQ_REL_ACQUIRE_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_seq_cst_s, \
eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _SEQ_CST_RELAXED_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_seq_cst_s, \
eastl::internal::memory_order_acquire_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _SEQ_CST_ACQUIRE_), bits); \
} \
\
bool funcName(T& expected, T desired, \
eastl::internal::memory_order_seq_cst_s, \
eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_CMPXCHG_FUNC_IMPL(EASTL_ATOMIC_BASE_OP_JOIN(cmpxchgOp, _SEQ_CST_SEQ_CST_), bits); \
}
#define EASTL_ATOMIC_BASE_CMPXCHG_WEAK_FUNCS_IMPL(bits) \
EASTL_ATOMIC_BASE_CMPXCHG_FUNCS_IMPL(compare_exchange_weak, CMPXCHG_WEAK, bits)
#define EASTL_ATOMIC_BASE_CMPXCHG_STRONG_FUNCS_IMPL(bits) \
EASTL_ATOMIC_BASE_CMPXCHG_FUNCS_IMPL(compare_exchange_strong, CMPXCHG_STRONG, bits)
#define EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(bytes, bits) \
template <typename T> \
struct atomic_base_width<T, bytes> : public atomic_size_aligned<T> \
{ \
private: \
\
static_assert(EA_ALIGN_OF(atomic_size_aligned<T>) == bytes, "eastl::atomic<T> must be sizeof(T) aligned!"); \
static_assert(EA_ALIGN_OF(atomic_size_aligned<T>) == sizeof(T), "eastl::atomic<T> must be sizeof(T) aligned!"); \
using Base = atomic_size_aligned<T>; \
\
public: /* ctors */ \
\
EA_CONSTEXPR atomic_base_width(T desired) EA_NOEXCEPT \
: Base{ desired } \
{ \
} \
\
EA_CONSTEXPR atomic_base_width() EA_NOEXCEPT_IF(eastl::is_nothrow_default_constructible_v<T>) = default; \
\
atomic_base_width(const atomic_base_width&) EA_NOEXCEPT = delete; \
\
public: /* store */ \
\
using Base::store; \
\
void store(T desired) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STORE_FUNC_IMPL(EASTL_ATOMIC_STORE_SEQ_CST_, bits); \
} \
\
void store(T desired, eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STORE_FUNC_IMPL(EASTL_ATOMIC_STORE_RELAXED_, bits); \
} \
\
void store(T desired, eastl::internal::memory_order_release_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STORE_FUNC_IMPL(EASTL_ATOMIC_STORE_RELEASE_, bits); \
} \
\
void store(T desired, eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STORE_FUNC_IMPL(EASTL_ATOMIC_STORE_SEQ_CST_, bits); \
} \
\
public: /* load */ \
\
using Base::load; \
\
T load() const EA_NOEXCEPT \
{ \
EASTL_ATOMIC_LOAD_FUNC_IMPL(EASTL_ATOMIC_LOAD_SEQ_CST_, bits); \
} \
\
T load(eastl::internal::memory_order_relaxed_s) const EA_NOEXCEPT \
{ \
EASTL_ATOMIC_LOAD_FUNC_IMPL(EASTL_ATOMIC_LOAD_RELAXED_, bits); \
} \
\
T load(eastl::internal::memory_order_acquire_s) const EA_NOEXCEPT \
{ \
EASTL_ATOMIC_LOAD_FUNC_IMPL(EASTL_ATOMIC_LOAD_ACQUIRE_, bits); \
} \
\
T load(eastl::internal::memory_order_seq_cst_s) const EA_NOEXCEPT \
{ \
EASTL_ATOMIC_LOAD_FUNC_IMPL(EASTL_ATOMIC_LOAD_SEQ_CST_, bits); \
} \
\
public: /* exchange */ \
\
using Base::exchange; \
\
T exchange(T desired) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_SEQ_CST_, bits); \
} \
\
T exchange(T desired, eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_RELAXED_, bits); \
} \
\
T exchange(T desired, eastl::internal::memory_order_acquire_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_ACQUIRE_, bits); \
} \
\
T exchange(T desired, eastl::internal::memory_order_release_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_RELEASE_, bits); \
} \
\
T exchange(T desired, eastl::internal::memory_order_acq_rel_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_ACQ_REL_, bits); \
} \
\
T exchange(T desired, eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_EXCHANGE_FUNC_IMPL(EASTL_ATOMIC_EXCHANGE_SEQ_CST_, bits); \
} \
\
public: /* compare_exchange_weak */ \
\
EASTL_ATOMIC_BASE_CMPXCHG_WEAK_FUNCS_IMPL(bits) \
\
public: /* compare_exchange_strong */ \
\
EASTL_ATOMIC_BASE_CMPXCHG_STRONG_FUNCS_IMPL(bits) \
\
public: /* assignment operator */ \
\
using Base::operator=; \
\
T operator=(T desired) EA_NOEXCEPT \
{ \
store(desired, eastl::memory_order_seq_cst); \
return desired; \
} \
\
atomic_base_width& operator=(const atomic_base_width&) EA_NOEXCEPT = delete; \
atomic_base_width& operator=(const atomic_base_width&) volatile EA_NOEXCEPT = delete; \
\
};
#if defined(EASTL_ATOMIC_HAS_8BIT)
EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(1, 8)
#endif
#if defined(EASTL_ATOMIC_HAS_16BIT)
EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(2, 16)
#endif
#if defined(EASTL_ATOMIC_HAS_32BIT)
EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(4, 32)
#endif
#if defined(EASTL_ATOMIC_HAS_64BIT)
EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(8, 64)
#endif
#if defined(EASTL_ATOMIC_HAS_128BIT)
EASTL_ATOMIC_BASE_WIDTH_SPECIALIZE(16, 128)
#endif
} // namespace internal
} // namespace eastl
#include "atomic_pop_compiler_options.h"
#endif /* EASTL_ATOMIC_INTERNAL_BASE_WIDTH_H */
@@ -0,0 +1,190 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_CASTS_H
#define EASTL_ATOMIC_INTERNAL_CASTS_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EASTL/internal/type_transformations.h>
#include <string.h>
namespace eastl
{
namespace internal
{
template <typename T>
EASTL_FORCE_INLINE volatile T* AtomicVolatileCast(T* ptr) EA_NOEXCEPT
{
static_assert(!eastl::is_volatile<volatile T*>::value, "eastl::atomic<T> : pointer must not be volatile, the pointed to type must be volatile!");
static_assert(eastl::is_volatile<volatile T>::value, "eastl::atomic<T> : the pointed to type must be volatile!");
return reinterpret_cast<volatile T*>(ptr);
}
/**
* NOTE:
*
* Some compiler intrinsics do not operate on pointer types thus
* doing atomic operations on pointers must be casted to the suitable
* sized unsigned integral type.
*
* Some compiler intrinsics aren't generics and thus structs must also
* be casted to the appropriate sized unsigned integral type.
*
* Atomic operations on an int* might have to be casted to a uint64_t on
* a platform with 8-byte pointers as an example.
*
* Also doing an atomic operation on a struct, we must ensure that we observe
* the whole struct as one atomic unit with no shearing between the members.
* A load of a struct with two uint32_t members must be one uint64_t load,
* not two separate uint32_t loads, thus casted to the suitable sized
* unsigned integral type.
*/
template <typename Integral, typename T>
EASTL_FORCE_INLINE volatile Integral* AtomicVolatileIntegralCast(T* ptr) EA_NOEXCEPT
{
static_assert(!eastl::is_volatile<volatile Integral*>::value, "eastl::atomic<T> : pointer must not be volatile, the pointed to type must be volatile!");
static_assert(eastl::is_volatile<volatile Integral>::value, "eastl::atomic<T> : the pointed to type must be volatile!");
static_assert(eastl::is_integral<Integral>::value, "eastl::atomic<T> : Integral cast must cast to an Integral type!");
static_assert(sizeof(Integral) == sizeof(T), "eastl::atomic<T> : Integral and T must be same size for casting!");
return reinterpret_cast<volatile Integral*>(ptr);
}
template <typename Integral, typename T>
EASTL_FORCE_INLINE Integral* AtomicIntegralCast(T* ptr) EA_NOEXCEPT
{
static_assert(eastl::is_integral<Integral>::value, "eastl::atomic<T> : Integral cast must cast to an Integral type!");
static_assert(sizeof(Integral) == sizeof(T), "eastl::atomic<T> : Integral and T must be same size for casting!");
return reinterpret_cast<Integral*>(ptr);
}
/**
* NOTE:
*
* These casts are meant to be used with unions or structs of larger types that must be casted
* down to the smaller integral types. Like with 128-bit atomics and msvc intrinsics.
*
* struct Foo128 { __int64 array[2]; }; can be casted to a __int64*
* since a poiter to Foo128 is a pointer to the first member.
*/
template <typename ToType, typename FromType>
EASTL_FORCE_INLINE volatile ToType* AtomicVolatileTypeCast(FromType* ptr) EA_NOEXCEPT
{
static_assert(!eastl::is_volatile<volatile ToType*>::value, "eastl::atomic<T> : pointer must not be volatile, the pointed to type must be volatile!");
static_assert(eastl::is_volatile<volatile ToType>::value, "eastl::atomic<T> : the pointed to type must be volatile!");
return reinterpret_cast<volatile ToType*>(ptr);
}
template <typename ToType, typename FromType>
EASTL_FORCE_INLINE ToType* AtomicTypeCast(FromType* ptr) EA_NOEXCEPT
{
return reinterpret_cast<ToType*>(ptr);
}
/**
* NOTE:
*
* This is a compiler guaranteed safe type punning.
* This is useful when dealing with user defined structs.
* struct Test { uint32_t; unint32_t; };
*
* Example:
* uint64_t atomicLoad = *((volatile uint64_t*)&Test);
* Test load = AtomicTypePunCast<Test, uint64_t>(atomicLoad);
*
* uint64_t comparand = AtomicTypePunCast<uint64_t, Test>(Test);
* cmpxchg(&Test, comparand, desired);
*
* This can be implemented in many different ways depending on the compiler such
* as thru a union, memcpy, reinterpret_cast<Test&>(atomicLoad), etc.
*/
template <typename Pun, typename T, eastl::enable_if_t<!eastl::is_same_v<Pun, T>, int> = 0>
EASTL_FORCE_INLINE Pun AtomicTypePunCast(const T& fromType) EA_NOEXCEPT
{
static_assert(sizeof(Pun) == sizeof(T), "eastl::atomic<T> : Pun and T must be the same size for type punning!");
/**
* aligned_storage ensures we can TypePun objects that aren't trivially default constructible
* but still trivially copyable.
*/
typename eastl::aligned_storage<sizeof(Pun), alignof(Pun)>::type ret;
memcpy(eastl::addressof(ret), eastl::addressof(fromType), sizeof(Pun));
return reinterpret_cast<Pun&>(ret);
}
template <typename Pun, typename T, eastl::enable_if_t<eastl::is_same_v<Pun, T>, int> = 0>
EASTL_FORCE_INLINE Pun AtomicTypePunCast(const T& fromType) EA_NOEXCEPT
{
return fromType;
}
template <typename T>
EASTL_FORCE_INLINE T AtomicNegateOperand(T val) EA_NOEXCEPT
{
static_assert(eastl::is_integral<T>::value, "eastl::atomic<T> : Integral Negation must be an Integral type!");
static_assert(!eastl::is_volatile<T>::value, "eastl::atomic<T> : T must not be volatile!");
return static_cast<T>(0U - static_cast<eastl::make_unsigned_t<T>>(val));
}
EASTL_FORCE_INLINE ptrdiff_t AtomicNegateOperand(ptrdiff_t val) EA_NOEXCEPT
{
return -val;
}
} // namespace internal
} // namespace eastl
/**
* NOTE:
*
* These macros are meant to prevent inclusion hell.
* Also so that it fits with the style of the rest of the atomic macro implementation.
*/
#define EASTL_ATOMIC_VOLATILE_CAST(ptr) \
eastl::internal::AtomicVolatileCast((ptr))
#define EASTL_ATOMIC_VOLATILE_INTEGRAL_CAST(IntegralType, ptr) \
eastl::internal::AtomicVolatileIntegralCast<IntegralType>((ptr))
#define EASTL_ATOMIC_INTEGRAL_CAST(IntegralType, ptr) \
eastl::internal::AtomicIntegralCast<IntegralType>((ptr))
#define EASTL_ATOMIC_VOLATILE_TYPE_CAST(ToType, ptr) \
eastl::internal::AtomicVolatileTypeCast<ToType>((ptr))
#define EASTL_ATOMIC_TYPE_CAST(ToType, ptr) \
eastl::internal::AtomicTypeCast<ToType>((ptr))
#define EASTL_ATOMIC_TYPE_PUN_CAST(PunType, fromType) \
eastl::internal::AtomicTypePunCast<PunType>((fromType))
#define EASTL_ATOMIC_NEGATE_OPERAND(val) \
eastl::internal::AtomicNegateOperand((val))
#endif /* EASTL_ATOMIC_INTERNAL_CASTS_H */
+170
View File
@@ -0,0 +1,170 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNA_ATOMIC_FLAG_H
#define EASTL_ATOMIC_INTERNA_ATOMIC_FLAG_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include "atomic_push_compiler_options.h"
namespace eastl
{
class atomic_flag
{
public: /* ctors */
EA_CONSTEXPR atomic_flag(bool desired) EA_NOEXCEPT
: mFlag{ desired }
{
}
EA_CONSTEXPR atomic_flag() EA_NOEXCEPT
: mFlag{ false }
{
}
public: /* deleted ctors && assignment operators */
atomic_flag(const atomic_flag&) EA_NOEXCEPT = delete;
atomic_flag& operator=(const atomic_flag&) EA_NOEXCEPT = delete;
atomic_flag& operator=(const atomic_flag&) volatile EA_NOEXCEPT = delete;
public: /* clear */
template <typename Order>
void clear(Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
}
template <typename Order>
void clear(Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
}
void clear(eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT
{
mFlag.store(false, eastl::memory_order_relaxed);
}
void clear(eastl::internal::memory_order_release_s) EA_NOEXCEPT
{
mFlag.store(false, eastl::memory_order_release);
}
void clear(eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT
{
mFlag.store(false, eastl::memory_order_seq_cst);
}
void clear() EA_NOEXCEPT
{
mFlag.store(false, eastl::memory_order_seq_cst);
}
public: /* test_and_set */
template <typename Order>
bool test_and_set(Order /*order*/) volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
return false;
}
template <typename Order>
bool test_and_set(Order /*order*/) EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
return false;
}
bool test_and_set(eastl::internal::memory_order_relaxed_s) EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_relaxed);
}
bool test_and_set(eastl::internal::memory_order_acquire_s) EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_acquire);
}
bool test_and_set(eastl::internal::memory_order_release_s) EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_release);
}
bool test_and_set(eastl::internal::memory_order_acq_rel_s) EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_acq_rel);
}
bool test_and_set(eastl::internal::memory_order_seq_cst_s) EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_seq_cst);
}
bool test_and_set() EA_NOEXCEPT
{
return mFlag.exchange(true, eastl::memory_order_seq_cst);
}
public: /* test */
template <typename Order>
bool test(Order /*order*/) const volatile EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(Order);
return false;
}
template <typename Order>
bool test(Order /*order*/) const EA_NOEXCEPT
{
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(Order);
return false;
}
bool test(eastl::internal::memory_order_relaxed_s) const EA_NOEXCEPT
{
return mFlag.load(eastl::memory_order_relaxed);
}
bool test(eastl::internal::memory_order_acquire_s) const EA_NOEXCEPT
{
return mFlag.load(eastl::memory_order_acquire);
}
bool test(eastl::internal::memory_order_seq_cst_s) const EA_NOEXCEPT
{
return mFlag.load(eastl::memory_order_seq_cst);
}
bool test() const EA_NOEXCEPT
{
return mFlag.load(eastl::memory_order_seq_cst);
}
private:
eastl::atomic<bool> mFlag;
};
} // namespace eastl
#include "atomic_pop_compiler_options.h"
#endif /* EASTL_ATOMIC_INTERNA_ATOMIC_FLAG_H */
@@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_FLAG_STANDALONE_H
#define EASTL_ATOMIC_INTERNAL_FLAG_STANDALONE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
namespace eastl
{
////////////////////////////////////////////////////////////////////////////////
//
// bool atomic_flag_test_and_set(eastl::atomic<T>*)
//
EASTL_FORCE_INLINE bool atomic_flag_test_and_set(eastl::atomic_flag* atomicObj) EA_NOEXCEPT
{
return atomicObj->test_and_set();
}
template <typename Order>
EASTL_FORCE_INLINE bool atomic_flag_test_and_set_explicit(eastl::atomic_flag* atomicObj, Order order)
{
return atomicObj->test_and_set(order);
}
////////////////////////////////////////////////////////////////////////////////
//
// bool atomic_flag_clear(eastl::atomic<T>*)
//
EASTL_FORCE_INLINE void atomic_flag_clear(eastl::atomic_flag* atomicObj)
{
atomicObj->clear();
}
template <typename Order>
EASTL_FORCE_INLINE void atomic_flag_clear_explicit(eastl::atomic_flag* atomicObj, Order order)
{
atomicObj->clear(order);
}
////////////////////////////////////////////////////////////////////////////////
//
// bool atomic_flag_test(eastl::atomic<T>*)
//
EASTL_FORCE_INLINE bool atomic_flag_test(eastl::atomic_flag* atomicObj)
{
return atomicObj->test();
}
template <typename Order>
EASTL_FORCE_INLINE bool atomic_flag_test_explicit(eastl::atomic_flag* atomicObj, Order order)
{
return atomicObj->test(order);
}
} // namespace eastl
#endif /* EASTL_ATOMIC_INTERNAL_FLAG_STANDALONE_H */
@@ -0,0 +1,344 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_INTEGRAL_H
#define EASTL_ATOMIC_INTERNAL_INTEGRAL_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include "atomic_push_compiler_options.h"
namespace eastl
{
namespace internal
{
#define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(funcName) \
template <typename Order> \
T funcName(T /*arg*/, Order /*order*/) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_INVALID_MEMORY_ORDER(T); \
} \
\
template <typename Order> \
T funcName(T /*arg*/, Order /*order*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
} \
\
T funcName(T /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
#define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_INC_DEC_OPERATOR_IMPL(operatorOp) \
T operator operatorOp() volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
} \
\
T operator operatorOp(int) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
#define EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(operatorOp) \
T operator operatorOp(T /*arg*/) volatile EA_NOEXCEPT \
{ \
EASTL_ATOMIC_STATIC_ASSERT_VOLATILE_MEM_FN(T); \
}
template <typename T, unsigned width = sizeof(T)>
struct atomic_integral_base : public atomic_base_width<T, width>
{
private:
using Base = atomic_base_width<T, width>;
public: /* ctors */
EA_CONSTEXPR atomic_integral_base(T desired) EA_NOEXCEPT
: Base{ desired }
{
}
EA_CONSTEXPR atomic_integral_base() EA_NOEXCEPT = default;
atomic_integral_base(const atomic_integral_base&) EA_NOEXCEPT = delete;
public: /* assignment operator */
using Base::operator=;
atomic_integral_base& operator=(const atomic_integral_base&) EA_NOEXCEPT = delete;
atomic_integral_base& operator=(const atomic_integral_base&) volatile EA_NOEXCEPT = delete;
public: /* fetch_add */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(fetch_add)
public: /* add_fetch */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(add_fetch)
public: /* fetch_sub */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(fetch_sub)
public: /* sub_fetch */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(sub_fetch)
public: /* fetch_and */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(fetch_and)
public: /* and_fetch */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(and_fetch)
public: /* fetch_or */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(fetch_or)
public: /* or_fetch */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(or_fetch)
public: /* fetch_xor */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(fetch_xor)
public: /* xor_fetch */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_FUNCS_IMPL(xor_fetch)
public: /* operator++ && operator-- */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_INC_DEC_OPERATOR_IMPL(++)
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_INC_DEC_OPERATOR_IMPL(--)
public: /* operator+= && operator-= */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(+=)
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(-=)
public: /* operator&= */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(&=)
public: /* operator|= */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(|=)
public: /* operator^= */
EASTL_ATOMIC_INTEGRAL_STATIC_ASSERT_ASSIGNMENT_OPERATOR_IMPL(^=)
};
template <typename T, unsigned width = sizeof(T)>
struct atomic_integral_width;
#define EASTL_ATOMIC_INTEGRAL_FUNC_IMPL(op, bits) \
EASTL_ATOMIC_DEFAULT_INIT(T, retVal); \
EA_PREPROCESSOR_JOIN(op, bits)(T, retVal, this->GetAtomicAddress(), arg); \
return retVal;
#define EASTL_ATOMIC_INTEGRAL_FETCH_IMPL(funcName, op, bits) \
T funcName(T arg) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_INTEGRAL_FUNC_IMPL(op, bits); \
}
#define EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, orderType, op, bits) \
T funcName(T arg, orderType) EA_NOEXCEPT \
{ \
EASTL_ATOMIC_INTEGRAL_FUNC_IMPL(op, bits); \
}
#define EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, Order) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_, fetchOp), Order)
#define EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(funcName, fetchOp, bits) \
using Base::funcName; \
\
EASTL_ATOMIC_INTEGRAL_FETCH_IMPL(funcName, EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _SEQ_CST_), bits) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, eastl::internal::memory_order_relaxed_s, \
EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _RELAXED_), bits) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, eastl::internal::memory_order_acquire_s, \
EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _ACQUIRE_), bits) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, eastl::internal::memory_order_release_s, \
EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _RELEASE_), bits) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, eastl::internal::memory_order_acq_rel_s, \
EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _ACQ_REL_), bits) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ORDER_IMPL(funcName, eastl::internal::memory_order_seq_cst_s, \
EASTL_ATOMIC_INTEGRAL_FETCH_OP_JOIN(fetchOp, _SEQ_CST_), bits)
#define EASTL_ATOMIC_INTEGRAL_FETCH_INC_DEC_OPERATOR_IMPL(operatorOp, preFuncName, postFuncName) \
using Base::operator operatorOp; \
\
T operator operatorOp() EA_NOEXCEPT \
{ \
return preFuncName(1, eastl::memory_order_seq_cst); \
} \
\
T operator operatorOp(int) EA_NOEXCEPT \
{ \
return postFuncName(1, eastl::memory_order_seq_cst); \
}
#define EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(operatorOp, funcName) \
using Base::operator operatorOp; \
\
T operator operatorOp(T arg) EA_NOEXCEPT \
{ \
return funcName(arg, eastl::memory_order_seq_cst); \
}
#define EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(bytes, bits) \
template <typename T> \
struct atomic_integral_width<T, bytes> : public atomic_integral_base<T, bytes> \
{ \
private: \
\
using Base = atomic_integral_base<T, bytes>; \
\
public: /* ctors */ \
\
EA_CONSTEXPR atomic_integral_width(T desired) EA_NOEXCEPT \
: Base{ desired } \
{ \
} \
\
EA_CONSTEXPR atomic_integral_width() EA_NOEXCEPT = default; \
\
atomic_integral_width(const atomic_integral_width&) EA_NOEXCEPT = delete; \
\
public: /* assignment operator */ \
\
using Base::operator=; \
\
atomic_integral_width& operator=(const atomic_integral_width&) EA_NOEXCEPT = delete; \
atomic_integral_width& operator=(const atomic_integral_width&) volatile EA_NOEXCEPT = delete; \
\
public: /* fetch_add */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(fetch_add, FETCH_ADD, bits) \
\
public: /* add_fetch */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(add_fetch, ADD_FETCH, bits) \
\
public: /* fetch_sub */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(fetch_sub, FETCH_SUB, bits) \
\
public: /* sub_fetch */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(sub_fetch, SUB_FETCH, bits) \
\
public: /* fetch_and */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(fetch_and, FETCH_AND, bits) \
\
public: /* and_fetch */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(and_fetch, AND_FETCH, bits) \
\
public: /* fetch_or */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(fetch_or, FETCH_OR, bits) \
\
public: /* or_fetch */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(or_fetch, OR_FETCH, bits) \
\
public: /* fetch_xor */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(fetch_xor, FETCH_XOR, bits) \
\
public: /* xor_fetch */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_FUNCS_IMPL(xor_fetch, XOR_FETCH, bits) \
\
public: /* operator++ && operator-- */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_INC_DEC_OPERATOR_IMPL(++, add_fetch, fetch_add) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_INC_DEC_OPERATOR_IMPL(--, sub_fetch, fetch_sub) \
\
public: /* operator+= && operator-= */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(+=, add_fetch) \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(-=, sub_fetch) \
\
public: /* operator&= */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(&=, and_fetch) \
\
public: /* operator|= */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(|=, or_fetch) \
\
public: /* operator^= */ \
\
EASTL_ATOMIC_INTEGRAL_FETCH_ASSIGNMENT_OPERATOR_IMPL(^=, xor_fetch) \
\
};
#if defined(EASTL_ATOMIC_HAS_8BIT)
EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(1, 8)
#endif
#if defined(EASTL_ATOMIC_HAS_16BIT)
EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(2, 16)
#endif
#if defined(EASTL_ATOMIC_HAS_32BIT)
EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(4, 32)
#endif
#if defined(EASTL_ATOMIC_HAS_64BIT)
EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(8, 64)
#endif
#if defined(EASTL_ATOMIC_HAS_128BIT)
//JLM: fails in VS2022
//EASTL_ATOMIC_INTEGRAL_WIDTH_SPECIALIZE(16, 128)
#endif
} // namespace internal
} // namespace eastl
#include "atomic_pop_compiler_options.h"
#endif /* EASTL_ATOMIC_INTERNAL_INTEGRAL_H */
@@ -0,0 +1,67 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_MACROS_H
#define EASTL_ATOMIC_INTERNAL_MACROS_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// The reason for the implementation separating out into a compiler and architecture
// folder is as follows.
//
// The compiler directory is meant to implement atomics using the compiler provided
// intrinsics. This also implies that usually the same compiler instrinsic implementation
// can be used for any architecture the compiler supports. If a compiler provides intrinsics
// to support barriers or atomic operations, then that implementation should be in the
// compiler directory.
//
// The arch directory is meant to manually implement atomics for a specific architecture
// such as power or x86. There may be some compiler specific code in this directory because
// GCC inline assembly syntax may be different than another compiler as an example.
//
// The arch directory can also be used to implement some atomic operations ourselves
// if we deem the compiler provided implementation to be inefficient for the given
// architecture or we need to do some things manually for a given compiler.
//
// The atomic_macros directory implements the macros that the rest of the atomic
// library uses. These macros will expand to either the compiler or arch implemented
// macro. The arch implemented macro is given priority over the compiler implemented
// macro if both are implemented otherwise whichever is implemented is chosen or
// an error is emitted if none are implemented.
//
// The implementation being all macros has a couple nice side effects as well.
//
// 1. All the implementation ends up funneling into one low level macro implementation
// which makes it easy to verify correctness, reduce copy-paste errors and differences
// in various platform implementations.
//
// 2. Allows for the implementation to be implemented efficiently on compilers that do not
// directly implement the C++ memory model in their intrinsics such as msvc.
//
// 3. Allows for the implementation of atomics that may not be supported on the given platform,
// such as 128-bit atomics on 32-bit platforms since the macros will only ever be expanded
// on platforms that support said features. This makes implementing said features pretty easy
// since we do not have to worry about complicated feature detection in the low level implementations.
//
// The macro implementation may asume that all passed in types are trivially constructible thus it is
// free to create local variables of the passed in types as it may please.
// It may also assume that all passed in types are trivially copyable as well.
// It cannot assume any passed in type is any given type thus is a specific type if needed, it must do an
// EASTL_ATOMIC_TYPE_PUN_CAST() to the required type.
//
#include "compiler/compiler.h"
#include "arch/arch.h"
#include "atomic_macros/atomic_macros.h"
#endif /* EASTL_ATOMIC_INTERNAL_MACROS_H */
@@ -0,0 +1,156 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_ATOMIC_MACROS_H
#define EASTL_ATOMIC_INTERNAL_ATOMIC_MACROS_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#include <EABase/eabase.h>
#include "atomic_macros_base.h"
#include "atomic_macros_fetch_add.h"
#include "atomic_macros_fetch_sub.h"
#include "atomic_macros_fetch_and.h"
#include "atomic_macros_fetch_xor.h"
#include "atomic_macros_fetch_or.h"
#include "atomic_macros_add_fetch.h"
#include "atomic_macros_sub_fetch.h"
#include "atomic_macros_and_fetch.h"
#include "atomic_macros_xor_fetch.h"
#include "atomic_macros_or_fetch.h"
#include "atomic_macros_exchange.h"
#include "atomic_macros_cmpxchg_weak.h"
#include "atomic_macros_cmpxchg_strong.h"
#include "atomic_macros_load.h"
#include "atomic_macros_store.h"
#include "atomic_macros_compiler_barrier.h"
#include "atomic_macros_cpu_pause.h"
#include "atomic_macros_memory_barrier.h"
#include "atomic_macros_signal_fence.h"
#include "atomic_macros_thread_fence.h"
/////////////////////////////////////////////////////////////////////////////////
#if defined(EASTL_COMPILER_ATOMIC_HAS_8BIT) || defined(EASTL_ARCH_ATOMIC_HAS_8BIT)
#define EASTL_ATOMIC_HAS_8BIT
#endif
#if defined(EASTL_COMPILER_ATOMIC_HAS_16BIT) || defined(EASTL_ARCH_ATOMIC_HAS_16BIT)
#define EASTL_ATOMIC_HAS_16BIT
#endif
#if defined(EASTL_COMPILER_ATOMIC_HAS_32BIT) || defined(EASTL_ARCH_ATOMIC_HAS_32BIT)
#define EASTL_ATOMIC_HAS_32BIT
#endif
#if defined(EASTL_COMPILER_ATOMIC_HAS_64BIT) || defined(EASTL_ARCH_ATOMIC_HAS_64BIT)
#define EASTL_ATOMIC_HAS_64BIT
#endif
#if defined(EASTL_COMPILER_ATOMIC_HAS_128BIT) || defined(EASTL_ARCH_ATOMIC_HAS_128BIT)
#define EASTL_ATOMIC_HAS_128BIT
#endif
/////////////////////////////////////////////////////////////////////////////////
#if defined(EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_8)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_8 EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_8
#elif defined(EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_8)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_8 EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_8
#endif
#if defined(EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_16)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_16 EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_16
#elif defined(EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_16)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_16 EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_16
#endif
#if defined(EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_32)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_32 EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_32
#elif defined(EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_32)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_32 EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_32
#endif
#if defined(EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_64)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_64 EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_64
#elif defined(EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_64)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_64 EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_64
#endif
#if defined(EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_128)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 EASTL_ARCH_ATOMIC_FIXED_WIDTH_TYPE_128
#elif defined(EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_128)
#define EASTL_ATOMIC_FIXED_WIDTH_TYPE_128 EASTL_COMPILER_ATOMIC_FIXED_WIDTH_TYPE_128
#endif
// We write some of our variables in inline assembly, which MSAN
// doesn't understand. This macro forces initialization of those
// variables when MSAN is enabled and doesn't pay the initialization
// cost when it's not enabled.
#if EA_MSAN_ENABLED
#define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var{}
#else
#define EASTL_ATOMIC_DEFAULT_INIT(type, var) type var
#endif // EA_MSAN_ENABLED
#endif /* EASTL_ATOMIC_INTERNAL_ATOMIC_MACROS_H */
@@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_MACROS_ADD_FETCH_H
#define EASTL_ATOMIC_INTERNAL_MACROS_ADD_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ATOMIC_ADD_FETCH_*_N(type, type ret, type * ptr, type val)
//
#define EASTL_ATOMIC_ADD_FETCH_RELAXED_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELAXED_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQUIRE_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQUIRE_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELEASE_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELEASE_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQ_REL_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQ_REL_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_SEQ_CST_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_SEQ_CST_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELAXED_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELAXED_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQUIRE_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQUIRE_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELEASE_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELEASE_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQ_REL_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQ_REL_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_SEQ_CST_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_SEQ_CST_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELAXED_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELAXED_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQUIRE_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQUIRE_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELEASE_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELEASE_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQ_REL_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQ_REL_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_SEQ_CST_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_SEQ_CST_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELAXED_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQUIRE_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELEASE_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQ_REL_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_SEQ_CST_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELAXED_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQUIRE_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_RELEASE_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_ACQ_REL_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_ADD_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_ADD_FETCH_SEQ_CST_128)(type, ret, ptr, val)
#endif /* EASTL_ATOMIC_INTERNAL_MACROS_ADD_FETCH_H */
@@ -0,0 +1,98 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_MACROS_AND_FETCH_H
#define EASTL_ATOMIC_INTERNAL_MACROS_AND_FETCH_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
/////////////////////////////////////////////////////////////////////////////////
//
// void EASTL_ATOMIC_AND_FETCH_*_N(type, type ret, type * ptr, type val)
//
#define EASTL_ATOMIC_AND_FETCH_RELAXED_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELAXED_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQUIRE_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQUIRE_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELEASE_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELEASE_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQ_REL_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQ_REL_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_SEQ_CST_8(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_SEQ_CST_8)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELAXED_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELAXED_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQUIRE_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQUIRE_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELEASE_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELEASE_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQ_REL_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQ_REL_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_SEQ_CST_16(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_SEQ_CST_16)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELAXED_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELAXED_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQUIRE_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQUIRE_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELEASE_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELEASE_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQ_REL_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQ_REL_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_SEQ_CST_32(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_SEQ_CST_32)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELAXED_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELAXED_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQUIRE_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQUIRE_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELEASE_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELEASE_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQ_REL_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQ_REL_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_SEQ_CST_64(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_SEQ_CST_64)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELAXED_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELAXED_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQUIRE_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQUIRE_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_RELEASE_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_RELEASE_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_ACQ_REL_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_ACQ_REL_128)(type, ret, ptr, val)
#define EASTL_ATOMIC_AND_FETCH_SEQ_CST_128(type, ret, ptr, val) \
EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_AND_FETCH_SEQ_CST_128)(type, ret, ptr, val)
#endif /* EASTL_ATOMIC_INTERNAL_MACROS_AND_FETCH_H */
@@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_ATOMIC_INTERNAL_MACROS_BASE_H
#define EASTL_ATOMIC_INTERNAL_MACROS_BASE_H
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
#pragma once
#endif
#define EASTL_ATOMIC_INTERNAL_COMPILER_AVAILABLE(op) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_COMPILER_, op), _AVAILABLE)
#define EASTL_ATOMIC_INTERNAL_ARCH_AVAILABLE(op) \
EA_PREPROCESSOR_JOIN(EA_PREPROCESSOR_JOIN(EASTL_ARCH_, op), _AVAILABLE)
// We can't just use static_assert(false, ...) here, since on MSVC 17.10
// the /Zc:static_assert flag makes non-dependent static_asserts in the body of a template
// be evaluated at template-parse time, rather than at template instantion time.
// So instead we just make the assert dependent on the type.
#define EASTL_ATOMIC_INTERNAL_NOT_IMPLEMENTED_ERROR(...) \
static_assert(!eastl::is_same_v<T,T>, "eastl::atomic<T> atomic macro not implemented!")
/* Compiler && Arch Not Implemented */
#define EASTL_ATOMIC_INTERNAL_OP_PATTERN_00(op) \
EASTL_ATOMIC_INTERNAL_NOT_IMPLEMENTED_ERROR
/* Arch Implemented */
#define EASTL_ATOMIC_INTERNAL_OP_PATTERN_01(op) \
EA_PREPROCESSOR_JOIN(EASTL_ARCH_, op)
/* Compiler Implmented */
#define EASTL_ATOMIC_INTERNAL_OP_PATTERN_10(op) \
EA_PREPROCESSOR_JOIN(EASTL_COMPILER_, op)
/* Compiler && Arch Implemented */
#define EASTL_ATOMIC_INTERNAL_OP_PATTERN_11(op) \
EA_PREPROCESSOR_JOIN(EASTL_ARCH_, op)
/* This macro creates the pattern macros above for the 2x2 True-False truth table */
#define EASTL_ATOMIC_INTERNAL_OP_HELPER1(compiler, arch, op) \
EA_PREPROCESSOR_JOIN(EASTL_ATOMIC_INTERNAL_OP_PATTERN_, EA_PREPROCESSOR_JOIN(compiler, arch))(op)
/////////////////////////////////////////////////////////////////////////////////
//
// EASTL_ATOMIC_CHOOSE_OP_IMPL
//
// This macro chooses between the compiler or architecture implementation for a
// given atomic operation.
//
// USAGE:
//
// EASTL_ATOMIC_CHOOSE_OP_IMPL(ATOMIC_FETCH_ADD_RELAXED_8)(ret, ptr, val)
//
#define EASTL_ATOMIC_CHOOSE_OP_IMPL(op) \
EASTL_ATOMIC_INTERNAL_OP_HELPER1( \
EASTL_ATOMIC_INTERNAL_COMPILER_AVAILABLE(op), \
EASTL_ATOMIC_INTERNAL_ARCH_AVAILABLE(op), \
op \
)
#endif /* EASTL_ATOMIC_INTERNAL_MACROS_BASE_H */

Some files were not shown because too many files have changed in this diff Show More