mirror of
https://github.com/electronicarts/EASTL.git
synced 2026-01-18 17:21:19 +01:00
3.04.00 release
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
version: 1.0.{build}
|
||||
|
||||
platform:
|
||||
- MSVC_2013_x86
|
||||
- MSVC_2013_x64
|
||||
- MSVC_2015_x86
|
||||
- MSVC_2015_x64
|
||||
- MinGW_x86
|
||||
- MinGW_x64
|
||||
|
||||
install:
|
||||
- scripts\ci-pre.cmd
|
||||
|
||||
build_script:
|
||||
- scripts\ci-build.cmd
|
||||
|
||||
test_script:
|
||||
- scripts\ci-test.cmd
|
||||
version: 1.0.{build}
|
||||
|
||||
platform:
|
||||
- MSVC_2013_x86
|
||||
- MSVC_2013_x64
|
||||
- MSVC_2015_x86
|
||||
- MSVC_2015_x64
|
||||
- MinGW_x86
|
||||
- MinGW_x64
|
||||
|
||||
install:
|
||||
- scripts\ci-pre.cmd
|
||||
|
||||
build_script:
|
||||
- scripts\ci-build.cmd
|
||||
|
||||
test_script:
|
||||
- scripts\ci-test.cmd
|
||||
|
||||
@@ -21,7 +21,7 @@ DerivePointerBinding : false
|
||||
IndentWidth : 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks : true
|
||||
MaxEmptyLinesToKeep : 2
|
||||
NamespaceIndentation : Inner
|
||||
NamespaceIndentation : All
|
||||
PointerBindsToType : true
|
||||
SpacesBeforeTrailingComments : 1
|
||||
SpacesInAngles : false
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,6 +4,7 @@ tags
|
||||
.swp
|
||||
*.swp
|
||||
.swo
|
||||
.TMP
|
||||
-.d
|
||||
eastl_build_out
|
||||
build_bench
|
||||
@@ -23,8 +24,6 @@ cmake_install.cmake
|
||||
**/*.vcxproj.filters
|
||||
*.VC.opendb
|
||||
*.sdf
|
||||
**/*.suo
|
||||
**/*.user
|
||||
.vs/*
|
||||
**/Debug/*
|
||||
CMakeFiles/*
|
||||
@@ -34,5 +33,6 @@ Release/*
|
||||
Win32/*
|
||||
x64/*
|
||||
MinSizeRel/*
|
||||
build*/*
|
||||
build/*
|
||||
Testing/*
|
||||
%ALLUSERSPROFILE%/*
|
||||
|
||||
@@ -4146,6 +4146,27 @@ namespace eastl
|
||||
|
||||
|
||||
|
||||
/// clamp
|
||||
///
|
||||
/// Returns a reference to a clamped value within the range of [lo, hi].
|
||||
///
|
||||
/// http://en.cppreference.com/w/cpp/algorithm/clamp
|
||||
///
|
||||
template <class T>
|
||||
EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi)
|
||||
{
|
||||
return clamp(v, lo, hi, eastl::less<>());
|
||||
}
|
||||
|
||||
template <class T, class Compare>
|
||||
EA_CONSTEXPR const T& clamp(const T& v, const T& lo, const T& hi, Compare comp)
|
||||
{
|
||||
// code collapsed to a single line due to constexpr requirements
|
||||
return [&] { EASTL_ASSERT(!comp(hi, lo)); }(),
|
||||
comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
|
||||
|
||||
568
include/EASTL/any.h
Normal file
568
include/EASTL/any.h
Normal file
@@ -0,0 +1,568 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// 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 a 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
|
||||
|
||||
EA_ONCE()
|
||||
|
||||
#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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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:
|
||||
{
|
||||
destroy(const_cast<any&>(*pThis));
|
||||
}
|
||||
break;
|
||||
|
||||
case storage_operation::COPY:
|
||||
{
|
||||
construct(pOther->m_storage, *(T*)(&pThis->m_storage.internal_storage));
|
||||
}
|
||||
break;
|
||||
|
||||
case storage_operation::MOVE:
|
||||
{
|
||||
construct(pOther->m_storage, eastl::move(*(T*)(&pThis->m_storage.internal_storage)));
|
||||
}
|
||||
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 = ::new T(eastl::forward<V>(v));
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static inline void construct_inplace(storage& s, Args... args)
|
||||
{
|
||||
s.external_storage = ::new 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 = ::new NT(il, eastl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static inline void destroy(any& refAny)
|
||||
{
|
||||
delete 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:
|
||||
{
|
||||
construct(pOther->m_storage, *static_cast<T*>(pThis->m_storage.external_storage));
|
||||
}
|
||||
break;
|
||||
|
||||
case storage_operation::MOVE:
|
||||
{
|
||||
construct(pOther->m_storage, eastl::move(*(T*)(pThis->m_storage.external_storage)));
|
||||
}
|
||||
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:
|
||||
EA_CONSTEXPR 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.
|
||||
other.m_handler(storage_operation::MOVE, &other, this);
|
||||
m_handler = eastl::move(other.m_handler);
|
||||
}
|
||||
}
|
||||
|
||||
~any() { reset(); }
|
||||
|
||||
template <class ValueType>
|
||||
any(ValueType&& value,
|
||||
typename eastl::enable_if<!eastl::is_same<typename eastl::decay<ValueType>::type, any>::value>::type* = 0)
|
||||
{
|
||||
static_assert(is_copy_constructible<decay_t<ValueType>>::value, "ValueType must be copy-constructible");
|
||||
storage_handler<decay_t<ValueType>>::construct(m_storage, eastl::forward<ValueType>(value));
|
||||
m_handler = &storage_handler<ValueType>::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
|
||||
{
|
||||
eastl::swap(m_storage, other.m_storage);
|
||||
eastl::swap(m_handler, other.m_handler);
|
||||
}
|
||||
|
||||
// 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
|
||||
//
|
||||
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;
|
||||
}
|
||||
|
||||
template <class ValueType>
|
||||
inline const ValueType* any_cast(const any* pAny) EA_NOEXCEPT
|
||||
{
|
||||
return (pAny && pAny->m_handler == &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 == &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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
@@ -105,8 +105,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_VERSION
|
||||
#define EASTL_VERSION "3.02.01"
|
||||
#define EASTL_VERSION_N 30201
|
||||
#define EASTL_VERSION "3.04.00"
|
||||
#define EASTL_VERSION_N 30400
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1036,6 +1036,7 @@ namespace eastl
|
||||
void clear(bool clearBuckets); // If clearBuckets is true, we free the bucket memory and set the bucket count back to the newly constructed count.
|
||||
void reset_lose_memory() EA_NOEXCEPT; // This is a unilateral reset to an initially empty state. No destructors are called, no deallocation occurs.
|
||||
void rehash(size_type nBucketCount);
|
||||
void reserve(size_type nElementCount);
|
||||
|
||||
#if EASTL_RESET_ENABLED
|
||||
void reset() EA_NOEXCEPT; // This function name is deprecated; use reset_lose_memory instead.
|
||||
@@ -2780,6 +2781,14 @@ namespace eastl
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V, typename A, typename EK, typename Eq,
|
||||
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
|
||||
inline void hashtable<K, V, A, EK, Eq, H1, H2, H, RP, bC, bM, bU>::reserve(size_type nElementCount)
|
||||
{
|
||||
rehash(mRehashPolicy.GetBucketCount(uint32_t(nElementCount)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename K, typename V, typename A, typename EK, typename Eq,
|
||||
typename H1, typename H2, typename H, typename RP, bool bC, bool bM, bool bU>
|
||||
|
||||
73
include/EASTL/internal/in_place_t.h
Normal file
73
include/EASTL/internal/in_place_t.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef EASTL_INTERNAL_IN_PLACE_T_H
|
||||
#define EASTL_INTERNAL_IN_PLACE_T_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
struct in_place_tag {};
|
||||
template <class> struct in_place_type_tag {};
|
||||
template <size_t> struct in_place_index_tag {};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// in_place_tag
|
||||
///
|
||||
/// http://en.cppreference.com/w/cpp/utility/in_place_tag
|
||||
///
|
||||
struct in_place_tag { in_place_tag() = delete; };
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// in_place_t / in_place_type_t / in_place_index_t
|
||||
///
|
||||
/// used to disambiguate overloads that take arguments (possibly a parameter
|
||||
/// pack) for in-place construction of some value.
|
||||
///
|
||||
/// http://en.cppreference.com/w/cpp/utility/optional/in_place_t
|
||||
///
|
||||
using in_place_t = in_place_tag(&)(Internal::in_place_tag);
|
||||
|
||||
template <class T>
|
||||
using in_place_type_t = in_place_tag(&)(Internal::in_place_type_tag<T>);
|
||||
|
||||
template <size_t N>
|
||||
using in_place_index_t = in_place_tag(&)(Internal::in_place_index_tag<N>);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// in_place / in_place<T> / in_place<size_t>
|
||||
///
|
||||
/// http://en.cppreference.com/w/cpp/utility/in_place
|
||||
///
|
||||
inline in_place_tag in_place(Internal::in_place_tag) { return {}; }
|
||||
|
||||
template <class T>
|
||||
inline in_place_tag in_place(Internal::in_place_type_tag<T>) { return {}; }
|
||||
|
||||
template <std::size_t I>
|
||||
inline in_place_tag in_place(Internal::in_place_index_tag<I>){ return {}; }
|
||||
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
|
||||
#endif // Header include guard
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ namespace eastl
|
||||
#define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming.
|
||||
|
||||
template <typename T>
|
||||
struct has_trivial_assign : public integral_constant<bool, (__has_trivial_assign(T) || eastl::is_pod<T>::value) && !eastl::is_const<T>::value && !eastl::is_volatile<T>::value>{};
|
||||
struct has_trivial_assign : public integral_constant<bool, (__has_trivial_assign(T) || eastl::is_pod<T>::value) && !eastl::is_const<T>::value && !eastl::is_volatile<T>::value && !eastl::is_hat_type<T>::value>{};
|
||||
#elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
|
||||
#define EASTL_TYPE_TRAIT_has_trivial_assign_CONFORMANCE 1 // has_trivial_assign is conforming.
|
||||
|
||||
@@ -335,7 +335,7 @@ namespace eastl
|
||||
#define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming.
|
||||
|
||||
template <typename T>
|
||||
struct has_trivial_destructor : public eastl::integral_constant<bool, __has_trivial_destructor(T) || eastl::is_pod<T>::value>{};
|
||||
struct has_trivial_destructor : public eastl::integral_constant<bool, (__has_trivial_destructor(T) || eastl::is_pod<T>::value) && !eastl::is_hat_type<T>::value>{};
|
||||
#elif EASTL_COMPILER_INTRINSIC_TYPE_TRAITS_AVAILABLE && (defined(_MSC_VER) || defined(EA_COMPILER_GNUC) || defined(EA_COMPILER_CLANG))
|
||||
#define EASTL_TYPE_TRAIT_has_trivial_destructor_CONFORMANCE 1 // has_trivial_destructor is conforming.
|
||||
|
||||
@@ -1667,7 +1667,7 @@ namespace eastl
|
||||
// For a complete type T and given
|
||||
// template <class U>
|
||||
// struct test { U u; };
|
||||
// test<T>::test() is not deleted (C++11 "= delete").
|
||||
// test<T>::˜test() is not deleted (C++11 "= delete").
|
||||
// T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@@ -1759,7 +1759,7 @@ namespace eastl
|
||||
|
||||
template <typename T>
|
||||
struct is_trivially_destructible // Can't use just __has_trivial_destructor(T) because some compilers give it slightly different meaning, and are just plain broken, such as VC++'s __has_trivial_destructor, which says false for fundamental types.
|
||||
: public integral_constant<bool, eastl::is_destructible<T>::value && ((__has_trivial_destructor(T) && !eastl::is_hat_type<T>::value)|| eastl::is_scalar<typename eastl::remove_all_extents<T>::type>::value)> {};
|
||||
: public integral_constant<bool, eastl::is_destructible<T>::value && ((__has_trivial_destructor(T) && !eastl::is_hat_type<T>::value)|| eastl::is_scalar<typename eastl::remove_all_extents<T>::type>::value)> {};
|
||||
|
||||
#else
|
||||
#define EASTL_TYPE_TRAIT_is_trivially_destructible_CONFORMANCE 0
|
||||
@@ -1907,6 +1907,10 @@ namespace eastl
|
||||
: public eastl::is_nothrow_constructible<T, typename eastl::add_rvalue_reference<T>::type> {};
|
||||
#endif
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR bool is_nothrow_move_constructible_v = is_nothrow_move_constructible<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
@@ -166,9 +166,13 @@ namespace eastl
|
||||
template <typename T>
|
||||
struct alignment_of : public integral_constant<size_t, alignment_of_value<T>::value>{};
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR size_t alignment_of_v = alignment_of<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// is_aligned
|
||||
//
|
||||
// Defined as true if the type has alignment requirements greater
|
||||
@@ -184,6 +188,11 @@ namespace eastl
|
||||
template <typename T>
|
||||
struct is_aligned : public integral_constant<bool, is_aligned_value<T>::value>{};
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <class T>
|
||||
EA_CONSTEXPR size_t is_aligned_v = is_aligned<T>::value;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <EASTL/internal/config.h>
|
||||
#include <EASTL/initializer_list.h>
|
||||
#include <EASTL/memory.h> // eastl::addressof
|
||||
#include <EASTL/internal/in_place_t.h> // eastl::in_place_t
|
||||
|
||||
#if defined(EASTL_OPTIONAL_ENABLED) && EASTL_OPTIONAL_ENABLED
|
||||
|
||||
@@ -38,6 +39,11 @@ EA_DISABLE_VC_WARNING(4583) // destructor is not implicitly called
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
#ifdef EASTL_EXCEPTIONS_ENABLED
|
||||
#define EASTL_OPTIONAL_NOEXCEPT
|
||||
#else
|
||||
#define EASTL_OPTIONAL_NOEXCEPT EA_NOEXCEPT
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// nullopt_t
|
||||
@@ -51,15 +57,6 @@ namespace eastl
|
||||
EA_CONSTEXPR nullopt_t nullopt{0};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// in_place_t
|
||||
///
|
||||
/// used to disambiguate overloads that take arguments (possibly a parameter pack) for in-place construction of some value.
|
||||
///
|
||||
struct in_place_t {};
|
||||
EA_CONSTEXPR in_place_t in_place{};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// bad_optional_access
|
||||
///
|
||||
@@ -67,7 +64,7 @@ namespace eastl
|
||||
struct bad_optional_access : public std::logic_error
|
||||
{
|
||||
bad_optional_access() : std::logic_error("eastl::bad_optional_access exception") {}
|
||||
virtual ~bad_optional_access() EA_NOEXCEPT;
|
||||
virtual ~bad_optional_access() EA_NOEXCEPT {}
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -204,14 +201,14 @@ namespace eastl
|
||||
#if EASTL_VARIADIC_TEMPLATES_ENABLED
|
||||
template <typename... Args>
|
||||
inline explicit optional(in_place_t, Args&&... args)
|
||||
: base_type(in_place_t{}, eastl::forward<Args>(args)...) {}
|
||||
: base_type(in_place, eastl::forward<Args>(args)...) {}
|
||||
|
||||
template <typename U,
|
||||
typename... Args,
|
||||
typename = typename eastl::enable_if<
|
||||
eastl::is_constructible<T, std::initializer_list<U>&, Args&&...>::value>::type>
|
||||
inline explicit optional(in_place_t, std::initializer_list<U> ilist, Args&&... args)
|
||||
: base_type(in_place_t{}, ilist, eastl::forward<Args>(args)...) {}
|
||||
: base_type(in_place, ilist, eastl::forward<Args>(args)...) {}
|
||||
#endif
|
||||
|
||||
inline optional& operator=(nullopt_t)
|
||||
@@ -332,7 +329,7 @@ namespace eastl
|
||||
}
|
||||
}
|
||||
|
||||
inline T* get_value_address() EA_NOEXCEPT
|
||||
inline T* get_value_address() EASTL_OPTIONAL_NOEXCEPT
|
||||
{
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
if(!engaged)
|
||||
@@ -343,7 +340,7 @@ namespace eastl
|
||||
return eastl::addressof(val);
|
||||
}
|
||||
|
||||
inline const T* get_value_address() const EA_NOEXCEPT
|
||||
inline const T* get_value_address() const EASTL_OPTIONAL_NOEXCEPT
|
||||
{
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
if(!engaged)
|
||||
@@ -354,7 +351,7 @@ namespace eastl
|
||||
return eastl::addressof(val);
|
||||
}
|
||||
|
||||
inline value_type& get_value_ref() EA_NOEXCEPT
|
||||
inline value_type& get_value_ref() EASTL_OPTIONAL_NOEXCEPT
|
||||
{
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
if(!engaged)
|
||||
@@ -365,7 +362,7 @@ namespace eastl
|
||||
return val;
|
||||
}
|
||||
|
||||
inline const value_type& get_value_ref() const EA_NOEXCEPT
|
||||
inline const value_type& get_value_ref() const EASTL_OPTIONAL_NOEXCEPT
|
||||
{
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
if(!engaged)
|
||||
@@ -582,6 +579,8 @@ namespace eastl
|
||||
return optional<typename eastl::decay<T>::type>(eastl::forward<T>(value));
|
||||
}
|
||||
|
||||
#undef EASTL_OPTIONAL_NOEXCEPT
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
520
include/EASTL/segmented_vector.h
Normal file
520
include/EASTL/segmented_vector.h
Normal file
@@ -0,0 +1,520 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_SEGMENTED_VECTOR_H
|
||||
#define EASTL_SEGMENTED_VECTOR_H
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <EASTL/internal/config.h>
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
template<typename T, size_t Count, typename Allocator = EASTLAllocatorType>
|
||||
class segment
|
||||
{
|
||||
public:
|
||||
typedef eastl_size_t size_type;
|
||||
typedef segment<T, Count, Allocator> this_type;
|
||||
typedef T* iterator;
|
||||
typedef const T* const_iterator;
|
||||
|
||||
const this_type* next_segment() const;
|
||||
this_type* next_segment();
|
||||
|
||||
const_iterator begin() const;
|
||||
iterator begin();
|
||||
|
||||
const_iterator end() const;
|
||||
iterator end();
|
||||
|
||||
private:
|
||||
static const uintptr_t kIsLastSegment = 1 << 0;
|
||||
uintptr_t mPrev;
|
||||
|
||||
union
|
||||
{
|
||||
this_type* mNext;
|
||||
size_type mSize;
|
||||
};
|
||||
T mData[Count];
|
||||
template<typename, size_t, typename> friend class segmented_vector;
|
||||
template<typename, size_t, typename> friend struct segmented_vector_iterator;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, size_t Count, typename Allocator = EASTLAllocatorType>
|
||||
struct segmented_vector_iterator
|
||||
{
|
||||
public:
|
||||
typedef segmented_vector_iterator<T, Count, Allocator> this_type;
|
||||
typedef segment<T, Count, Allocator> segment_type;
|
||||
|
||||
T* operator->() const;
|
||||
T& operator*() const;
|
||||
|
||||
this_type& operator++();
|
||||
this_type operator++(int);
|
||||
|
||||
public:
|
||||
T* mCurrent;
|
||||
T* mEnd;
|
||||
segment_type* mSegment;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, size_t Count, typename Allocator = EASTLAllocatorType>
|
||||
class segmented_vector
|
||||
{
|
||||
public:
|
||||
typedef eastl_size_t size_type;
|
||||
typedef segmented_vector<T, Count, Allocator> this_type;
|
||||
typedef segment<T, Count, Allocator> segment_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef segmented_vector_iterator<const T, Count, Allocator> const_iterator;
|
||||
typedef segmented_vector_iterator<T, Count, Allocator> iterator;
|
||||
|
||||
|
||||
segmented_vector(const Allocator& allocator = Allocator());
|
||||
~segmented_vector();
|
||||
|
||||
allocator_type& get_allocator();
|
||||
|
||||
const segment_type* first_segment() const;
|
||||
segment_type* first_segment();
|
||||
const_iterator begin() const;
|
||||
iterator begin();
|
||||
|
||||
const_iterator end() const;
|
||||
iterator end();
|
||||
|
||||
size_type size() const;
|
||||
size_type segment_count() const;
|
||||
T& front();
|
||||
T& back();
|
||||
|
||||
bool empty() const;
|
||||
void clear();
|
||||
|
||||
T& push_back();
|
||||
T& push_back(const T& value);
|
||||
void* push_back_uninitialized();
|
||||
|
||||
void pop_back();
|
||||
|
||||
void erase_unsorted(segment_type& segment, typename segment_type::iterator it);
|
||||
iterator erase_unsorted(const iterator& i);
|
||||
|
||||
void swap(this_type& other);
|
||||
|
||||
protected:
|
||||
segment_type* DoAllocSegment(segment_type* prevSegment);
|
||||
void* DoPushBack();
|
||||
|
||||
allocator_type mAllocator;
|
||||
segment_type* mFirstSegment;
|
||||
segment_type* mLastSegment;
|
||||
size_type mSegmentCount;
|
||||
};
|
||||
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline const segment<T, Count, Allocator>*
|
||||
segment<T, Count, Allocator>::next_segment() const
|
||||
{
|
||||
if (mPrev & kIsLastSegment)
|
||||
return 0;
|
||||
else
|
||||
return mNext;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline segment<T, Count, Allocator>*
|
||||
segment<T, Count, Allocator>::next_segment()
|
||||
{
|
||||
if (mPrev & kIsLastSegment)
|
||||
return 0;
|
||||
else
|
||||
return mNext;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline typename segment<T, Count, Allocator>::const_iterator
|
||||
segment<T, Count, Allocator>::begin() const
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline typename segment<T, Count, Allocator>::iterator
|
||||
segment<T, Count, Allocator>::begin()
|
||||
{
|
||||
return mData;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline typename segment<T, Count, Allocator>::const_iterator
|
||||
segment<T, Count, Allocator>::end() const
|
||||
{
|
||||
if (mPrev & kIsLastSegment)
|
||||
return mData + mSize;
|
||||
else
|
||||
return mData + Count;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline typename segment<T, Count, Allocator>::iterator
|
||||
segment<T, Count, Allocator>::end()
|
||||
{
|
||||
if (mPrev & kIsLastSegment)
|
||||
return mData + mSize;
|
||||
else
|
||||
return mData + Count;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
T*
|
||||
segmented_vector_iterator<T, Count, Allocator>::operator->() const
|
||||
{
|
||||
return mCurrent;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
T&
|
||||
segmented_vector_iterator<T, Count, Allocator>::operator*() const
|
||||
{
|
||||
return *mCurrent;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
segmented_vector_iterator<T, Count, Allocator>&
|
||||
segmented_vector_iterator<T, Count, Allocator>::operator++()
|
||||
{
|
||||
++mCurrent;
|
||||
if(EASTL_UNLIKELY(mCurrent == mEnd))
|
||||
{
|
||||
if (!(mSegment->mPrev & segment_type::kIsLastSegment))
|
||||
{
|
||||
mSegment = mSegment->mNext;
|
||||
mCurrent = mSegment->begin();
|
||||
mEnd = mSegment->end();
|
||||
}
|
||||
else
|
||||
mCurrent = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
segmented_vector_iterator<T, Count, Allocator>
|
||||
segmented_vector_iterator<T, Count, Allocator>::operator++(int)
|
||||
{
|
||||
this_type i(*this);
|
||||
return ++i;
|
||||
}
|
||||
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline segmented_vector<T, Count, Allocator>::segmented_vector(const Allocator& allocator)
|
||||
: mAllocator(allocator)
|
||||
, mFirstSegment(0)
|
||||
, mLastSegment(0)
|
||||
, mSegmentCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline segmented_vector<T, Count, Allocator>::~segmented_vector()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::allocator_type&
|
||||
segmented_vector<T, Count, Allocator>::get_allocator()
|
||||
{
|
||||
return mAllocator;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline const typename segmented_vector<T, Count, Allocator>::segment_type*
|
||||
segmented_vector<T, Count, Allocator>::first_segment() const
|
||||
{
|
||||
return mFirstSegment;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::segment_type*
|
||||
segmented_vector<T, Count, Allocator>::first_segment()
|
||||
{
|
||||
return mFirstSegment;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::const_iterator
|
||||
segmented_vector<T, Count, Allocator>::begin() const
|
||||
{
|
||||
iterator i;
|
||||
i.mSegment = mFirstSegment;
|
||||
if (mFirstSegment)
|
||||
{
|
||||
i.mCurrent = mFirstSegment->begin();
|
||||
i.mEnd = mFirstSegment->end();
|
||||
}
|
||||
else
|
||||
i.mCurrent = 0;
|
||||
return (const_iterator&)i;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::iterator
|
||||
segmented_vector<T, Count, Allocator>::begin()
|
||||
{
|
||||
iterator i;
|
||||
i.mSegment = mFirstSegment;
|
||||
if (mFirstSegment)
|
||||
{
|
||||
i.mCurrent = mFirstSegment->begin();
|
||||
i.mEnd = mFirstSegment->end();
|
||||
}
|
||||
else
|
||||
i.mCurrent = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::const_iterator
|
||||
segmented_vector<T, Count, Allocator>::end() const
|
||||
{
|
||||
iterator i;
|
||||
i.mCurrent = 0;
|
||||
return (const_iterator&)i;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::iterator
|
||||
segmented_vector<T, Count, Allocator>::end()
|
||||
{
|
||||
iterator i;
|
||||
i.mCurrent = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::size_type
|
||||
segmented_vector<T, Count, Allocator>::size() const
|
||||
{
|
||||
if (segment_type* segment = mLastSegment)
|
||||
return (mSegmentCount-1)*Count + segment->mSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::size_type
|
||||
segmented_vector<T, Count, Allocator>::segment_count() const
|
||||
{
|
||||
return mSegmentCount;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline T&
|
||||
segmented_vector<T, Count, Allocator>::front()
|
||||
{
|
||||
return mFirstSegment->mData[0];
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline T&
|
||||
segmented_vector<T, Count, Allocator>::back()
|
||||
{
|
||||
segment_type* lastSegment = mLastSegment;
|
||||
return lastSegment->mData[lastSegment->mSize-1];
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline bool
|
||||
segmented_vector<T, Count, Allocator>::empty() const
|
||||
{
|
||||
return mFirstSegment == 0;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline void
|
||||
segmented_vector<T, Count, Allocator>::clear()
|
||||
{
|
||||
if (segment_type* segment = mFirstSegment)
|
||||
{
|
||||
while (segment != mLastSegment)
|
||||
{
|
||||
segment_type* nextSegment = segment->mNext;
|
||||
segment->~segment_type();
|
||||
EASTLFree(mAllocator, segment, sizeof(segment_type));
|
||||
segment = nextSegment;
|
||||
}
|
||||
for (T* i = segment->mData, *e = segment->mData + segment->mSize; i!=e; ++i)
|
||||
i->~T();
|
||||
EASTLFree(mAllocator, segment, sizeof(segment_type));
|
||||
mFirstSegment = 0;
|
||||
mLastSegment = 0;
|
||||
mSegmentCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline T&
|
||||
segmented_vector<T, Count, Allocator>::push_back()
|
||||
{
|
||||
return *(new (DoPushBack()) T());
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline T&
|
||||
segmented_vector<T, Count, Allocator>::push_back(const T& value)
|
||||
{
|
||||
return *(new (DoPushBack()) T(value));
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline void*
|
||||
segmented_vector<T, Count, Allocator>::push_back_uninitialized()
|
||||
{
|
||||
return DoPushBack();
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline void
|
||||
segmented_vector<T, Count, Allocator>::pop_back()
|
||||
{
|
||||
segment_type* lastSegment = mLastSegment;
|
||||
#if EASTL_ASSERT_ENABLED
|
||||
if(EASTL_UNLIKELY(!lastSegment))
|
||||
EASTL_FAIL_MSG("segmented_vector::pop_back -- segmented vector is empty");
|
||||
#endif
|
||||
--lastSegment->mSize;
|
||||
(lastSegment->mData + lastSegment->mSize)->T::~T();
|
||||
|
||||
if (!lastSegment->mSize)
|
||||
{
|
||||
--mSegmentCount;
|
||||
mLastSegment = (segment_type*)(lastSegment->mPrev & (~segment_type::kIsLastSegment));
|
||||
EASTLFree(mAllocator, lastSegment, sizeof(segment_type));
|
||||
if (mLastSegment)
|
||||
{
|
||||
mLastSegment->mPrev |= segment_type::kIsLastSegment;
|
||||
mLastSegment->mSize = Count;
|
||||
}
|
||||
else
|
||||
mFirstSegment = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline void
|
||||
segmented_vector<T, Count, Allocator>::erase_unsorted(segment_type& segment, typename segment_type::iterator it)
|
||||
{
|
||||
*it = back();
|
||||
pop_back();
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline typename segmented_vector<T, Count, Allocator>::iterator
|
||||
segmented_vector<T, Count, Allocator>::erase_unsorted(const iterator& i)
|
||||
{
|
||||
iterator ret(i);
|
||||
*i = back();
|
||||
if (i.mSegment == mLastSegment && mLastSegment->mSize == 1)
|
||||
ret.mCurrent = 0;
|
||||
pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
void
|
||||
segmented_vector<T, Count, Allocator>::swap(this_type& other)
|
||||
{
|
||||
allocator_type tempAllocator(mAllocator);
|
||||
segment_type* tempFirstSegment = mFirstSegment;
|
||||
segment_type* tempLastSegment = mLastSegment;
|
||||
size_type tempSegmentCount = mSegmentCount;
|
||||
|
||||
mAllocator = other.mAllocator;
|
||||
mFirstSegment = other.mFirstSegment;
|
||||
mLastSegment = other.mLastSegment;
|
||||
mSegmentCount = other.mSegmentCount;
|
||||
|
||||
other.mAllocator = tempAllocator;
|
||||
other.mFirstSegment = tempFirstSegment;
|
||||
other.mLastSegment = tempLastSegment;
|
||||
other.mSegmentCount = tempSegmentCount;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
segment<T, Count, Allocator>*
|
||||
segmented_vector<T, Count, Allocator>::DoAllocSegment(segment_type* prevSegment)
|
||||
{
|
||||
++mSegmentCount;
|
||||
segment_type* segment = (segment_type*)allocate_memory(mAllocator, sizeof(segment_type), EASTL_ALIGN_OF(segment_type), 0);
|
||||
segment->mPrev = uintptr_t(prevSegment) | segment_type::kIsLastSegment;
|
||||
segment->mSize = 1;
|
||||
return segment;
|
||||
}
|
||||
|
||||
template <typename T, size_t Count, typename Allocator>
|
||||
inline void*
|
||||
segmented_vector<T, Count, Allocator>::DoPushBack()
|
||||
{
|
||||
if (segment_type* segment = mLastSegment)
|
||||
{
|
||||
size_type size = segment->mSize;
|
||||
if (size < Count)
|
||||
{
|
||||
++segment->mSize;
|
||||
return segment->mData + size;
|
||||
}
|
||||
else
|
||||
{
|
||||
segment_type* lastSegment = mLastSegment;
|
||||
segment_type* newSegment = mLastSegment = DoAllocSegment(mLastSegment);
|
||||
lastSegment->mPrev &= ~segment_type::kIsLastSegment;
|
||||
lastSegment->mNext = newSegment;
|
||||
return newSegment->mData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = mFirstSegment = mLastSegment = DoAllocSegment(0);
|
||||
return segment->mData;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline bool operator==(const segmented_vector_iterator<const T, Count, Allocator>& a, const segmented_vector_iterator<const T, Count, Allocator>& b)
|
||||
{
|
||||
return a.mCurrent == b.mCurrent;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline bool operator!=(const segmented_vector_iterator<const T, Count, Allocator>& a, const segmented_vector_iterator<const T, Count, Allocator>& b)
|
||||
{
|
||||
return a.mCurrent != b.mCurrent;
|
||||
}
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline bool operator==(const segmented_vector_iterator<T, Count, Allocator>& a, const segmented_vector_iterator<T, Count, Allocator>& b)
|
||||
{
|
||||
return a.mCurrent == b.mCurrent;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, size_t Count, typename Allocator>
|
||||
inline bool operator!=(const segmented_vector_iterator<T, Count, Allocator>& a, const segmented_vector_iterator<T, Count, Allocator>& b)
|
||||
{
|
||||
return a.mCurrent != b.mCurrent;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -133,7 +133,7 @@ namespace eastl
|
||||
/// If an exception occurs during the allocation of the shared
|
||||
/// reference count, the owned pointer is deleted and the exception
|
||||
/// is rethrown. A null pointer is given a reference count of 1.
|
||||
explicit shared_array(T* pArray = NULL, const allocator& allocator = EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR)
|
||||
explicit shared_array(T* pArray = NULL, const allocator_type& allocator = EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR)
|
||||
: mpArray(pArray),
|
||||
mpRefCount(NULL),
|
||||
mAllocator(allocator)
|
||||
|
||||
174
include/EASTL/string_hash_map.h
Normal file
174
include/EASTL/string_hash_map.h
Normal file
@@ -0,0 +1,174 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_STRING_HASH_MAP_H
|
||||
#define EASTL_STRING_HASH_MAP_H
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <EASTL/hash_map.h>
|
||||
#include <EASTL/string.h>
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
|
||||
|
||||
template<typename T, typename Hash = hash<string>, typename Predicate = equal_to<string>, typename Allocator = EASTLAllocatorType>
|
||||
class string_hash_map : public eastl::hash_map<const char*, T, Hash, Predicate, Allocator>
|
||||
{
|
||||
public:
|
||||
typedef eastl::hash_map<const char*, T, Hash, Predicate, Allocator> base;
|
||||
typedef string_hash_map<T, Hash, Predicate, Allocator> this_type;
|
||||
typedef typename base::base_type::allocator_type allocator_type;
|
||||
typedef typename base::base_type::insert_return_type insert_return_type;
|
||||
typedef typename base::base_type::iterator iterator;
|
||||
//typedef typename base::base_type::reverse_iterator reverse_iterator;
|
||||
typedef typename base::base_type::const_iterator const_iterator;
|
||||
typedef typename base::base_type::size_type size_type;
|
||||
typedef typename base::base_type::value_type value_type;
|
||||
typedef typename base::mapped_type mapped_type;
|
||||
|
||||
string_hash_map(const allocator_type& allocator = allocator_type()) : base(allocator) {}
|
||||
string_hash_map(const string_hash_map& src, const allocator_type& allocator = allocator_type());
|
||||
~string_hash_map();
|
||||
void clear();
|
||||
void clear(bool clearBuckets);
|
||||
|
||||
this_type& operator=(const this_type& x);
|
||||
|
||||
insert_return_type insert(const char* key, const T& value);
|
||||
insert_return_type insert(const char* key);
|
||||
iterator erase(const_iterator position);
|
||||
size_type erase(const char* key);
|
||||
mapped_type& operator[](const char* key);
|
||||
|
||||
private:
|
||||
char* strduplicate(const char* str);
|
||||
|
||||
// Not implemented right now
|
||||
//insert_return_type insert(const value_type& value);
|
||||
//iterator insert(iterator position, const value_type& value);
|
||||
//reverse_iterator erase(reverse_iterator position);
|
||||
//reverse_iterator erase(reverse_iterator first, reverse_iterator last);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::string_hash_map(const string_hash_map& src, const allocator_type& allocator) : base(allocator)
|
||||
{
|
||||
for (const_iterator i=src.begin(), e=src.end(); i!=e; ++i)
|
||||
base::base_type::insert(eastl::make_pair(strduplicate(i->first), i->second));
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::~string_hash_map()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
void
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::clear()
|
||||
{
|
||||
allocator_type& allocator = base::base_type::get_allocator();
|
||||
for (const_iterator i=base::base_type::begin(), e=base::base_type::end(); i!=e; ++i)
|
||||
allocator.deallocate((void*)i->first, 0);
|
||||
base::base_type::clear();
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
void
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::clear(bool clearBuckets)
|
||||
{
|
||||
allocator_type& allocator = base::base_type::get_allocator();
|
||||
for (const_iterator i=base::base_type::begin(), e=base::base_type::end(); i!=e; ++i)
|
||||
allocator.deallocate((void*)i->first, 0);
|
||||
base::base_type::clear(clearBuckets);
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::this_type&
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::operator=(const this_type& x)
|
||||
{
|
||||
allocator_type allocator = base::base_type::get_allocator();
|
||||
this->~this_type();
|
||||
new (this) this_type(x, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::insert_return_type
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::insert(const char* key)
|
||||
{
|
||||
return insert(key, mapped_type());
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::insert_return_type
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::insert(const char* key, const T& value)
|
||||
{
|
||||
EASTL_ASSERT(key);
|
||||
iterator i = base::base_type::find(key);
|
||||
if (i != base::base_type::end())
|
||||
{
|
||||
insert_return_type ret;
|
||||
ret.first = i;
|
||||
ret.second = false;
|
||||
return ret;
|
||||
}
|
||||
return base::base_type::insert(eastl::make_pair(strduplicate(key), value));
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::iterator
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::erase(const_iterator position)
|
||||
{
|
||||
const char* key = position->first;
|
||||
iterator result = base::base_type::erase(position);
|
||||
base::base_type::get_allocator().deallocate((void*)key, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::size_type
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::erase(const char* key)
|
||||
{
|
||||
const iterator it(base::base_type::find(key));
|
||||
|
||||
if(it != base::base_type::end())
|
||||
{
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
typename string_hash_map<T, Hash, Predicate, Allocator>::mapped_type&
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::operator[](const char* key)
|
||||
{
|
||||
EASTL_ASSERT(key);
|
||||
iterator i = base::base_type::find(key);
|
||||
if (i != base::base_type::end())
|
||||
return i->second;
|
||||
return base::base_type::insert(strduplicate(key)).first->second;
|
||||
}
|
||||
|
||||
template<typename T, typename Hash, typename Predicate, typename Allocator>
|
||||
char*
|
||||
string_hash_map<T, Hash, Predicate, Allocator>::strduplicate(const char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char* result = (char*)base::base_type::get_allocator().allocate(len + 1);
|
||||
memcpy(result, str, len+1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
165
include/EASTL/string_map.h
Normal file
165
include/EASTL/string_map.h
Normal file
@@ -0,0 +1,165 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EASTL_STRING_MAP_H
|
||||
#define EASTL_STRING_MAP_H
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <EASTL/map.h>
|
||||
#include <EASTL/string.h>
|
||||
|
||||
namespace eastl
|
||||
{
|
||||
|
||||
|
||||
template<typename T, typename Predicate = less<string>, typename Allocator = EASTLAllocatorType>
|
||||
class string_map : public eastl::map<const char*, T, Predicate, Allocator>
|
||||
{
|
||||
public:
|
||||
typedef eastl::map<const char*, T, Predicate, Allocator> base;
|
||||
typedef string_map<T, Predicate, Allocator> this_type;
|
||||
typedef typename base::base_type::allocator_type allocator_type;
|
||||
typedef typename base::base_type::insert_return_type insert_return_type;
|
||||
typedef typename base::base_type::iterator iterator;
|
||||
typedef typename base::base_type::reverse_iterator reverse_iterator;
|
||||
typedef typename base::base_type::const_iterator const_iterator;
|
||||
typedef typename base::base_type::size_type size_type;
|
||||
typedef typename base::base_type::key_type key_type;
|
||||
typedef typename base::base_type::value_type value_type;
|
||||
typedef typename base::mapped_type mapped_type;
|
||||
|
||||
string_map(const allocator_type& allocator = allocator_type()) : base(allocator) {}
|
||||
string_map(const string_map& src, const allocator_type& allocator = allocator_type());
|
||||
~string_map();
|
||||
void clear();
|
||||
|
||||
this_type& operator=(const this_type& x);
|
||||
|
||||
insert_return_type insert(const char* key, const T& value);
|
||||
insert_return_type insert(const char* key);
|
||||
iterator erase(iterator position);
|
||||
size_type erase(const char* key);
|
||||
mapped_type& operator[](const char* key);
|
||||
|
||||
private:
|
||||
char* strduplicate(const char* str);
|
||||
|
||||
// Not implemented right now
|
||||
//insert_return_type insert(const value_type& value);
|
||||
//iterator insert(iterator position, const value_type& value);
|
||||
//reverse_iterator erase(reverse_iterator position);
|
||||
//reverse_iterator erase(reverse_iterator first, reverse_iterator last);
|
||||
//void erase(const key_type* first, const key_type* last);
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
string_map<T, Predicate, Allocator>::string_map(const string_map& src, const allocator_type& allocator) : base(allocator)
|
||||
{
|
||||
for (const_iterator i=src.begin(), e=src.end(); i!=e; ++i)
|
||||
base::base_type::insert(eastl::make_pair(strduplicate(i->first), i->second));
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
string_map<T, Predicate, Allocator>::~string_map()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
void
|
||||
string_map<T, Predicate, Allocator>::clear()
|
||||
{
|
||||
allocator_type& allocator = base::base_type::get_allocator();
|
||||
for (const_iterator i=base::base_type::begin(), e=base::base_type::end(); i!=e; ++i)
|
||||
allocator.deallocate((void*)i->first, 0);
|
||||
base::base_type::clear();
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::this_type&
|
||||
string_map<T, Predicate, Allocator>::operator=(const this_type& x)
|
||||
{
|
||||
allocator_type allocator = base::base_type::get_allocator();
|
||||
this->~this_type();
|
||||
new (this) this_type(x, allocator);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::insert_return_type
|
||||
string_map<T, Predicate, Allocator>::insert(const char* key)
|
||||
{
|
||||
return insert(key, mapped_type());
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::insert_return_type
|
||||
string_map<T, Predicate, Allocator>::insert(const char* key, const T& value)
|
||||
{
|
||||
EASTL_ASSERT(key);
|
||||
iterator i = base::base_type::find(key);
|
||||
if (i != base::base_type::end())
|
||||
{
|
||||
insert_return_type ret;
|
||||
ret.first = i;
|
||||
ret.second = false;
|
||||
return ret;
|
||||
}
|
||||
return base::base_type::insert(eastl::make_pair(strduplicate(key), value));
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::iterator
|
||||
string_map<T, Predicate, Allocator>::erase(iterator position)
|
||||
{
|
||||
const char* key = position->first;
|
||||
iterator result = base::base_type::erase(position);
|
||||
base::base_type::get_allocator().deallocate((void*)key, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::size_type
|
||||
string_map<T, Predicate, Allocator>::erase(const char* key)
|
||||
{
|
||||
const iterator it(base::base_type::find(key));
|
||||
|
||||
if(it != base::base_type::end())
|
||||
{
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
typename string_map<T, Predicate, Allocator>::mapped_type&
|
||||
string_map<T, Predicate, Allocator>::operator[](const char* key)
|
||||
{
|
||||
EASTL_ASSERT(key);
|
||||
iterator i = base::base_type::find(key);
|
||||
if (i != base::base_type::end())
|
||||
return i->second;
|
||||
return base::base_type::insert(strduplicate(key)).first->second;
|
||||
}
|
||||
|
||||
template<typename T, typename Predicate, typename Allocator>
|
||||
char*
|
||||
string_map<T, Predicate, Allocator>::strduplicate(const char* str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char* result = (char*)base::base_type::get_allocator().allocate(len + 1);
|
||||
memcpy(result, str, len+1);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -457,6 +457,10 @@ namespace eastl
|
||||
template <typename T, typename F>
|
||||
struct conditional<false, T, F> { typedef F type; };
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template <bool B, class T, class F>
|
||||
using conditional_t = typename conditional<B, T, F>::type;
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// identity
|
||||
@@ -750,6 +754,10 @@ namespace eastl
|
||||
template <typename T> struct remove_reference<T&&>{ typedef T type; };
|
||||
#endif
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
template<typename T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <EASTL/internal/integer_sequence.h>
|
||||
#include <EASTL/internal/tuple_fwd_decls.h>
|
||||
#include <EASTL/internal/in_place_t.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push) // VC++ generates a bogus warning that you cannot code away.
|
||||
@@ -809,7 +810,8 @@ namespace eastl
|
||||
|
||||
#endif // EASTL_TUPLE_ENABLED
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
} // namespace eastl
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
|
||||
@@ -590,7 +590,7 @@ namespace eastl
|
||||
#if EASTL_MOVE_SEMANTICS_ENABLED
|
||||
template <typename T, typename Allocator>
|
||||
inline vector<T, Allocator>::vector(this_type&& x)
|
||||
: base_type(x.mAllocator)
|
||||
: base_type(eastl::move(x.mAllocator)) // vector requires move-construction of allocator in this case.
|
||||
{
|
||||
DoSwap(x);
|
||||
}
|
||||
@@ -600,7 +600,13 @@ namespace eastl
|
||||
inline vector<T, Allocator>::vector(this_type&& x, const allocator_type& allocator)
|
||||
: base_type(allocator)
|
||||
{
|
||||
swap(x); // member swap handles the case that x has a different allocator than our allocator by doing a copy.
|
||||
if (mAllocator == x.mAllocator) // If allocators are equivalent...
|
||||
DoSwap(x);
|
||||
else
|
||||
{
|
||||
this_type temp(eastl::move(*this)); // move construct so we don't require the use of copy-ctors that prevent the use of move-only types.
|
||||
temp.swap(x);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1381,10 +1387,10 @@ namespace eastl
|
||||
// allocator_traits<allocator_type>::propagate_on_container_swap::value is true (propagate_on_container_swap
|
||||
// is false by default). EASTL doesn't have allocator_traits and so this doesn't directly apply,
|
||||
// but EASTL has the effective behavior of propagate_on_container_swap = false for all allocators.
|
||||
// So EASTL swap exchanges contents but not allocators, and swap is more efficient if allocators are equivalent.
|
||||
template <typename T, typename Allocator>
|
||||
inline void vector<T, Allocator>::swap(this_type& x)
|
||||
{
|
||||
#if EASTL_VECTOR_LEGACY_SWAP_BEHAVIOUR_REQUIRES_COPY_CTOR
|
||||
if(mAllocator == x.mAllocator) // If allocators are equivalent...
|
||||
DoSwap(x);
|
||||
else // else swap the contents.
|
||||
@@ -1393,6 +1399,27 @@ namespace eastl
|
||||
*this = x; // itself call this member swap function.
|
||||
x = temp;
|
||||
}
|
||||
#else
|
||||
// NOTE(rparolin): The previous implementation required T to be copy-constructible in the fall-back case where
|
||||
// allocators with unique instances copied elements. This was an unnecessary restriction and prevented the common
|
||||
// usage of vector with non-copyable types (eg. eastl::vector<non_copyable> or eastl::vector<unique_ptr>).
|
||||
//
|
||||
// The previous implementation violated the following requirements of vector::swap so the fall-back code has
|
||||
// been removed. EASTL implicitly defines 'propagate_on_container_swap = false' therefore the fall-back case is
|
||||
// undefined behaviour. We simply swap the contents and the allocator as that is the common expectation of
|
||||
// users and does not put the container into an invalid state since it can not free its memory via its current
|
||||
// allocator instance.
|
||||
//
|
||||
// http://en.cppreference.com/w/cpp/container/vector/swap
|
||||
// "Exchanges the contents of the container with those of other. Does not invoke any move, copy, or swap
|
||||
// operations on individual elements."
|
||||
//
|
||||
// http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer
|
||||
// "Swapping two containers with unequal allocators if propagate_on_container_swap is false is undefined
|
||||
// behavior."
|
||||
|
||||
DoSwap(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1445,7 +1472,7 @@ namespace eastl
|
||||
inline void vector<T, Allocator>::DoInitFromIterator(InputIterator first, InputIterator last, EASTL_ITC_NS::input_iterator_tag)
|
||||
{
|
||||
// To do: Use emplace_back instead of push_back(). Our emplace_back will work below without any ifdefs.
|
||||
for(; first < last; ++first) // InputIterators by definition actually only allow you to iterate through them once.
|
||||
for(; first != last; ++first) // InputIterators by definition actually only allow you to iterate through them once.
|
||||
push_back(*first); // Thus the standard *requires* that we do this (inefficient) implementation.
|
||||
} // Luckily, InputIterators are in practice almost never used, so this code will likely never get executed.
|
||||
|
||||
@@ -1730,7 +1757,7 @@ namespace eastl
|
||||
void vector<T, Allocator>::DoClearCapacity() // This function exists because set_capacity() currently indirectly requires value_type to be default-constructible,
|
||||
{ // and some functions that need to clear our capacity (e.g. operator=) aren't supposed to require default-constructibility.
|
||||
clear();
|
||||
this_type temp(*this); // This is the simplest way to accomplish this,
|
||||
this_type temp(eastl::move(*this)); // This is the simplest way to accomplish this,
|
||||
swap(temp); // and it is as efficient as any other.
|
||||
}
|
||||
|
||||
|
||||
@@ -1054,9 +1054,9 @@
|
||||
#if !defined(EA_COMPILER_NO_VARIABLE_TEMPLATES)
|
||||
#if defined(_MSC_VER) && (_MSC_FULL_VER >= 190023918) // VS2015 Update 2 and above.
|
||||
// supported.
|
||||
#elif defined(__clang__) && (EA_COMPILER_VERSION >= 340) && !defined(__APPLE__) // Clang 3.4+, not including Apple's Clang.
|
||||
#elif defined(EA_COMPILER_CPP14_ENABLED) && defined(__clang__) && (EA_COMPILER_VERSION >= 304) && !defined(__APPLE__) // Clang 3.4+, not including Apple's Clang.
|
||||
// supported.
|
||||
#elif defined(__GNUC__) && (EA_COMPILER_VERSION >= 5000) // GCC 5+
|
||||
#elif defined(EA_COMPILER_CPP14_ENABLED) && defined(__GNUC__) && (EA_COMPILER_VERSION >= 5000) // GCC 5+
|
||||
// supported.
|
||||
#elif !defined(EA_COMPILER_CPP14_ENABLED)
|
||||
#define EA_COMPILER_NO_VARIABLE_TEMPLATES 1
|
||||
|
||||
@@ -68,6 +68,12 @@
|
||||
* EA_DISABLE_EDG_WARNING / EA_RESTORE_EDG_WARNING
|
||||
* EA_DISABLE_CW_WARNING / EA_RESTORE_CW_WARNING
|
||||
*
|
||||
* EA_DISABLE_DEFAULT_CTOR
|
||||
* EA_DISABLE_COPY_CTOR
|
||||
* EA_DISABLE_MOVE_CTOR
|
||||
* EA_DISABLE_ASSIGNMENT_OPERATOR
|
||||
* EA_DISABLE_MOVE_OPERATOR
|
||||
*
|
||||
* Todo:
|
||||
* Find a way to reliably detect wchar_t size at preprocessor time and
|
||||
* implement it below for EA_WCHAR_SIZE.
|
||||
@@ -1022,7 +1028,7 @@
|
||||
#define EA_WCHAR_T_NON_NATIVE 1
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_BORLAND)
|
||||
#elif defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_BORLAND) || (defined(EA_COMPILER_CLANG) && defined(EA_PLATFORM_WINDOWS))
|
||||
#ifndef _NATIVE_WCHAR_T_DEFINED
|
||||
#define EA_WCHAR_T_NON_NATIVE 1
|
||||
#endif
|
||||
@@ -1796,6 +1802,85 @@
|
||||
#define EA_FUNCTION_DELETE = delete
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_DEFAULT_CTOR
|
||||
//
|
||||
// Disables the compiler generated default constructor. This macro is
|
||||
// provided to improve portability and clarify intent of code.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class Example
|
||||
// {
|
||||
// private:
|
||||
// EA_DISABLE_DEFAULT_CTOR(Example);
|
||||
// };
|
||||
//
|
||||
#define EA_DISABLE_DEFAULT_CTOR(ClassName) ClassName() EA_FUNCTION_DELETE
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_COPY_CTOR
|
||||
//
|
||||
// Disables the compiler generated copy constructor. This macro is
|
||||
// provided to improve portability and clarify intent of code.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class Example
|
||||
// {
|
||||
// private:
|
||||
// EA_DISABLE_COPY_CTOR(Example);
|
||||
// };
|
||||
//
|
||||
#define EA_DISABLE_COPY_CTOR(ClassName) ClassName(const ClassName &) EA_FUNCTION_DELETE
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_MOVE_CTOR
|
||||
//
|
||||
// Disables the compiler generated move constructor. This macro is
|
||||
// provided to improve portability and clarify intent of code.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class Example
|
||||
// {
|
||||
// private:
|
||||
// EA_DISABLE_MOVE_CTOR(Example);
|
||||
// };
|
||||
//
|
||||
#define EA_DISABLE_MOVE_CTOR(ClassName) ClassName(ClassName&&) EA_FUNCTION_DELETE
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_ASSIGNMENT_OPERATOR
|
||||
//
|
||||
// Disables the compiler generated assignment operator. This macro is
|
||||
// provided to improve portability and clarify intent of code.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class Example
|
||||
// {
|
||||
// private:
|
||||
// EA_DISABLE_ASSIGNMENT_OPERATOR(Example);
|
||||
// };
|
||||
//
|
||||
#define EA_DISABLE_ASSIGNMENT_OPERATOR(ClassName) ClassName & operator=(const ClassName &) EA_FUNCTION_DELETE
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EA_DISABLE_MOVE_OPERATOR
|
||||
//
|
||||
// Disables the compiler generated move operator. This macro is
|
||||
// provided to improve portability and clarify intent of code.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// class Example
|
||||
// {
|
||||
// private:
|
||||
// EA_DISABLE_MOVE_OPERATOR(Example);
|
||||
// };
|
||||
//
|
||||
#define EA_DISABLE_MOVE_OPERATOR(ClassName) ClassName & operator=(ClassName&&) EA_FUNCTION_DELETE
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// EANonCopyable
|
||||
@@ -1867,7 +1952,7 @@
|
||||
#define EA_OPTIMIZE_OFF() \
|
||||
_Pragma("GCC push_options") \
|
||||
_Pragma("GCC optimize 0")
|
||||
#elif defined(EA_COMPILER_CLANG)
|
||||
#elif defined(EA_COMPILER_CLANG) && !defined(EA_PLATFORM_ANDROID) // android clang 305 compiler crashes when this pragma is used
|
||||
#define EA_OPTIMIZE_OFF() \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) \
|
||||
_Pragma("clang optimize off") \
|
||||
@@ -1882,7 +1967,7 @@
|
||||
#define EA_OPTIMIZE_ON() __pragma(optimize("", on))
|
||||
#elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION > 4004) && (defined(__i386__) || defined(__x86_64__)) // GCC 4.4+ - Seems to work only on x86/Linux so far. However, GCC 4.4 itself appears broken and screws up parameter passing conventions.
|
||||
#define EA_OPTIMIZE_ON() _Pragma("GCC pop_options")
|
||||
#elif defined(EA_COMPILER_CLANG)
|
||||
#elif defined(EA_COMPILER_CLANG) && !defined(EA_PLATFORM_ANDROID) // android clang 305 compiler crashes when this pragma is used
|
||||
#define EA_OPTIMIZE_ON() \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas) \
|
||||
_Pragma("clang optimize on") \
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EABASE_VERSION
|
||||
#define EABASE_VERSION "2.07.00"
|
||||
#define EABASE_VERSION_N 20700
|
||||
#define EABASE_VERSION "2.07.01"
|
||||
#define EABASE_VERSION_N 20701
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1163,6 +1163,9 @@ int TestSuite::Run()
|
||||
{
|
||||
ResultInfo& resultInfo = *it;
|
||||
|
||||
eastl::string test_name;
|
||||
resultInfo.mpTest->GetName(test_name);
|
||||
|
||||
// If we already have a result for this test, we don't need to run it again.
|
||||
if(resultInfo.mnResult != kTestResultNone)
|
||||
continue;
|
||||
|
||||
@@ -54,13 +54,16 @@ int TestFixedString();
|
||||
int TestArray();
|
||||
int TestVector();
|
||||
int TestFixedVector();
|
||||
int TestSegmentedVector();
|
||||
int TestDeque();
|
||||
int TestMap();
|
||||
int TestFixedMap();
|
||||
int TestStringMap();
|
||||
int TestSet();
|
||||
int TestFixedSet();
|
||||
int TestHash();
|
||||
int TestFixedHash();
|
||||
int TestStringHashMap();
|
||||
int TestIntrusiveHash();
|
||||
int TestVectorMap();
|
||||
int TestVectorSet();
|
||||
@@ -75,6 +78,7 @@ int TestIterator();
|
||||
int TestRatio();
|
||||
int TestChrono();
|
||||
int TestOptional();
|
||||
int TestAny();
|
||||
|
||||
|
||||
// Now enable warnings as desired.
|
||||
@@ -371,7 +375,7 @@ struct TestObject
|
||||
int mX; // Value for the TestObject.
|
||||
bool mbThrowOnCopy; // Throw an exception of this object is copied, moved, or assigned to another.
|
||||
int64_t mId; // Unique id for each object, equal to its creation number. This value is not coped from other TestObjects during any operations, including moves.
|
||||
uint32_t mMagicValue; // Used to verify that an instance is valid and that it is not corrupted. It should alwasy be kMagicValue.
|
||||
uint32_t mMagicValue; // Used to verify that an instance is valid and that it is not corrupted. It should always be kMagicValue.
|
||||
static int64_t sTOCount; // Count of all current existing TestObjects.
|
||||
static int64_t sTOCtorCount; // Count of times any ctor was called.
|
||||
static int64_t sTODtorCount; // Count of times dtor was called.
|
||||
|
||||
@@ -626,6 +626,40 @@ static int TestMinMax()
|
||||
}
|
||||
|
||||
|
||||
static int TestClamp()
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
EATEST_VERIFY(eastl::clamp(42, 1, 100) == 42);
|
||||
EATEST_VERIFY(eastl::clamp(-42, 1, 100) == 1);
|
||||
EATEST_VERIFY(eastl::clamp(420, 1, 100) == 100);
|
||||
EATEST_VERIFY(eastl::clamp(1, 1, 100) == 1);
|
||||
EATEST_VERIFY(eastl::clamp(100, 1, 100) == 100);
|
||||
|
||||
EATEST_VERIFY(eastl::clamp(42.f, 1.f, 100.f, less<float>()) == 42.f);
|
||||
EATEST_VERIFY(eastl::clamp(-42.f, 1.f, 100.f, less<float>()) == 1.f);
|
||||
EATEST_VERIFY(eastl::clamp(420.f, 1.f, 100.f, less<float>()) == 100.f);
|
||||
EATEST_VERIFY(eastl::clamp(1.f, 1.f, 100.f, less<float>()) == 1.f);
|
||||
EATEST_VERIFY(eastl::clamp(100.f, 1.f, 100.f, less<float>()) == 100.f);
|
||||
|
||||
EATEST_VERIFY(eastl::clamp(42., 1., 100., less<double>()) == 42.);
|
||||
EATEST_VERIFY(eastl::clamp(-42., 1., 100., less<double>()) == 1.);
|
||||
EATEST_VERIFY(eastl::clamp(420., 1., 100., less<double>()) == 100.);
|
||||
EATEST_VERIFY(eastl::clamp(1., 1., 100., less<double>()) == 1.);
|
||||
EATEST_VERIFY(eastl::clamp(100., 1., 100., less<double>()) == 100.);
|
||||
|
||||
EATEST_VERIFY(eastl::clamp(A(42), A(1), A(100), LessStruct()).a == A(42).a);
|
||||
EATEST_VERIFY(eastl::clamp(A(-42), A(1), A(100), LessStruct()).a == A(1).a);
|
||||
EATEST_VERIFY(eastl::clamp(A(420), A(1), A(100), LessStruct()).a == A(100).a);
|
||||
EATEST_VERIFY(eastl::clamp(A(1), A(1), A(100), LessStruct()).a == A(1).a);
|
||||
EATEST_VERIFY(eastl::clamp(A(100), A(1), A(100), LessStruct()).a == A(100).a);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TestAlgorithm
|
||||
//
|
||||
@@ -642,6 +676,8 @@ int TestAlgorithm()
|
||||
TestObject::Reset();
|
||||
|
||||
nErrorCount += TestMinMax();
|
||||
nErrorCount += TestClamp();
|
||||
|
||||
|
||||
// bool all_of (InputIterator first, InputIterator last, Predicate p);
|
||||
// bool any_of (InputIterator first, InputIterator last, Predicate p);
|
||||
|
||||
389
test/source/TestAny.cpp
Normal file
389
test/source/TestAny.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/any.h>
|
||||
#include <EASTL/vector.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <EASTL/numeric.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
|
||||
// SmallTestObject
|
||||
//
|
||||
struct SmallTestObject
|
||||
{
|
||||
static int mCtorCount;
|
||||
|
||||
SmallTestObject() EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject(const SmallTestObject&) EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject(SmallTestObject&&) EA_NOEXCEPT { mCtorCount++; }
|
||||
SmallTestObject& operator=(const SmallTestObject&) EA_NOEXCEPT { mCtorCount++; return *this; }
|
||||
~SmallTestObject() EA_NOEXCEPT { mCtorCount--; }
|
||||
|
||||
static void Reset() { mCtorCount = 0; }
|
||||
static bool IsClear() { return mCtorCount == 0; }
|
||||
};
|
||||
|
||||
int SmallTestObject::mCtorCount = 0;
|
||||
|
||||
|
||||
// RequiresInitList
|
||||
//
|
||||
struct RequiresInitList
|
||||
{
|
||||
RequiresInitList(std::initializer_list<int> ilist)
|
||||
: sum(eastl::accumulate(begin(ilist), end(ilist), 0)) {}
|
||||
|
||||
int sum;
|
||||
};
|
||||
|
||||
|
||||
int TestAny()
|
||||
{
|
||||
using namespace eastl;
|
||||
EASTLTest_Printf("TestAny\n");
|
||||
int nErrorCount = 0;
|
||||
|
||||
// NOTE(rparolin): Ensure 'any' is at least the size of an eastl::string and an eastl::vector to prevent heap
|
||||
// allocation of handle objects (objects that point to a heap allocation). This will reduce memory pressure since
|
||||
// eastl::string will be a commonly used type. We could also test with a vector.
|
||||
{
|
||||
static_assert(sizeof(eastl::string) <= sizeof(eastl::any), "ensure that 'any' has enough local memory to store a string");
|
||||
static_assert(sizeof(eastl::vector<int>) <= sizeof(eastl::any), "ensure that 'any' has enough local memory to store a vector");
|
||||
}
|
||||
|
||||
{
|
||||
// default construct
|
||||
any a;
|
||||
VERIFY(a.has_value() == false);
|
||||
}
|
||||
|
||||
{
|
||||
// test object ctors & dtors are called for a large object
|
||||
TestObject::Reset();
|
||||
{ any a{TestObject()}; }
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
// test object ctors & dtors are called for a small object
|
||||
SmallTestObject::Reset();
|
||||
{ any a{SmallTestObject()}; }
|
||||
VERIFY(SmallTestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
any a(42);
|
||||
VERIFY(a.has_value() == true);
|
||||
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
VERIFY(any_cast<int>(a) != 1337);
|
||||
any_cast<int&>(a) = 10;
|
||||
VERIFY(any_cast<int>(a) == 10);
|
||||
|
||||
a = 1.f;
|
||||
any_cast<float&>(a) = 1337.f;
|
||||
VERIFY(any_cast<float>(a) == 1337.f);
|
||||
|
||||
a = 4343;
|
||||
VERIFY(any_cast<int>(a) == 4343);
|
||||
|
||||
a = string("hello world");
|
||||
VERIFY(any_cast<string>(a) == "hello world");
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
}
|
||||
|
||||
{
|
||||
struct custom_type { int data; };
|
||||
|
||||
any a = custom_type{};
|
||||
any_cast<custom_type&>(a).data = 42;
|
||||
VERIFY(any_cast<custom_type>(a).data == 42);
|
||||
}
|
||||
|
||||
{
|
||||
any a = 42;
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
int throwCount = 0;
|
||||
try { VERIFY(any_cast<short>(a) == 42); }
|
||||
catch (bad_any_cast) { throwCount++; }
|
||||
VERIFY(throwCount != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va = {42, 'a', 42.f, 3333u, 4444ul, 5555ull, 6666.0};
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<unsigned>(va[3]) == 3333u);
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
}
|
||||
|
||||
{
|
||||
any a(string("test string"));
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<string>(a) == "test string");
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va = {42, string("rob"), 'a', 42.f};
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<string>(va[1]) == "rob");
|
||||
VERIFY(any_cast<char>(va[2]) == 'a');
|
||||
VERIFY(any_cast<float>(va[3]) == 42.f);
|
||||
}
|
||||
|
||||
{
|
||||
vector<any> va;
|
||||
va.push_back(42);
|
||||
va.push_back(string("rob"));
|
||||
va.push_back('a');
|
||||
va.push_back(42.f);
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<string>(va[1]) == "rob");
|
||||
VERIFY(any_cast<char>(va[2]) == 'a');
|
||||
VERIFY(any_cast<float>(va[3]) == 42.f);
|
||||
}
|
||||
|
||||
// NOTE(rparolin): Replaces a small 'any' object with a large one and make sure it doesn't corrupt
|
||||
// the surrounding memory in the vector.
|
||||
{
|
||||
TestObject::Reset();
|
||||
{
|
||||
vector<any> va = {42, 'a', 42.f, 3333u, 4444ul, 5555ull, 6666.0};
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<unsigned>(va[3]) == 3333u);
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
|
||||
va[3] = TestObject(3333); // replace a small integral with a large heap allocated object.
|
||||
|
||||
VERIFY(any_cast<int>(va[0]) == 42);
|
||||
VERIFY(any_cast<char>(va[1]) == 'a');
|
||||
VERIFY(any_cast<float>(va[2]) == 42.f);
|
||||
VERIFY(any_cast<TestObject>(va[3]).mX == 3333); // not 3333u because TestObject ctor takes a signed type.
|
||||
VERIFY(any_cast<unsigned long>(va[4]) == 4444ul);
|
||||
VERIFY(any_cast<unsigned long long>(va[5]) == 5555ull);
|
||||
VERIFY(any_cast<double>(va[6]) == 6666.0);
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
{
|
||||
any a(string("test string"));
|
||||
VERIFY(a.has_value());
|
||||
a.reset();
|
||||
VERIFY(!a.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
any a1 = 42;
|
||||
any a2 = a1;
|
||||
|
||||
VERIFY(a1.has_value());
|
||||
VERIFY(a2.has_value());
|
||||
VERIFY(any_cast<int>(a1) == any_cast<int>(a2));
|
||||
}
|
||||
|
||||
{
|
||||
any a1;
|
||||
VERIFY(!a1.has_value());
|
||||
{
|
||||
any a2(string("test string"));
|
||||
a1 = any_cast<string>(a2);
|
||||
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
VERIFY(any_cast<string>(a1) == "test string");
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
any a1;
|
||||
VERIFY(!a1.has_value());
|
||||
{
|
||||
any a2(string("test string"));
|
||||
a1 = a2;
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
VERIFY(any_cast<string&>(a1) == "test string");
|
||||
VERIFY(a1.has_value());
|
||||
}
|
||||
|
||||
{
|
||||
any a1 = 42;
|
||||
any a2 = 24;
|
||||
VERIFY(any_cast<int>(a1) == 42);
|
||||
VERIFY(any_cast<int>(a2) == 24);
|
||||
|
||||
a1.swap(a2);
|
||||
VERIFY(any_cast<int>(a1) == 24);
|
||||
VERIFY(any_cast<int>(a2) == 42);
|
||||
|
||||
eastl::swap(a1, a2);
|
||||
VERIFY(any_cast<int>(a1) == 42);
|
||||
VERIFY(any_cast<int>(a2) == 24);
|
||||
}
|
||||
|
||||
#if EASTL_RTTI_ENABLED
|
||||
{
|
||||
VERIFY(EA::StdC::Strcmp(any(42).type().name(), "int") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42.f).type().name(), "float") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42u).type().name(), "unsigned int") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42ul).type().name(), "unsigned long") == 0);
|
||||
VERIFY(EA::StdC::Strcmp(any(42l).type().name(), "long") == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// emplace, small object tests
|
||||
{
|
||||
any a;
|
||||
|
||||
a.emplace<int>(42);
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
|
||||
a.emplace<short>((short)8); // no way to define a short literal we must cast here.
|
||||
VERIFY(any_cast<short>(a) == 8);
|
||||
VERIFY(a.has_value());
|
||||
|
||||
a.reset();
|
||||
VERIFY(!a.has_value());
|
||||
}
|
||||
|
||||
// emplace, large object tests
|
||||
{
|
||||
TestObject::Reset();
|
||||
{
|
||||
any a;
|
||||
a.emplace<TestObject>();
|
||||
VERIFY(a.has_value());
|
||||
}
|
||||
VERIFY(TestObject::IsClear());
|
||||
}
|
||||
|
||||
// emplace, initializer_list
|
||||
{
|
||||
{
|
||||
any a;
|
||||
a.emplace<RequiresInitList>(std::initializer_list<int>{1,2,3,4,5,6});
|
||||
|
||||
VERIFY(a.has_value());
|
||||
VERIFY(any_cast<RequiresInitList>(a).sum == 21);
|
||||
}
|
||||
}
|
||||
|
||||
// equivalence tests
|
||||
{
|
||||
any a, b;
|
||||
VERIFY(!a.has_value() == !b.has_value());
|
||||
|
||||
#if EASTL_EXCEPTIONS_ENABLED
|
||||
int bad_any_cast_thrown = 0;
|
||||
try
|
||||
{
|
||||
VERIFY(any_cast<int>(a) == any_cast<int>(b));
|
||||
}
|
||||
catch (eastl::bad_any_cast)
|
||||
{
|
||||
bad_any_cast_thrown++;
|
||||
}
|
||||
VERIFY(bad_any_cast_thrown != 0);
|
||||
#endif
|
||||
|
||||
|
||||
a = 42; b = 24;
|
||||
VERIFY(any_cast<int>(a) != any_cast<int>(b));
|
||||
VERIFY(a.has_value() == b.has_value());
|
||||
|
||||
a = 42; b = 42;
|
||||
VERIFY(any_cast<int>(a) == any_cast<int>(b));
|
||||
VERIFY(a.has_value() == b.has_value());
|
||||
}
|
||||
|
||||
// move tests
|
||||
{
|
||||
any a = string("hello world");
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
|
||||
auto s = move(any_cast<string&>(a)); // move string out
|
||||
VERIFY(s == "hello world");
|
||||
VERIFY(any_cast<string&>(a).empty());
|
||||
|
||||
any_cast<string&>(a) = move(s); // move string in
|
||||
VERIFY(any_cast<string&>(a) == "hello world");
|
||||
}
|
||||
|
||||
// nullptr tests
|
||||
{
|
||||
any* a = nullptr;
|
||||
VERIFY(any_cast<int>(a) == nullptr);
|
||||
VERIFY(any_cast<short>(a) == nullptr);
|
||||
VERIFY(any_cast<long>(a) == nullptr);
|
||||
VERIFY(any_cast<string>(a) == nullptr);
|
||||
|
||||
any b;
|
||||
VERIFY(any_cast<short>(&b) == nullptr);
|
||||
VERIFY(any_cast<const short>(&b) == nullptr);
|
||||
VERIFY(any_cast<volatile short>(&b) == nullptr);
|
||||
VERIFY(any_cast<const volatile short>(&b) == nullptr);
|
||||
|
||||
VERIFY(any_cast<short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<const short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<volatile short*>(&b) == nullptr);
|
||||
VERIFY(any_cast<const volatile short*>(&b) == nullptr);
|
||||
}
|
||||
|
||||
// Aligned type tests
|
||||
{
|
||||
// TODO(rparolin): Aligned types that do not fit into the local buffer optimization require use of global
|
||||
// operator new that takes the alignment parameter. I'm hesitant to add this dependency as it is not widely
|
||||
// used in EASTL containers. Consider for a future release.
|
||||
//
|
||||
// {
|
||||
// any a = Align16(1337);
|
||||
// VERIFY(any_cast<Align16>(a) == Align16(1337));
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// any a = Align32(1337);
|
||||
// VERIFY(any_cast<Align32>(a) == Align32(1337));
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// any a = Align64(1337);
|
||||
// VERIFY(any_cast<Align64>(a) == Align64(1337));
|
||||
// }
|
||||
}
|
||||
|
||||
// make_any
|
||||
{
|
||||
{
|
||||
auto a = make_any<int>(42);
|
||||
VERIFY(any_cast<int>(a) == 42);
|
||||
}
|
||||
|
||||
{
|
||||
auto a = make_any<RequiresInitList>(std::initializer_list<int>{1,2,3,4,5,6,7,8});
|
||||
VERIFY(any_cast<RequiresInitList&>(a).sum == 36);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace eastl
|
||||
class allocator;
|
||||
|
||||
template <typename T, typename Allocator> class basic_string;
|
||||
typedef basic_string<char, allocator> string8;
|
||||
typedef basic_string<char, allocator> local_string8; // collides with eastl::string8 in bulkbuilds
|
||||
|
||||
static void UseForwardDeclaredString(string8*)
|
||||
static void UseForwardDeclaredString(local_string8*)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ static int TestForwardDeclarations()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
eastl::string8 s8;
|
||||
eastl::local_string8 s8;
|
||||
UseForwardDeclaredString(&s8);
|
||||
|
||||
eastl::vector8 v8;
|
||||
|
||||
@@ -560,6 +560,22 @@ int TestFixedHash()
|
||||
nErrorCount += TestMultisetCpp11<eastl::fixed_hash_multiset<TestObject, 32, 7, true> >();
|
||||
}
|
||||
|
||||
{
|
||||
// void reserve(size_type nElementCount);
|
||||
|
||||
// test with overflow enabled.
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_set<int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_multiset<int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_map<int, int, 16>>()();
|
||||
nErrorCount += HashContainerReserveTest<fixed_hash_multimap<int, int, 16>>()();
|
||||
|
||||
// API prevents testing fixed size hash container reservation without overflow enabled.
|
||||
//
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_set<int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_multiset<int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_map<int, int, 400, 401, false>>()();
|
||||
// nErrorCount += HashContainerReserveTest<fixed_hash_multimap<int, int, 9000, 9001, false>>()();
|
||||
}
|
||||
|
||||
{
|
||||
// initializer_list support.
|
||||
|
||||
@@ -335,6 +335,15 @@ int TestHash()
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// void reserve(size_type nElementCount);
|
||||
nErrorCount += HashContainerReserveTest<hash_set<int>>()();
|
||||
nErrorCount += HashContainerReserveTest<hash_multiset<int>>()();
|
||||
nErrorCount += HashContainerReserveTest<hash_map<int, int>>()();
|
||||
nErrorCount += HashContainerReserveTest<hash_multimap<int, int>>()();
|
||||
}
|
||||
|
||||
|
||||
{ // Test hash_set with cached hash code.
|
||||
|
||||
// insert_return_type insert(const value_type& value) ;
|
||||
|
||||
@@ -1000,11 +1000,28 @@ int TestMultimapCpp11()
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename HashContainer>
|
||||
struct HashContainerReserveTest
|
||||
{
|
||||
int operator()()
|
||||
{
|
||||
int nErrorCount = 0;
|
||||
|
||||
HashContainer hashContainer;
|
||||
|
||||
const typename HashContainer::size_type reserve_sizes[] = {16, 128, 4096, 32768};
|
||||
for (auto& reserve_size : reserve_sizes)
|
||||
{
|
||||
hashContainer.reserve(reserve_size);
|
||||
|
||||
// verify bucket count and hashtable load_factor requirements
|
||||
VERIFY(hashContainer.bucket_count() >= reserve_size);
|
||||
VERIFY(hashContainer.load_factor() <= ceilf(reserve_size / hashContainer.get_max_load_factor()));
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
72
test/source/TestSegmentedVector.cpp
Normal file
72
test/source/TestSegmentedVector.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/segmented_vector.h>
|
||||
#include <EASTL/list.h>
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::segmented_vector<bool, 16>;
|
||||
template class eastl::segmented_vector<int, 16>;
|
||||
template class eastl::segmented_vector<Align64, 16>;
|
||||
template class eastl::segmented_vector<TestObject, 16>;
|
||||
|
||||
|
||||
int TestSegmentedVector()
|
||||
{
|
||||
EASTLTest_Printf("TestSegmentedVector\n");
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
TestObject::Reset();
|
||||
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
// Construct segmented_vectors of different types.
|
||||
|
||||
segmented_vector<int, 8> vectorOfInt;
|
||||
segmented_vector<TestObject, 8> vectorOfTO;
|
||||
segmented_vector<list<TestObject>, 8> vectorOfListOfTO;
|
||||
|
||||
EATEST_VERIFY(vectorOfInt.empty());
|
||||
EATEST_VERIFY(vectorOfTO.empty());
|
||||
EATEST_VERIFY(vectorOfListOfTO.empty());
|
||||
}
|
||||
|
||||
{
|
||||
using namespace eastl;
|
||||
|
||||
// Test basic segmented_vector operations.
|
||||
|
||||
segmented_vector<int, 4> vectorOfInt;
|
||||
|
||||
vectorOfInt.push_back(42);
|
||||
EATEST_VERIFY(vectorOfInt.size() == 1);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 1);
|
||||
EATEST_VERIFY(vectorOfInt.empty() == false);
|
||||
|
||||
vectorOfInt.push_back(43);
|
||||
vectorOfInt.push_back(44);
|
||||
vectorOfInt.push_back(45);
|
||||
vectorOfInt.push_back(46);
|
||||
EATEST_VERIFY(vectorOfInt.size() == 5);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 2);
|
||||
|
||||
EATEST_VERIFY(vectorOfInt.front() == 42);
|
||||
EATEST_VERIFY(vectorOfInt.back() == 46);
|
||||
|
||||
vectorOfInt.pop_back();
|
||||
EATEST_VERIFY(vectorOfInt.size() == 4);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 1);
|
||||
|
||||
vectorOfInt.clear();
|
||||
EATEST_VERIFY(vectorOfInt.empty());
|
||||
EATEST_VERIFY(vectorOfInt.size() == 0);
|
||||
EATEST_VERIFY(vectorOfInt.segment_count() == 0);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -28,7 +28,7 @@ int TEST_STRING_NAME()
|
||||
|
||||
// explicit basic_string(const allocator_type& allocator);
|
||||
{
|
||||
eastl::allocator alloc;
|
||||
typename StringType::allocator_type alloc;
|
||||
StringType str(alloc);
|
||||
VERIFY(str.validate());
|
||||
}
|
||||
|
||||
221
test/source/TestStringHashMap.cpp
Normal file
221
test/source/TestStringHashMap.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/string_hash_map.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::string_hash_map<int>;
|
||||
template class eastl::string_hash_map<Align32>;
|
||||
|
||||
static const char* strings[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"};
|
||||
static const size_t kStringCount = 10; // This is intentionally half the length of strings, so that we can test with strings that are not inserted to the map.
|
||||
|
||||
|
||||
int TestStringHashMap()
|
||||
{
|
||||
EASTLTest_Printf("TestStringHashMap\n");
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{ // Test declarations
|
||||
string_hash_map<int> stringHashMap;
|
||||
|
||||
string_hash_map<int> stringHashMap2(stringHashMap);
|
||||
EATEST_VERIFY(stringHashMap2.size() == stringHashMap.size());
|
||||
EATEST_VERIFY(stringHashMap2 == stringHashMap);
|
||||
|
||||
|
||||
// allocator_type& get_allocator();
|
||||
// void set_allocator(const allocator_type& allocator);
|
||||
string_hash_map<int>::allocator_type& allocator = stringHashMap.get_allocator();
|
||||
stringHashMap.set_allocator(EASTLAllocatorType());
|
||||
stringHashMap.set_allocator(allocator);
|
||||
// To do: Try to find something better to test here.
|
||||
|
||||
|
||||
// const key_equal& key_eq() const;
|
||||
// key_equal& key_eq();
|
||||
string_hash_map<int> hs;
|
||||
const string_hash_map<int> hsc;
|
||||
|
||||
const string_hash_map<int>::key_equal& ke = hsc.key_eq();
|
||||
hs.key_eq() = ke;
|
||||
|
||||
|
||||
// const char* get_name() const;
|
||||
// void set_name(const char* pName);
|
||||
#if EASTL_NAME_ENABLED
|
||||
stringHashMap.get_allocator().set_name("test");
|
||||
const char* pName = stringHashMap.get_allocator().get_name();
|
||||
EATEST_VERIFY(equal(pName, pName + 5, "test"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
string_hash_map<int> stringHashMap;
|
||||
|
||||
// Clear a newly constructed, already empty container.
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
|
||||
stringHashMap.clear(true);
|
||||
EATEST_VERIFY(stringHashMap.validate());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.bucket_count() == 1);
|
||||
}
|
||||
|
||||
|
||||
{ // Test string_hash_map
|
||||
|
||||
// size_type size() const
|
||||
// bool empty() const
|
||||
// insert_return_type insert(const value_type& value);
|
||||
// insert_return_type insert(const value_type& value, hash_code_t c, node_type* pNodeNew = NULL);
|
||||
// iterator insert(const_iterator, const value_type& value);
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
// size_type count(const key_type& k) const;
|
||||
|
||||
typedef string_hash_map<int> StringHashMapInt;
|
||||
|
||||
StringHashMapInt stringHashMap;
|
||||
|
||||
EATEST_VERIFY(stringHashMap.empty());
|
||||
EATEST_VERIFY(stringHashMap.size() == 0);
|
||||
EATEST_VERIFY(stringHashMap.count(strings[0]) == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringHashMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(!stringHashMap.empty());
|
||||
EATEST_VERIFY(stringHashMap.size() == kStringCount);
|
||||
EATEST_VERIFY(stringHashMap.count(strings[0]) == 1);
|
||||
|
||||
int j = 0;
|
||||
for (StringHashMapInt::iterator it = stringHashMap.begin(); it != stringHashMap.end(); ++it, ++j)
|
||||
{
|
||||
int value = (*it).second;
|
||||
EATEST_VERIFY(value < (int)kStringCount);
|
||||
}
|
||||
|
||||
for(int i = 0; i < (int)kStringCount * 2; i++)
|
||||
{
|
||||
StringHashMapInt::iterator it = stringHashMap.find(strings[i]);
|
||||
|
||||
if (i < (int)kStringCount)
|
||||
{
|
||||
EATEST_VERIFY(it != stringHashMap.end());
|
||||
const char* k = (*it).first;
|
||||
int v = (*it).second;
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(k, strings[i]) == 0);
|
||||
EATEST_VERIFY(v == i);
|
||||
}
|
||||
else
|
||||
EATEST_VERIFY(it == stringHashMap.end());
|
||||
}
|
||||
|
||||
StringHashMapInt::insert_return_type result = stringHashMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == true);
|
||||
result = stringHashMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == false);
|
||||
result.first->second = 0;
|
||||
|
||||
// iterator erase(const_iterator);
|
||||
size_t nExpectedSize = stringHashMap.size();
|
||||
|
||||
StringHashMapInt::iterator itD = stringHashMap.find("d");
|
||||
EATEST_VERIFY(itD != stringHashMap.end());
|
||||
|
||||
// erase the element and verify that the size has decreased
|
||||
stringHashMap.erase(itD);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(stringHashMap.size() == nExpectedSize);
|
||||
|
||||
// verify that erased element is gone
|
||||
itD = stringHashMap.find(strings[3]);
|
||||
EATEST_VERIFY(itD == stringHashMap.end());
|
||||
|
||||
// iterator erase(const char*)
|
||||
StringHashMapInt::size_type n = stringHashMap.erase(strings[4]);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(n == 1);
|
||||
EATEST_VERIFY(stringHashMap.size() == nExpectedSize);
|
||||
|
||||
|
||||
// mapped_type& operator[](const key_type& key)
|
||||
stringHashMap.clear();
|
||||
|
||||
int x = stringHashMap["A"]; // A default-constructed int (i.e. 0) should be returned.
|
||||
EATEST_VERIFY(x == 0);
|
||||
|
||||
stringHashMap["B"] = 1;
|
||||
x = stringHashMap["B"];
|
||||
EATEST_VERIFY(x == 1); // Verify that the value we assigned is returned and a default-constructed value is not returned.
|
||||
|
||||
stringHashMap["A"] = 10; // Overwrite our previous 0 with 10.
|
||||
stringHashMap["B"] = 11;
|
||||
x = stringHashMap["A"];
|
||||
EATEST_VERIFY(x == 10); // Verify the value is as expected.
|
||||
x = stringHashMap["B"];
|
||||
EATEST_VERIFY(x == 11);
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// string_hash_map(const allocator_type& allocator);
|
||||
// string_hash_map& operator=(const this_type& x);
|
||||
// bool validate() const;
|
||||
|
||||
string_hash_map<int> stringHashMap1(EASTLAllocatorType("TestStringHashMap"));
|
||||
string_hash_map<int> stringHashMap2(stringHashMap1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
stringHashMap1.insert(strings[i], i);
|
||||
}
|
||||
|
||||
stringHashMap2 = stringHashMap1;
|
||||
string_hash_map<int> stringHashMap3(stringHashMap1);
|
||||
|
||||
EATEST_VERIFY(stringHashMap1.validate());
|
||||
EATEST_VERIFY(stringHashMap2.validate());
|
||||
EATEST_VERIFY(stringHashMap3.validate());
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
EATEST_VERIFY(stringHashMap1[strings[i]] == stringHashMap2[strings[i]]);
|
||||
EATEST_VERIFY(stringHashMap1[strings[i]] == stringHashMap3[strings[i]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
209
test/source/TestStringMap.cpp
Normal file
209
test/source/TestStringMap.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "EASTLTest.h"
|
||||
#include <EASTL/string_map.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
using namespace eastl;
|
||||
|
||||
|
||||
// Template instantations.
|
||||
// These tell the compiler to compile all the functions for the given class.
|
||||
template class eastl::string_map<int>;
|
||||
template class eastl::string_map<Align32>;
|
||||
|
||||
static const char* strings[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t" };
|
||||
static const size_t kStringCount = 10; // This is intentionally half the length of strings, so that we can test with strings that are not inserted to the map.
|
||||
|
||||
|
||||
int TestStringMap()
|
||||
{
|
||||
EASTLTest_Printf("TestStringMap\n");
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
{ // Test declarations
|
||||
string_map<int> stringMap;
|
||||
|
||||
string_map<int> stringMap2(stringMap);
|
||||
EATEST_VERIFY(stringMap2.size() == stringMap.size());
|
||||
EATEST_VERIFY(stringMap2 == stringMap);
|
||||
|
||||
|
||||
// allocator_type& get_allocator();
|
||||
// void set_allocator(const allocator_type& allocator);
|
||||
string_map<int>::allocator_type& allocator = stringMap.get_allocator();
|
||||
stringMap.set_allocator(EASTLAllocatorType());
|
||||
stringMap.set_allocator(allocator);
|
||||
// To do: Try to find something better to test here.
|
||||
|
||||
|
||||
// const char* get_name() const;
|
||||
// void set_name(const char* pName);
|
||||
#if EASTL_NAME_ENABLED
|
||||
stringMap.get_allocator().set_name("test");
|
||||
const char* pName = stringMap.get_allocator().get_name();
|
||||
EATEST_VERIFY(equal(pName, pName + 5, "test"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
string_map<int> stringMap;
|
||||
|
||||
// Clear a newly constructed, already empty container.
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
|
||||
stringMap.clear();
|
||||
EATEST_VERIFY(stringMap.validate());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
}
|
||||
|
||||
|
||||
{ // Test string_map
|
||||
|
||||
// size_type size() const
|
||||
// bool empty() const
|
||||
// insert_return_type insert(const value_type& value);
|
||||
// insert_return_type insert(const value_type& value, hash_code_t c, node_type* pNodeNew = NULL);
|
||||
// iterator insert(const_iterator, const value_type& value);
|
||||
// iterator find(const key_type& k);
|
||||
// const_iterator find(const key_type& k) const;
|
||||
// size_type count(const key_type& k) const;
|
||||
|
||||
typedef string_map<int> StringMapInt;
|
||||
|
||||
StringMapInt stringMap;
|
||||
|
||||
EATEST_VERIFY(stringMap.empty());
|
||||
EATEST_VERIFY(stringMap.size() == 0);
|
||||
EATEST_VERIFY(stringMap.count(strings[0]) == 0);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
stringMap.insert(strings[i], i);
|
||||
|
||||
EATEST_VERIFY(!stringMap.empty());
|
||||
EATEST_VERIFY(stringMap.size() == kStringCount);
|
||||
EATEST_VERIFY(stringMap.count(strings[0]) == 1);
|
||||
|
||||
int j = 0;
|
||||
for (StringMapInt::iterator it = stringMap.begin(); it != stringMap.end(); ++it, ++j)
|
||||
{
|
||||
int value = (*it).second;
|
||||
EATEST_VERIFY(value < (int)kStringCount);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)kStringCount * 2; i++)
|
||||
{
|
||||
StringMapInt::iterator it = stringMap.find(strings[i]);
|
||||
|
||||
if (i < (int)kStringCount)
|
||||
{
|
||||
EATEST_VERIFY(it != stringMap.end());
|
||||
const char* k = (*it).first;
|
||||
int v = (*it).second;
|
||||
EATEST_VERIFY(EA::StdC::Strcmp(k, strings[i]) == 0);
|
||||
EATEST_VERIFY(v == i);
|
||||
}
|
||||
else
|
||||
EATEST_VERIFY(it == stringMap.end());
|
||||
}
|
||||
|
||||
StringMapInt::insert_return_type result = stringMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == true);
|
||||
result = stringMap.insert("EASTLTEST");
|
||||
EATEST_VERIFY(result.second == false);
|
||||
result.first->second = 0;
|
||||
|
||||
// iterator erase(const_iterator);
|
||||
size_t nExpectedSize = stringMap.size();
|
||||
|
||||
StringMapInt::iterator itD = stringMap.find("d");
|
||||
EATEST_VERIFY(itD != stringMap.end());
|
||||
|
||||
// erase the element and verify that the size has decreased
|
||||
stringMap.erase(itD);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(stringMap.size() == nExpectedSize);
|
||||
|
||||
// verify that erased element is gone
|
||||
itD = stringMap.find(strings[3]);
|
||||
EATEST_VERIFY(itD == stringMap.end());
|
||||
|
||||
// iterator erase(const char*)
|
||||
StringMapInt::size_type n = stringMap.erase(strings[4]);
|
||||
nExpectedSize--;
|
||||
EATEST_VERIFY(n == 1);
|
||||
EATEST_VERIFY(stringMap.size() == nExpectedSize);
|
||||
|
||||
|
||||
// mapped_type& operator[](const key_type& key)
|
||||
stringMap.clear();
|
||||
|
||||
int x = stringMap["A"]; // A default-constructed int (i.e. 0) should be returned.
|
||||
EATEST_VERIFY(x == 0);
|
||||
|
||||
stringMap["B"] = 1;
|
||||
x = stringMap["B"];
|
||||
EATEST_VERIFY(x == 1); // Verify that the value we assigned is returned and a default-constructed value is not returned.
|
||||
|
||||
stringMap["A"] = 10; // Overwrite our previous 0 with 10.
|
||||
stringMap["B"] = 11;
|
||||
x = stringMap["A"];
|
||||
EATEST_VERIFY(x == 10); // Verify the value is as expected.
|
||||
x = stringMap["B"];
|
||||
EATEST_VERIFY(x == 11);
|
||||
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// string_map(const allocator_type& allocator);
|
||||
// string_map& operator=(const this_type& x);
|
||||
// bool validate() const;
|
||||
|
||||
string_map<int> stringMap1(EASTLAllocatorType("TestStringMap"));
|
||||
string_map<int> stringMap2(stringMap1);
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
stringMap1.insert(strings[i], i);
|
||||
}
|
||||
|
||||
stringMap2 = stringMap1;
|
||||
string_map<int> stringMap3(stringMap1);
|
||||
|
||||
EATEST_VERIFY(stringMap1.validate());
|
||||
EATEST_VERIFY(stringMap2.validate());
|
||||
EATEST_VERIFY(stringMap3.validate());
|
||||
|
||||
for (int i = 0; i < (int)kStringCount; i++)
|
||||
{
|
||||
EATEST_VERIFY(stringMap1[strings[i]] == stringMap2[strings[i]]);
|
||||
EATEST_VERIFY(stringMap1[strings[i]] == stringMap3[strings[i]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -306,6 +306,10 @@ int TestTuple()
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int TestTuple() { return 0; }
|
||||
|
||||
#endif // EASTL_TUPLE_ENABLED
|
||||
|
||||
EA_RESTORE_VC_WARNING()
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <EASTL/algorithm.h>
|
||||
#include <EASTL/utility.h>
|
||||
#include <EASTL/allocator_malloc.h>
|
||||
#include <EASTL/unique_ptr.h>
|
||||
|
||||
#include "ConceptImpls.h"
|
||||
|
||||
@@ -120,6 +121,19 @@ public:
|
||||
testmovable& operator=(testmovable&&) EA_NOEXCEPT { return *this; }
|
||||
};
|
||||
|
||||
|
||||
#if EASTL_VARIABLE_TEMPLATES_ENABLED
|
||||
/// custom type-trait which checks if a type is comparable via the <operator.
|
||||
template <class, class = eastl::void_t<>>
|
||||
struct is_less_comparable : eastl::false_type { };
|
||||
template <class T>
|
||||
struct is_less_comparable<T, eastl::void_t<decltype(eastl::declval<T>() < eastl::declval<T>())>> : eastl::true_type { };
|
||||
#else
|
||||
// bypass the test since the compiler doesn't support variable templates.
|
||||
template <class> struct is_less_comparable : eastl::false_type { };
|
||||
#endif
|
||||
|
||||
|
||||
int TestVector()
|
||||
{
|
||||
EASTLTest_Printf("TestVector\n");
|
||||
@@ -398,7 +412,7 @@ int TestVector()
|
||||
TestObject& r01 = vec01.at(6);
|
||||
EATEST_VERIFY(!(r01 == TestObject(0))); // Should not get here, as exception thrown.
|
||||
}
|
||||
catch (std::out_of_range& err) { EATEST_VERIFY(true); }
|
||||
catch (std::out_of_range&) { EATEST_VERIFY(true); }
|
||||
catch (...) { EATEST_VERIFY(false); }
|
||||
#endif
|
||||
}
|
||||
@@ -1400,5 +1414,81 @@ int TestVector()
|
||||
|
||||
#endif // EASTL_TEST_CONCEPT_IMPLS
|
||||
|
||||
{
|
||||
// validates our vector implementation does not use 'operator<' on input iterators during vector construction.
|
||||
//
|
||||
struct container_value_type { int data; };
|
||||
struct container_with_custom_iterator
|
||||
{
|
||||
struct iterator
|
||||
{
|
||||
typedef eastl::input_iterator_tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef int* pointer;
|
||||
typedef int& reference;
|
||||
|
||||
bool operator!=(const iterator& rhs) const { return false; }
|
||||
iterator& operator++() { return *this; }
|
||||
iterator operator++(int) { return *this; }
|
||||
container_value_type operator*() { return {}; }
|
||||
};
|
||||
|
||||
container_with_custom_iterator() {}
|
||||
|
||||
iterator begin() const { return {}; }
|
||||
iterator end() const { return {}; }
|
||||
bool empty() const { return false; }
|
||||
|
||||
private:
|
||||
eastl::vector<container_value_type> m_vector;
|
||||
};
|
||||
|
||||
static_assert(!is_less_comparable<container_with_custom_iterator::iterator>::value, "type cannot support comparison by '<' for this test");
|
||||
container_with_custom_iterator ci;
|
||||
eastl::vector<container_value_type> v2(ci.begin(), ci.end());
|
||||
}
|
||||
|
||||
|
||||
// unique_ptr tests
|
||||
{
|
||||
// Simple move-assignment test to prevent regressions where eastl::vector utilizes operations on T that are not necessary.
|
||||
{
|
||||
eastl::vector<eastl::unique_ptr<int>> v1;
|
||||
eastl::vector<eastl::unique_ptr<int>> v2;
|
||||
v2 = eastl::move(v1);
|
||||
}
|
||||
|
||||
{
|
||||
// This test verifies that eastl::vector can handle the move-assignment case where its utilizes two
|
||||
// different allocator instances that do not compare equal. An example of an allocator that compares equal
|
||||
// but isn't the same object instance is an allocator that shares the same memory allocation mechanism (eg.
|
||||
// malloc). The memory allocated from one instance can be freed by another instance in the case where
|
||||
// allocators compare equal. This test is verifying functionality in the opposite case where allocators
|
||||
// instances do not compare equal and must clean up its own allocated memory.
|
||||
InstanceAllocator::reset_all();
|
||||
{
|
||||
InstanceAllocator a1(uint8_t(0)), a2(uint8_t(1));
|
||||
eastl::vector<eastl::unique_ptr<int>, InstanceAllocator> v1(a1);
|
||||
eastl::vector<eastl::unique_ptr<int>, InstanceAllocator> v2(a2);
|
||||
|
||||
VERIFY(v1.get_allocator() != v2.get_allocator());
|
||||
|
||||
// add some data in the vector so we can move it to the other vector.
|
||||
v1.push_back(nullptr);
|
||||
v1.push_back(nullptr);
|
||||
v1.push_back(nullptr);
|
||||
v1.push_back(nullptr);
|
||||
|
||||
VERIFY(!v1.empty() && v2.empty());
|
||||
v2 = eastl::move(v1);
|
||||
VERIFY(v1.empty() && !v2.empty());
|
||||
v1.swap(v2);
|
||||
VERIFY(!v1.empty() && v2.empty());
|
||||
}
|
||||
VERIFY(InstanceAllocator::mMismatchCount == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
|
||||
@@ -83,15 +83,14 @@ int EAMain(int argc, char* argv[])
|
||||
|
||||
TestApplication testSuite("EASTL Unit Tests", argc, argv);
|
||||
|
||||
testSuite.AddTest("Any", TestAny);
|
||||
testSuite.AddTest("Optional", TestOptional);
|
||||
testSuite.AddTest("TypeTraits", TestTypeTraits);
|
||||
testSuite.AddTest("TestCppCXTypeTraits", TestCppCXTypeTraits);
|
||||
testSuite.AddTest("Extra", TestExtra);
|
||||
testSuite.AddTest("Functional", TestFunctional);
|
||||
testSuite.AddTest("Utility", TestUtility);
|
||||
#if EASTL_TUPLE_ENABLED
|
||||
testSuite.AddTest("Tuple", TestTuple);
|
||||
#endif // EASTL_TUPLE_ENABLED
|
||||
testSuite.AddTest("Memory", TestMemory);
|
||||
testSuite.AddTest("Allocator", TestAllocator);
|
||||
testSuite.AddTest("Random", TestRandom);
|
||||
@@ -111,13 +110,16 @@ int EAMain(int argc, char* argv[])
|
||||
testSuite.AddTest("Array", TestArray);
|
||||
testSuite.AddTest("Vector", TestVector);
|
||||
testSuite.AddTest("FixedVector", TestFixedVector);
|
||||
testSuite.AddTest("SegmentedVector", TestSegmentedVector);
|
||||
testSuite.AddTest("Deque", TestDeque);
|
||||
testSuite.AddTest("Map", TestMap);
|
||||
testSuite.AddTest("FixedMap", TestFixedMap);
|
||||
testSuite.AddTest("StringMap", TestStringMap);
|
||||
testSuite.AddTest("Set", TestSet);
|
||||
testSuite.AddTest("FixedSet", TestFixedSet);
|
||||
testSuite.AddTest("Hash", TestHash);
|
||||
testSuite.AddTest("FixedHash", TestFixedHash);
|
||||
testSuite.AddTest("FixedHash", TestStringHashMap);
|
||||
testSuite.AddTest("IntrusiveHash", TestIntrusiveHash);
|
||||
testSuite.AddTest("VectorMap", TestVectorMap);
|
||||
testSuite.AddTest("VectorSet", TestVectorSet);
|
||||
|
||||
Reference in New Issue
Block a user