Files
EASTL/include/EASTL/core_allocator_adapter.h
T
jeanlemotan 48ab06b1d9 First
2024-07-02 18:10:39 +02:00

369 lines
12 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// 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