//
// LDASTools AL - A library collection to provide an abstraction layer
//
// Copyright (C) 2018 California Institute of Technology
//
// LDASTools AL is free software; you may redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 (GPLv2) of the
// License or at your discretion, any later version.
//
// LDASTools AL is distributed in the hope that it will be useful, but
// without any warranty or even the implied warranty of merchantability
// or fitness for a particular purpose. See the GNU General Public
// License (GPLv2) for more details.
//
// Neither the names of the California Institute of Technology (Caltech),
// The Massachusetts Institute of Technology (M.I.T), The Laser
// Interferometer Gravitational-Wave Observatory (LIGO), nor the names
// of its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// You should have received a copy of the licensing terms for this
// software included in the file LICENSE located in the top-level
// directory of this package. If you did not, you can view a copy at
// http://dcc.ligo.org/M1500244/LICENSE
//

#ifndef LDASTOOLSAL__MALLOC_ALLOCATOR_HH
#define LDASTOOLSAL__MALLOC_ALLOCATOR_HH
//---------------------------------------------------------------------
// This code is derived from:
//  http://www.drdobbs.com/the-standard-librarian-what-are-allocato/184403759?pgno=1
//
//---------------------------------------------------------------------
template < class T >
class malloc_allocator
{
public:
    typedef T                 value_type;
    typedef value_type*       pointer;
    typedef const value_type* const_pointer;
    typedef value_type&       reference;
    typedef const value_type& const_reference;
    typedef std::size_t       size_type;
    typedef std::ptrdiff_t    difference_type;

    template < class U >
    struct rebind
    {
        typedef malloc_allocator< U > other;
    };

    malloc_allocator( )
    {
    }
    malloc_allocator( const malloc_allocator& )
    {
    }

    template < class U >
    malloc_allocator( const malloc_allocator< U >& )
    {
    }

    ~malloc_allocator( )
    {
    }

    pointer
    address( reference x ) const
    {
        return &x;
    }

    const_pointer
    address( const_reference x ) const
    {
        return x;
    }

    pointer
    allocate( size_type n, const_pointer = 0 )
    {
        void* p = std::malloc( n * sizeof( T ) );
        if ( !p )
            throw std::bad_alloc( );
        return static_cast< pointer >( p );
    }

    void
    deallocate( pointer p, size_type )
    {
        std::free( p );
    }

    size_type
    max_size( ) const
    {
        return static_cast< size_type >( -1 ) / sizeof( T );
    }

    void
    construct( pointer p, const value_type& x )
    {
        new ( p ) value_type( x );
    }

    void
    destroy( pointer p )
    {
        p->~value_type( );
    }

private:
    void operator=( const malloc_allocator& );
};

template <>
class malloc_allocator< void >
{
    typedef void        value_type;
    typedef void*       pointer;
    typedef const void* const_pointer;

    template < class U >
    struct rebind
    {
        typedef malloc_allocator< U > other;
    };
};
#endif /* LDASTOOLSAL__MALLOC_ALLOCATOR_HH */
