3.04.00 release

This commit is contained in:
Rob Parolin
2016-10-26 07:46:48 -07:00
parent 0788b8c74d
commit d153910373
37 changed files with 2809 additions and 72 deletions

View File

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

View File

@@ -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
View File

@@ -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%/*

View File

@@ -1,2 +1,3 @@
/.git/
tags
.gitignore

View File

@@ -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
View 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

View File

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

View File

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

View 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

View File

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

View File

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

View File

@@ -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()

View 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

View File

@@ -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)

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

View File

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

View File

@@ -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)

View File

@@ -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.
}

View File

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

View File

@@ -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") \

View File

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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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
View 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;
}

View File

@@ -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;

View File

@@ -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.

View File

@@ -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) ;

View File

@@ -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;
}
};

View 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;
}

View File

@@ -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());
}

View 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;
}

View 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;
}

View File

@@ -306,6 +306,10 @@ int TestTuple()
return nErrorCount;
}
#else
int TestTuple() { return 0; }
#endif // EASTL_TUPLE_ENABLED
EA_RESTORE_VC_WARNING()

View File

@@ -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;
}

View File

@@ -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);