This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
MonsterDefense/lib/eastl/include/EASTL/memory.h

699 lines
27 KiB
C
Raw Permalink Normal View History

2019-03-01 20:29:19 -05:00
/*
Copyright (C) 2009-2010 Electronic Arts, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
///////////////////////////////////////////////////////////////////////////////
// EASTL/memory.h
//
// Copyright (c) 2005, Electronic Arts. All rights reserved.
// Written and maintained by Paul Pedriana.
// The uninitialized_move function was written by Ryan Ingram.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// This file implements the following functions from the C++ standard that
// are found in the <memory> header:
//
// Temporary memory:
// get_temporary_buffer
// return_temporary_buffer
//
// Uninitialized operations:
// These are the same as the copy, fill, and fill_n algorithms, except that
// they *construct* the destination with the source values rather than assign
// the destination with the source values.
//
// uninitialized_copy
// uninitialized_fill
// uninitialized_fill_n
// uninitialized_move - Extention to standard functionality.
// uninitialized_copy_ptr - Extention to standard functionality.
// uninitialized_fill_ptr - Extention to standard functionality.
// uninitialized_fill_n_ptr - Extention to standard functionality.
// uninitialized_copy_fill - Extention to standard functionality.
// uninitialized_fill_copy - Extention to standard functionality.
// uninitialized_copy_copy - Extention to standard functionality.
//
// In-place destructor helpers:
// destruct(T*)
// destruct(first, last)
//
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_MEMORY_H
#define EASTL_MEMORY_H
#include <EASTL/internal/config.h>
#include <EASTL/internal/generic_iterator.h>
#include <EASTL/type_traits.h>
#include <EASTL/algorithm.h>
#include <EASTL/allocator.h>
#ifdef _MSC_VER
#pragma warning(push, 0)
#endif
#include <stdlib.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
#endif
namespace eastl
{
/// EASTL_TEMP_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_TEMP_DEFAULT_NAME
#define EASTL_TEMP_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " temp" // Unless the user overrides something, this is "EASTL temp".
#endif
/// get_temporary_buffer
///
/// From the C++ standard, section 20.4.3:
/// 1 Effects: Obtains a pointer to storage sufficient to store up to n adjacent T objects.
/// 2 Returns: A pair containing the buffer's address and capacity (in the units of sizeof(T)),
/// or a pair of 0 values if no storage can be obtained.
///
/// Note: The return value is space to hold T elements, but no T elements are constructed.
///
/// Our implementation here differs slightly in that we have alignment, alignmentOffset, and pName arguments.
/// Note that you can use the EASTL_NAME_VAL macro to make names go away in release builds.
///
/// Example usage:
/// pair<int*, ptrdiff_t> pr = get_temporary_buffer<int>(100, 0, 0, EASTL_NAME_VAL("Temp int array"));
/// memset(pr.first, 0, 100 * sizeof(int));
/// return_temporary_buffer(pr.first);
///
template <typename T>
pair<T*, ptrdiff_t> get_temporary_buffer(ptrdiff_t n, size_t alignment = 0, size_t alignmentOffset = 0, const char* pName = EASTL_TEMP_DEFAULT_NAME)
{
EASTLAllocatorType allocator(*EASTLAllocatorDefault(), pName);
return eastl::pair<T*, ptrdiff_t>(static_cast<T*>(EASTLAllocAligned(allocator, n * sizeof(T), alignment, alignmentOffset)), n);
}
/// return_temporary_buffer
///
/// From the C++ standard, section 20.4.3:
/// 3 Effects: Deallocates the buffer to which p points.
/// 4 Requires: The buffer shall have been previously allocated by get_temporary_buffer.
///
/// Note: This function merely frees space and does not destruct any T elements.
///
/// Example usage:
/// pair<int*, ptrdiff_t> pr = get_temporary_buffer<int>(300);
/// memset(pr.first, 0, 300 * sizeof(int));
/// return_temporary_buffer(pr.first, pr.second);
///
template <typename T>
void return_temporary_buffer(T* p, ptrdiff_t n = 0)
{
EASTLAllocatorType& allocator(*EASTLAllocatorDefault());
EASTLFree(allocator, p, n * sizeof(T));
}
/// uninitialized_move
///
/// uninitialized_move takes a constructed sequence of objects and an
/// uninitialized destination buffer. In the case of any exception thrown
/// while moving the objects, any newly constructed objects are guaranteed
/// to be destructed and the input left fully constructed.
///
/// In the case where you need to do multiple moves atomically, split the
/// calls into uninitialized_move_start/abort/commit.
///
/// uninitialized_move_start can possibly throw an exception. If it does,
/// you don't need to do anything. However, if it returns without throwing
/// an exception you need to guarantee that either uninitialize_move_abort
/// or uninitialized_move_commit is called.
///
/// Both uninitialize_move_abort and uninitialize_move_commit are
/// guaranteed to not throw C++ exceptions.
template <bool hasTrivialMove, typename iteratorTag>
struct uninitialized_move_impl
{
template <typename ForwardIterator, typename ForwardIteratorDest>
static ForwardIteratorDest do_move_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
#if EASTL_EXCEPTIONS_ENABLED
ForwardIteratorDest origDest(dest);
try
{
for(; first != last; ++first, ++dest)
::new(&*dest) value_type(*first);
}
catch(...)
{
for(; origDest < dest; ++origDest)
origDest->~value_type();
throw;
}
#else
for(; first != last; ++first, ++dest)
::new(&*dest) value_type(*first);
#endif
return dest;
}
template <typename ForwardIterator, typename ForwardIteratorDest>
static ForwardIteratorDest do_move_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) //throw()
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
for(; first != last; ++first, ++dest)
first->~value_type();
return dest;
}
template <typename ForwardIterator, typename ForwardIteratorDest>
static ForwardIteratorDest do_move_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest) //throw()
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
for(; first != last; ++first, ++dest)
dest->~value_type();
return dest;
}
};
template <>
struct uninitialized_move_impl<true, EASTL_ITC_NS::random_access_iterator_tag>
{
template <typename T>
static T* do_move_start(T* first, T* last, T* dest)
{
return (T*)memcpy(dest, first, (size_t)((uintptr_t)last - (uintptr_t)first)) + (last - first);
}
template <typename T>
static T* do_move_commit(T* first, T* last, T* dest)
{
return dest + (last - first);
}
template <typename T>
static T* do_move_abort(T* first, T* last, T* dest)
{
return dest + (last - first);
}
};
/// uninitialized_move_start, uninitialized_move_commit, uninitialized_move_abort
///
/// After calling uninitialized_move_start, if it doesn't throw an exception,
/// both the source and destination iterators point to undefined data. If it
/// does throw an exception, the destination remains uninitialized and the source
/// is as it was before.
///
/// In order to make the iterators valid again you need to call either uninitialized_move_abort
/// or uninitialized_move_commit. The abort call makes the original source
/// iterator valid again, and commit makes the destination valid. Both abort
/// and commit are guaranteed to not throw C++ exceptions.
///
/// Example usage:
/// iterator dest2 = uninitialized_move_start(first, last, dest);
/// try {
/// // some code here that might throw an exception
/// }
/// catch(...)
/// {
/// uninitialized_move_abort(first, last, dest);
/// throw;
/// }
/// uninitialized_move_commit(first, last, dest);
///
template <typename ForwardIterator, typename ForwardIteratorDest>
inline ForwardIteratorDest uninitialized_move_start(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
{
typedef typename eastl::iterator_traits<ForwardIterator>::iterator_category IC;
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type_input;
typedef typename eastl::iterator_traits<ForwardIteratorDest>::value_type value_type_output;
const bool bHasTrivialMove = type_and<has_trivial_relocate<value_type_input>::value,
is_pointer<ForwardIterator>::value,
is_pointer<ForwardIteratorDest>::value,
is_same<value_type_input, value_type_output>::value>::value;
return eastl::uninitialized_move_impl<bHasTrivialMove, IC>::do_move_start(first, last, dest);
}
template <typename ForwardIterator, typename ForwardIteratorDest>
inline ForwardIteratorDest uninitialized_move_commit(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
{
typedef typename eastl::iterator_traits<ForwardIterator>::iterator_category IC;
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type_input;
typedef typename eastl::iterator_traits<ForwardIteratorDest>::value_type value_type_output;
const bool bHasTrivialMove = type_and<has_trivial_relocate<value_type_input>::value,
is_pointer<ForwardIterator>::value,
is_pointer<ForwardIteratorDest>::value,
is_same<value_type_input, value_type_output>::value>::value;
return eastl::uninitialized_move_impl<bHasTrivialMove, IC>::do_move_commit(first, last, dest);
}
template <typename ForwardIterator, typename ForwardIteratorDest>
inline ForwardIteratorDest uninitialized_move_abort(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
{
typedef typename eastl::iterator_traits<ForwardIterator>::iterator_category IC;
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type_input;
typedef typename eastl::iterator_traits<ForwardIteratorDest>::value_type value_type_output;
const bool bHasTrivialMove = type_and<has_trivial_relocate<value_type_input>::value,
is_pointer<ForwardIterator>::value,
is_pointer<ForwardIteratorDest>::value,
is_same<value_type_input, value_type_output>::value>::value;
return eastl::uninitialized_move_impl<bHasTrivialMove, IC>::do_move_abort(first, last, dest);
}
/// uninitialized_move
///
/// uninitialized_move takes a constructed sequence of objects and an
/// uninitialized destination buffer. In the case of any exception thrown
/// while moving the objects, any newly constructed objects are guaranteed
/// to be destructed and the input left as it was before.
///
template <typename ForwardIterator, typename ForwardIteratorDest>
inline ForwardIteratorDest uninitialized_move(ForwardIterator first, ForwardIterator last, ForwardIteratorDest dest)
{
ForwardIteratorDest result = uninitialized_move_start(first, last, dest);
uninitialized_move_commit(first, last, dest);
return result;
}
// uninitialized_copy
//
template <typename InputIterator, typename ForwardIterator>
inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, true_type)
{
return eastl::copy(first, last, dest); // The copy() in turn will use memcpy for POD types.
}
template <typename InputIterator, typename ForwardIterator>
inline ForwardIterator uninitialized_copy_impl(InputIterator first, InputIterator last, ForwardIterator dest, false_type)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
ForwardIterator currentDest(dest);
#if EASTL_EXCEPTIONS_ENABLED
try
{
for(; first != last; ++first, ++currentDest)
::new(&*currentDest) value_type(*first);
}
catch(...)
{
for(; dest < currentDest; ++dest)
dest->~value_type();
throw;
}
#else
for(; first != last; ++first, ++currentDest)
::new(&*currentDest) value_type(*first);
#endif
return currentDest;
}
/// uninitialized_copy
///
/// Copies a source range to a destination, copy-constructing the destination with
/// the source values (and not *assigning* the destination with the source values).
/// Returns the end of the destination range (i.e. dest + (last - first)).
///
/// Declaration:
/// template <typename InputIterator, typename ForwardIterator>
/// ForwardIterator uninitialized_copy(InputIterator sourceFirst, InputIterator sourceLast, ForwardIterator destination);
///
/// Example usage:
/// SomeClass* pArray = malloc(10 * sizeof(SomeClass));
/// uninitialized_copy(pSourceDataBegin, pSourceDataBegin + 10, pArray);
///
template <typename InputIterator, typename ForwardIterator>
inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
// Note: has_trivial_assign isn't actually the right thing to use here, as it
// refers to assignment as opposed to construction. Bug Paul Pedriana if this
// is becoming a problem. In the meantime, this code assumes that if has_trivial_assign
// is present for a type, then has_trivial_copy is as well.
return uninitialized_copy_impl(first, last, result, has_trivial_assign<value_type>());
}
/// uninitialized_copy_ptr
///
/// This is a specialization of uninitialized_copy for iterators that are pointers.
/// It exists so that we can declare a value_type for the iterator, which you
/// can't do with a pointer by itself.
///
template <typename First, typename Last, typename Result>
inline Result uninitialized_copy_ptr(First first, Last last, Result result)
{
typedef typename eastl::iterator_traits<generic_iterator<Result, void> >::value_type value_type;
const generic_iterator<Result, void> i(uninitialized_copy_impl(generic_iterator<First, void>(first),
generic_iterator<Last, void>(last),
generic_iterator<Result, void>(result),
has_trivial_assign<value_type>()));
return i.base();
}
// uninitialized_fill
//
template <typename ForwardIterator, typename T>
inline void uninitialized_fill_impl(ForwardIterator first, ForwardIterator last, const T& value, true_type)
{
eastl::fill(first, last, value);
}
template <typename ForwardIterator, typename T>
void uninitialized_fill_impl(ForwardIterator first, ForwardIterator last, const T& value, false_type)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
ForwardIterator currentDest(first);
#if EASTL_EXCEPTIONS_ENABLED
try
{
for(; currentDest != last; ++currentDest)
::new(&*currentDest) value_type(value);
}
catch(...)
{
for(; first < currentDest; ++first)
first->~value_type();
throw;
}
#else
for(; currentDest != last; ++currentDest)
::new(&*currentDest) value_type(value);
#endif
}
/// uninitialized_fill
///
/// Copy-constructs the elements in the destination range with the given input value.
/// Returns void. It wouldn't be useful to return the end of the destination range,
/// as that is the same as the 'last' input parameter.
///
/// Declaration:
/// template <typename ForwardIterator, typename T>
/// void uninitialized_fill(ForwardIterator destinationFirst, ForwardIterator destinationLast, const T& value);
///
template <typename ForwardIterator, typename T>
inline void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& value)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
uninitialized_fill_impl(first, last, value, has_trivial_assign<value_type>());
}
/// uninitialized_fill_ptr
///
/// This is a specialization of uninitialized_fill for iterators that are pointers.
/// It exists so that we can declare a value_type for the iterator, which you
/// can't do with a pointer by itself.
///
template <typename T>
inline void uninitialized_fill_ptr(T* first, T* last, const T& value)
{
typedef typename eastl::iterator_traits<generic_iterator<T*, void> >::value_type value_type;
uninitialized_fill_impl(generic_iterator<T*, void>(first), generic_iterator<T*, void>(last), value, has_trivial_assign<value_type>());
}
// uninitialized_fill_n
//
template <typename ForwardIterator, typename Count, typename T>
inline void uninitialized_fill_n_impl(ForwardIterator first, Count n, const T& value, true_type)
{
eastl::fill_n(first, n, value);
}
template <typename ForwardIterator, typename Count, typename T>
void uninitialized_fill_n_impl(ForwardIterator first, Count n, const T& value, false_type)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
ForwardIterator currentDest(first);
#if EASTL_EXCEPTIONS_ENABLED
try
{
for(; n > 0; --n, ++currentDest)
::new(&*currentDest) value_type(value);
}
catch(...)
{
for(; first < currentDest; ++first)
first->~value_type();
throw;
}
#else
for(; n > 0; --n, ++currentDest)
::new(&*currentDest) value_type(value);
#endif
}
/// uninitialized_fill_n
///
/// Copy-constructs the range of [first, first + n) with the given input value.
/// Returns void as per the C++ standard, though returning the end input iterator
/// value may be of use.
///
/// Declaration:
/// template <typename ForwardIterator, typename Count, typename T>
/// void uninitialized_fill_n(ForwardIterator destination, Count n, const T& value);
///
template <typename ForwardIterator, typename Count, typename T>
inline void uninitialized_fill_n(ForwardIterator first, Count n, const T& value)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
uninitialized_fill_n_impl(first, n, value, has_trivial_assign<value_type>());
}
/// uninitialized_fill_n_ptr
///
/// This is a specialization of uninitialized_fill_n for iterators that are pointers.
/// It exists so that we can declare a value_type for the iterator, which you
/// can't do with a pointer by itself.
///
template <typename T, typename Count>
inline void uninitialized_fill_n_ptr(T* first, Count n, const T& value)
{
typedef typename eastl::iterator_traits<generic_iterator<T*, void> >::value_type value_type;
uninitialized_fill_n_impl(generic_iterator<T*, void>(first), n, value, has_trivial_assign<value_type>());
}
/// uninitialized_copy_fill
///
/// Copies [first1, last1) into [first2, first2 + (last1 - first1)) then
/// fills [first2 + (last1 - first1), last2) with value.
///
template <typename InputIterator, typename ForwardIterator, typename T>
inline void uninitialized_copy_fill(InputIterator first1, InputIterator last1,
ForwardIterator first2, ForwardIterator last2, const T& value)
{
const ForwardIterator mid(eastl::uninitialized_copy(first1, last1, first2));
#if EASTL_EXCEPTIONS_ENABLED
try
{
#endif
eastl::uninitialized_fill(mid, last2, value);
#if EASTL_EXCEPTIONS_ENABLED
}
catch(...)
{
for(; first2 < mid; ++first2)
first2->~value_type();
throw;
}
#endif
}
/// uninitialized_fill_copy
///
/// Fills [result, mid) with value then copies [first, last) into [mid, mid + (last - first)).
///
template <typename ForwardIterator, typename T, typename InputIterator>
inline ForwardIterator
uninitialized_fill_copy(ForwardIterator result, ForwardIterator mid, const T& value, InputIterator first, InputIterator last)
{
eastl::uninitialized_fill(result, mid, value);
#if EASTL_EXCEPTIONS_ENABLED
try
{
#endif
return eastl::uninitialized_copy(first, last, mid);
#if EASTL_EXCEPTIONS_ENABLED
}
catch(...)
{
for(; result < mid; ++result)
result->~value_type();
throw;
}
#endif
}
/// uninitialized_copy_copy
///
/// Copies [first1, last1) into [result, result + (last1 - first1)) then
/// copies [first2, last2) into [result, result + (last1 - first1) + (last2 - first2)).
///
template <typename InputIterator1, typename InputIterator2, typename ForwardIterator>
inline ForwardIterator
uninitialized_copy_copy(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2,
ForwardIterator result)
{
const ForwardIterator mid(eastl::uninitialized_copy(first1, last1, result));
#if EASTL_EXCEPTIONS_ENABLED
try
{
#endif
return eastl::uninitialized_copy(first2, last2, mid);
#if EASTL_EXCEPTIONS_ENABLED
}
catch(...)
{
for(; result < mid; ++result)
result->~value_type();
throw;
}
#endif
}
/// destruct
///
/// Calls the destructor of a given object.
///
/// Note that we don't have a specialized version of this for objects
/// with trivial destructors, such as integers. This is because the
/// compiler can already see in our version here that the destructor
/// is a no-op.
///
template <typename T>
inline void destruct(T* p)
{
p->~T();
}
// destruct(first, last)
//
template <typename ForwardIterator>
inline void destruct_impl(ForwardIterator /*first*/, ForwardIterator /*last*/, true_type) // true means the type has a trivial destructor.
{
// Empty. The type has a trivial destructor.
}
template <typename ForwardIterator>
inline void destruct_impl(ForwardIterator first, ForwardIterator last, false_type) // false means the type has a significant destructor.
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
for(; first != last; ++first)
(*first).~value_type();
}
/// destruct
///
/// Calls the destructor on a range of objects.
///
/// We have a specialization for objects with trivial destructors, such as
/// PODs. In this specialization the destruction of the range is a no-op.
///
template <typename ForwardIterator>
inline void destruct(ForwardIterator first, ForwardIterator last)
{
typedef typename eastl::iterator_traits<ForwardIterator>::value_type value_type;
destruct_impl(first, last, eastl::has_trivial_destructor<value_type>());
}
} // namespace eastl
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // Header include guard