I tried to write my own allocator that relies on VirtualAlloc() or
mmap(). But it doesn't work for the above reason; i.e. the allocator
might get rebound and the new allocator might be used for tiny amounts
of memory, rounded up to a page-size.
#ifdef _MSC_VER
#include <Windows.h>
#elif __unix__
#include <sys/mman.h>
#endif
#include <cstddef>
#include <exception>
#include <cassert>
#include <new>
#include <iostream>
template<class T>
class virtual_allocator
{
public:
typedef T value_type;
#if __cplusplus < 201703L
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
#endif
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
#if __cplusplus < 201703L
template<typename U>
struct rebind
{
typedef virtual_allocator<U> other;
};
#endif
explicit virtual_allocator() = default;
explicit virtual_allocator( virtual_allocator const
&other ) = default;
template<typename U>
virtual_allocator( virtual_allocator<U> const
&other );
#if __cplusplus < 201703L
static pointer address( reference value );
static const_pointer address( const_reference value );
static size_type max_size() throw();
#endif
#if __cplusplus >= 201703L
T *allocate( size_type n, void *hint = nullptr );
void deallocate( T *p, size_type num = 1 );
#else
pointer allocate( size_type n, void *hint = nullptr );
void deallocate( pointer p, size_type num = 1 );
#endif
#if __cplusplus < 201703L
static void construct( pointer p, const T&value );
template<typename U>
static void destroy( U *p );
#endif
};
template<typename T>
template<typename U>
inline
virtual_allocator<T>::virtual_allocator( virtual_allocator<U> const
&other ) :
virtual_allocator()
{
}
#if __cplusplus < 201703L
template<typename T>
inline
typename virtual_allocator<T>::pointer virtual_allocator<T>::address(
reference value )
{
return &value;
}
template<typename T>
inline
typename virtual_allocator<T>::const_pointer
virtual_allocator<T>::address( const_reference value )
{
return &value;
}
template<typename T>
inline
typename virtual_allocator<T>::size_type
virtual_allocator<T>::max_size() throw()
{
return (size_t)(ptrdiff_t)-1 / sizeof(T);
}
#endif
template<typename T>
#if __cplusplus >= 201703L
T *virtual_allocator<T>::allocate( size_type n, void *hint )
#else
typename virtual_allocator<T>::pointer virtual_allocator<T>::allocate(
size_type n, void *hint )
#endif
{
std::cout << "allocate" << n << std::endl;
#if defined(_MSC_VER)
T *p = (T *)VirtualAlloc( hint, n * sizeof(T), MEM_RESERVE |
MEM_COMMIT, PAGE_READWRITE );
if( !p )
throw std::bad_alloc();
return p;
#elif __unix__
void *p = mmap( hint, n * sizeof(T), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0 );
if( p == MAP_FAILED )
throw std::bad_alloc();
return (pointer)p;
#else
#error no implementation for your OS
#endif
}
template<typename T>
#if __cplusplus >= 201703L
inline
void virtual_allocator<T>::deallocate( T *p, size_type n )
#else
inline
void virtual_allocator<T>::deallocate( pointer p, size_type n )
#endif
{
std::cout << "dellocate " << n << std::endl;
#if defined(_MSC_VER)
BOOL ret = VirtualFree( p, 0, MEM_RELEASE );
assert(ret);
#elif __unix__
int ret = munmap( p, n * sizeof(T) );
assert(ret == 0);
#else
#error no implementation for your OS
#endif
}
#if __cplusplus < 201703L
template<typename T>
inline
void virtual_allocator<T>::construct( pointer p, const T&value )
{
new( (void*)p ) T( value );
}
template<typename T>
template<typename U>
inline
void virtual_allocator<T>::destroy( U *p )
{
p->~T();
}
#endif