You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
concurrentqueue/benchmarks/dlib/std_allocator.h

200 lines
6.8 KiB
C++

// Copyright (C) 2007 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_STD_ALLOc_H_
#define DLIB_STD_ALLOc_H_
#include <limits>
#include <memory>
#include "enable_if.h"
#include "algs.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename T,
typename M
>
class std_allocator
{
/*!
REQUIREMENTS ON M
must be an implementation of memory_manager/memory_manager_kernel_abstract.h or
must be an implementation of memory_manager_global/memory_manager_global_kernel_abstract.h or
must be an implementation of memory_manager_stateless/memory_manager_stateless_kernel_abstract.h
M::type can be set to anything.
WHAT THIS OBJECT REPRESENTS
This object is an implementation of an allocator that conforms to the C++ standard
requirements for allocator objects. The M template argument is one of the dlib
memory manager objects and this allocator implementation will do all of its memory allocations
using whatever dlib memory manager you supply.
Thus, using this allocator object you can use any of the dlib memory manager objects with
the containers in the STL or with any other object that requires a C++ allocator object.
It is important to note that many STL implementations make the assumption that the memory
allocated by one allocator can be freed by another. This effectively means that you should
only use a global or stateless memory manager with the std_allocator. Either that or you
have to verify that your version of the STL isn't going to try and allocate and deallocate
memory with different allocators.
!*/
public:
//type definitions
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
//rebind std_allocator to type U
template <typename U>
struct rebind {
typedef std_allocator<U,M> other;
};
//return address of values
pointer address (reference value) const { return &value; }
const_pointer address (const_reference value) const { return &value; }
/*constructors and destructor
*-nothing to do because the std_allocator has no state
*/
std_allocator() throw() { }
std_allocator(const std_allocator&) throw() { }
template <typename U>
std_allocator (const std_allocator<U,M>&) throw() { }
~std_allocator() throw() { }
//return maximum number of elements that can be allocated
size_type max_size () const throw()
{
//for numeric_limits see Section 4.3, page 59
return std::numeric_limits<size_t>::max() / sizeof(T);
}
//allocate but don't initialize num elements of type T
pointer allocate (
size_type num,
typename std_allocator<void,M>::const_pointer = 0
)
{
return (pointer) pool.allocate_array(num*sizeof(T));
}
// This function is not required by the C++ standard but some versions of the STL
// distributed with gcc erroneously require it. See the bug report for further
// details: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51626
void construct(pointer p) { return construct(p, value_type()); }
//initialize elements of allocated storage p with value value
void construct (pointer p, const T& value)
{
//initialize memory with placement new
new((void*)p)T(value);
}
//destroy elements of initialized storage p
void destroy (pointer p)
{
// destroy objects by calling their destructor
p->~T();
}
//deallocate storage p of deleted elements
void deallocate (pointer p, size_type )
{
pool.deallocate_array((char*)p);
}
void swap (
std_allocator& item
)
{
pool.swap(item.pool);
}
std_allocator& operator= (const std_allocator&) { return *this;}
private:
typename M::template rebind<char>::other pool;
};
// ----------------------------------------------------------------------------------------
template <
typename M
>
class std_allocator<void,M>
{
public:
//type definitions
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
//rebind std_allocator to type U
template <typename U>
struct rebind {
typedef std_allocator<U,M> other;
};
};
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2, typename enabled = void>
struct std_alloc_compare
{ const static bool are_interchangeable = false; };
template <typename M1, typename M2>
struct std_alloc_compare<M1,M2,typename enable_if<is_same_type<typename M1::mm_global_type, typename M2::mm_global_type> >::type>
{ const static bool are_interchangeable = true; };
template <typename M>
struct std_alloc_compare<M,M,typename enable_if_c<M::is_stateless>::type>
{ const static bool are_interchangeable = true; };
//return that all specializations of this std_allocator are interchangeable if they use memory_manager_global
// instances with the same mm_global_type
template <typename T1, typename M1, typename T2, typename M2>
bool operator== (
const std_allocator<T1,M1>&,
const std_allocator<T2,M2>&
) throw()
{ return std_alloc_compare<M1,M2>::are_interchangeable; }
template <typename T1, typename M1, typename T2, typename M2>
bool operator!= (
const std_allocator<T1,M1>&,
const std_allocator<T2,M2>&
) throw()
{ return !std_alloc_compare<M1,M2>::are_interchangeable; }
// ----------------------------------------------------------------------------------------
template <typename T, typename M>
void swap (
std_allocator<T,M>& a,
std_allocator<T,M>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_STD_ALLOc_H_