diff options
Diffstat (limited to 'src/third-party/ArenaAlloc')
-rw-r--r-- | src/third-party/ArenaAlloc/arenaalloc.h | 192 | ||||
-rw-r--r-- | src/third-party/ArenaAlloc/arenaallocimpl.h | 465 |
2 files changed, 330 insertions, 327 deletions
diff --git a/src/third-party/ArenaAlloc/arenaalloc.h b/src/third-party/ArenaAlloc/arenaalloc.h index dfd648d..fab4de0 100644 --- a/src/third-party/ArenaAlloc/arenaalloc.h +++ b/src/third-party/ArenaAlloc/arenaalloc.h @@ -1,11 +1,11 @@ // -*- c++ -*- /****************************************************************************** * arenaalloc.h - * + * * Arena allocator based on the example logic provided by Nicolai Josuttis * and available at http://www.josuttis.com/libbook/examples.html. * This enhanced work is provided under the terms of the MIT license. - * + * *****************************************************************************/ #ifndef _ARENA_ALLOC_H @@ -15,43 +15,40 @@ #include <memory> #if __cplusplus >= 201103L -#include <type_traits> -#include <utility> +# include <type_traits> +# include <utility> #endif // Define macro ARENA_ALLOC_DEBUG to enable some tracing of the allocator #include "arenaallocimpl.h" -namespace ArenaAlloc -{ - - struct _newAllocatorImpl - { +namespace ArenaAlloc { + +struct _newAllocatorImpl { // these two functions should be supported by a specialized // allocator for shared memory or another source of specialized // memory such as device mapped memory. - void* allocate( size_t numBytes ) { return new char[ numBytes ]; } - void deallocate( void* ptr ) { delete[]( (char*)ptr ); } - }; - - template <class T, - class AllocatorImpl = _newAllocatorImpl, - class MemblockImpl = _memblockimpl<AllocatorImpl> > - class Alloc { - - private: - MemblockImpl* m_impl; - - public: + void* allocate(size_t numBytes) { return new char[numBytes]; } + void deallocate(void* ptr) { delete[] ((char*) ptr); } +}; + +template<class T, + class AllocatorImpl = _newAllocatorImpl, + class MemblockImpl = _memblockimpl<AllocatorImpl> > +class Alloc { +private: + MemblockImpl* m_impl; + +public: // type definitions - typedef T value_type; - typedef T* pointer; + typedef T value_type; + typedef T* pointer; typedef const T* const_pointer; - typedef T& reference; + typedef T& reference; typedef const T& const_reference; - typedef std::size_t size_type; + typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; - + #if __cplusplus >= 201103L // when containers are swapped, (i.e. vector.swap) // swap the allocators also. This was not specified in c++98 @@ -64,123 +61,110 @@ namespace ArenaAlloc typedef std::true_type propagate_on_container_swap; // container moves should move the allocator also. - typedef std::true_type propagate_on_container_move_assignment; + typedef std::true_type propagate_on_container_move_assignment; #endif - + // rebind allocator to type U - template <class U> + template<class U> struct rebind { - typedef Alloc<U,AllocatorImpl,MemblockImpl> other; + typedef Alloc<U, AllocatorImpl, MemblockImpl> other; }; - + // return address of values - pointer address (reference value) const { - return &value; - } - const_pointer address (const_reference value) const { - return &value; - } + pointer address(reference value) const { return &value; } + const_pointer address(const_reference value) const { return &value; } - Alloc( std::size_t defaultSize = 32768, AllocatorImpl allocImpl = AllocatorImpl() ) throw(): - m_impl( MemblockImpl::create( defaultSize, allocImpl ) ) - { - } - - Alloc(const Alloc& src) throw(): - m_impl( src.m_impl ) + Alloc(std::size_t defaultSize = 32768, + AllocatorImpl allocImpl = AllocatorImpl()) throw() + : m_impl(MemblockImpl::create(defaultSize, allocImpl)) { - m_impl->incrementRefCount(); } - - template <class U> - Alloc (const Alloc<U,AllocatorImpl,MemblockImpl>& src) throw(): - m_impl( 0 ) + + Alloc(const Alloc& src) throw() : m_impl(src.m_impl) { - MemblockImpl::assign( src, m_impl ); - m_impl->incrementRefCount(); + m_impl->incrementRefCount(); } - - ~Alloc() throw() + + template<class U> + Alloc(const Alloc<U, AllocatorImpl, MemblockImpl>& src) throw() : m_impl(0) { - m_impl->decrementRefCount(); + MemblockImpl::assign(src, m_impl); + m_impl->incrementRefCount(); } + ~Alloc() throw() { m_impl->decrementRefCount(); } + // return maximum number of elements that can be allocated - size_type max_size () const throw() + size_type max_size() const throw() { - return std::numeric_limits<std::size_t>::max() / sizeof(T); + return std::numeric_limits<std::size_t>::max() / sizeof(T); } + void reset() { m_impl->reset(); } + // allocate but don't initialize num elements of type T - pointer allocate (size_type num, const void* = 0) + pointer allocate(size_type num, const void* = 0) { - return reinterpret_cast<pointer>( m_impl->allocate(num*sizeof(T)) ); + return reinterpret_cast<pointer>(m_impl->allocate(num * sizeof(T))); } // initialize elements of allocated storage p with value value #if __cplusplus >= 201103L - // use c++11 style forwarding to construct the object - template< typename P, typename... Args> - void construct( P* obj, Args&&... args ) + // use c++11 style forwarding to construct the object + template<typename P, typename... Args> + void construct(P* obj, Args&&... args) { - ::new((void*) obj ) P( std::forward<Args>( args )... ); + ::new ((void*) obj) P(std::forward<Args>(args)...); } - template< typename P > - void destroy( P* obj ) { obj->~P(); } - -#else - void construct (pointer p, const T& value) + template<typename P> + void destroy(P* obj) { - new((void*)p)T(value); + obj->~P(); } - void destroy (pointer p) { p->~T(); } + +#else + void construct(pointer p, const T& value) { new ((void*) p) T(value); } + void destroy(pointer p) { p->~T(); } #endif // deallocate storage p of deleted elements - void deallocate (pointer p, size_type num) - { - m_impl->deallocate( p ); - } - - bool equals( const MemblockImpl * impl ) const - { - return impl == m_impl; - } - - bool operator == ( const Alloc& t2 ) const - { - return m_impl == t2.m_impl; - } - + void deallocate(pointer p, size_type num) { m_impl->deallocate(p); } + + bool equals(const MemblockImpl* impl) const { return impl == m_impl; } + + bool operator==(const Alloc& t2) const { return m_impl == t2.m_impl; } + friend MemblockImpl; - - template< typename Other > - bool operator == ( const Alloc< Other, AllocatorImpl, MemblockImpl >& t2 ) + + template<typename Other> + bool operator==(const Alloc<Other, AllocatorImpl, MemblockImpl>& t2) { - return t2.equals( m_impl ); + return t2.equals(m_impl); } - - template< typename Other > - bool operator != ( const Alloc< Other, AllocatorImpl, MemblockImpl >& t2 ) + + template<typename Other> + bool operator!=(const Alloc<Other, AllocatorImpl, MemblockImpl>& t2) { - return !t2.equals( m_impl ); + return !t2.equals(m_impl); } - + // These are extension functions not required for an stl allocator size_t getNumAllocations() { return m_impl->getNumAllocations(); } size_t getNumDeallocations() { return m_impl->getNumDeallocations(); } - size_t getNumBytesAllocated() { return m_impl->getNumBytesAllocated(); } - }; - - template<typename A> - template<typename T> - void _memblockimpl<A>::assign( const Alloc<T,A, _memblockimpl<A> >& src, _memblockimpl<A> *& dest ) - { - dest = const_cast<_memblockimpl<A>* >(src.m_impl); - } - + size_t getNumBytesAllocated() { return m_impl->getNumBytesAllocated(); } +}; + +template<typename A> +template<typename T> +void +_memblockimpl<A>::assign(const Alloc<T, A, _memblockimpl<A> >& src, + _memblockimpl<A>*& dest) +{ + dest = const_cast<_memblockimpl<A>*>(src.m_impl); } +} // namespace ArenaAlloc + #endif diff --git a/src/third-party/ArenaAlloc/arenaallocimpl.h b/src/third-party/ArenaAlloc/arenaallocimpl.h index 879e0d2..39b9a17 100644 --- a/src/third-party/ArenaAlloc/arenaallocimpl.h +++ b/src/third-party/ArenaAlloc/arenaallocimpl.h @@ -1,7 +1,7 @@ // -*- c++ -*- /****************************************************************************** ** arenaallocimpl.h - ** + ** ** Internal implementation types of the arena allocator ** MIT license *****************************************************************************/ @@ -10,281 +10,300 @@ #define _ARENA_ALLOC_IMPL_H #ifdef ARENA_ALLOC_DEBUG -#include <stdio.h> +# include <stdio.h> #endif #include <stdint.h> -namespace ArenaAlloc -{ +namespace ArenaAlloc { - template< typename T, typename A, typename M > - class Alloc; - - // internal structure for tracking memory blocks - template < typename AllocImpl > - struct _memblock - { +template<typename T, typename A, typename M> +class Alloc; + +// internal structure for tracking memory blocks +template<typename AllocImpl> +struct _memblock { // allocations are rounded up to a multiple of the size of this - // struct to maintain proper alignment for any pointer and double - // values stored in the allocation. - // A future goal is to support even stricter alignment for example - // to support cache alignment, special device dependent mappings, - // or GPU ops. - union _roundsize { - double d; - void* p; - }; - - _memblock* m_next{nullptr}; // blocks kept link listed for cleanup at end - std::size_t m_bufferSize; // size of the buffer - std::size_t m_index; // index of next allocatable byte in the block - char* m_buffer; // pointer to large block to allocate from - - _memblock(std::size_t bufferSize, AllocImpl& allocImpl) - : m_bufferSize(roundSize(bufferSize)), m_index(0), - m_buffer(reinterpret_cast<char*>(allocImpl.allocate( - bufferSize))) // this works b/c of order of decl - { - } - - std::size_t roundSize( std::size_t numBytes ) + // struct to maintain proper alignment for any pointer and double + // values stored in the allocation. + // A future goal is to support even stricter alignment for example + // to support cache alignment, special device dependent mappings, + // or GPU ops. + union _roundsize { + double d; + void* p; + }; + + _memblock* m_next{nullptr}; // blocks kept link listed for cleanup at end + std::size_t m_bufferSize; // size of the buffer + std::size_t m_index; // index of next allocatable byte in the block + char* m_buffer; // pointer to large block to allocate from + + _memblock(std::size_t bufferSize, AllocImpl& allocImpl) + : m_bufferSize(roundSize(bufferSize)), m_index(0), + m_buffer(reinterpret_cast<char*>(allocImpl.allocate( + bufferSize))) // this works b/c of order of decl { - // this is subject to overflow. calling logic should not permit - // an attempt to allocate a really massive size. - // i.e. an attempt to allocate 10s of terabytes should be an error - return ( ( numBytes + sizeof( _roundsize ) - 1 ) / - sizeof( _roundsize ) ) * sizeof( _roundsize ); } - char * allocate( std::size_t numBytes ) + std::size_t roundSize(std::size_t numBytes) { - std::size_t roundedSize = roundSize( numBytes ); - if( roundedSize + m_index > m_bufferSize ) - return 0; - - char * ptrToReturn = &m_buffer[ m_index ]; - m_index += roundedSize; - return ptrToReturn; + // this is subject to overflow. calling logic should not permit + // an attempt to allocate a really massive size. + // i.e. an attempt to allocate 10s of terabytes should be an error + return ((numBytes + sizeof(_roundsize) - 1) / sizeof(_roundsize)) + * sizeof(_roundsize); } - - void dispose( AllocImpl& impl ) + + char* allocate(std::size_t numBytes) { - impl.deallocate( m_buffer ); + std::size_t roundedSize = roundSize(numBytes); + if (roundedSize + m_index > m_bufferSize) + return 0; + + char* ptrToReturn = &m_buffer[m_index]; + m_index += roundedSize; + return ptrToReturn; } - ~_memblock() - { - } - }; - - template< typename AllocatorImpl, typename Derived > - struct _memblockimplbase - { + void reset() { this->m_index = 0; } + + void dispose(AllocImpl& impl) { impl.deallocate(m_buffer); } + + ~_memblock() {} +}; + +template<typename AllocatorImpl, typename Derived> +struct _memblockimplbase { AllocatorImpl m_alloc; - std::size_t m_refCount; // when refs -> 0 delete this + std::size_t m_refCount; // when refs -> 0 delete this std::size_t m_defaultSize; - - std::size_t m_numAllocate; // number of times allocate called - std::size_t m_numDeallocate; // number of time deallocate called - std::size_t m_numBytesAllocated; // A good estimate of amount of space used - - _memblock<AllocatorImpl> * m_head; - _memblock<AllocatorImpl> * m_current; + + std::size_t m_numAllocate; // number of times allocate called + std::size_t m_numDeallocate; // number of time deallocate called + std::size_t m_numBytesAllocated; // A good estimate of amount of space used + + _memblock<AllocatorImpl>* m_head; + _memblock<AllocatorImpl>* m_current; // round up 2 next power of 2 if not already // a power of 2 - std::size_t roundpow2( std::size_t value ) + std::size_t roundpow2(std::size_t value) { - // note this works because subtracting 1 is equivalent to - // inverting the lowest set bit and complementing any - // bits lower than that. only a power of 2 - // will yield 0 in the following check - if( 0 == ( value & ( value - 1 ) ) ) - return value; // already a power of 2 - - // fold t over itself. This will set all bits after the highest set bit of t to 1 - // who said bit twiddling wasn't practical? - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; + // note this works because subtracting 1 is equivalent to + // inverting the lowest set bit and complementing any + // bits lower than that. only a power of 2 + // will yield 0 in the following check + if (0 == (value & (value - 1))) + return value; // already a power of 2 + + // fold t over itself. This will set all bits after the highest set bit + // of t to 1 who said bit twiddling wasn't practical? + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; #if SIZE_MAX > UINT32_MAX - value |= value >> 32; + value |= value >> 32; #endif - return value + 1; + return value + 1; } - _memblockimplbase( std::size_t defaultSize, AllocatorImpl& allocator ): - m_alloc( allocator ), - m_refCount( 1 ), - m_defaultSize( defaultSize ), - m_numAllocate( 0 ), - m_numDeallocate( 0 ), - m_numBytesAllocated( 0 ), - m_head( 0 ), - m_current( 0 ) - { - if( m_defaultSize < 256 ) - { - m_defaultSize = 256; // anything less is academic. a more practical size is 4k or more - } - else if ( m_defaultSize > 1024UL*1024*1024*16 ) - { - // when this becomes a problem, this package has succeeded beyond my wildest expectations - m_defaultSize = 1024UL*1024*1024*16; - } - - // for convenience block size should be a power of 2 - // round up to next power of 2 - m_defaultSize = roundpow2( m_defaultSize ); - allocateNewBlock( m_defaultSize ); + _memblockimplbase(std::size_t defaultSize, AllocatorImpl& allocator) + : m_alloc(allocator), m_refCount(1), m_defaultSize(defaultSize), + m_numAllocate(0), m_numDeallocate(0), m_numBytesAllocated(0), + m_head(0), m_current(0) + { + if (m_defaultSize < 256) { + m_defaultSize = 256; // anything less is academic. a more practical + // size is 4k or more + } else if (m_defaultSize > 1024UL * 1024 * 1024 * 16) { + // when this becomes a problem, this package has succeeded beyond my + // wildest expectations + m_defaultSize = 1024UL * 1024 * 1024 * 16; + } + + // for convenience block size should be a power of 2 + // round up to next power of 2 + m_defaultSize = roundpow2(m_defaultSize); + allocateNewBlock(m_defaultSize); } - - char * allocate( std::size_t numBytes ) + + char* allocate(std::size_t numBytes) { - char * ptrToReturn = m_current->allocate( numBytes ); - if( !ptrToReturn ) - { - allocateNewBlock( numBytes > m_defaultSize / 2 ? roundpow2( numBytes*2 ) : - m_defaultSize ); - - ptrToReturn = m_current->allocate( numBytes ); - } - + char* ptrToReturn = m_current->allocate(numBytes); + if (!ptrToReturn) { + allocateNewBlock(numBytes > m_defaultSize / 2 + ? roundpow2(numBytes * 2) + : m_defaultSize); + + ptrToReturn = m_current->allocate(numBytes); + } + #ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "_memblockimpl=%p allocated %ld bytes at address=%p\n", this, numBytes, ptrToReturn ); + fprintf(stdout, + "_memblockimpl=%p allocated %ld bytes at address=%p\n", + this, + numBytes, + ptrToReturn); #endif - ++ m_numAllocate; - m_numBytesAllocated += numBytes; // does not account for the small overhead in tracking the allocation - - return ptrToReturn; + ++m_numAllocate; + m_numBytesAllocated += numBytes; // does not account for the small + // overhead in tracking the allocation + + return ptrToReturn; } - - void allocateNewBlock( std::size_t blockSize ) - { - _memblock<AllocatorImpl> * newBlock = new ( m_alloc.allocate( sizeof( _memblock<AllocatorImpl> ) ) ) - _memblock<AllocatorImpl>( blockSize, m_alloc ); - -#ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "_memblockimplbase=%p allocating a new block of size=%ld\n", this, blockSize ); -#endif - - if( m_head == 0 ) - { - m_head = m_current = newBlock; - } - else - { - m_current->m_next = newBlock; - m_current = newBlock; - } - } - - void deallocate( void * ptr ) + + void allocateNewBlock(std::size_t blockSize) { - ++ m_numDeallocate; + _memblock<AllocatorImpl>* newBlock + = new (m_alloc.allocate(sizeof(_memblock<AllocatorImpl>))) + _memblock<AllocatorImpl>(blockSize, m_alloc); + +#ifdef ARENA_ALLOC_DEBUG + fprintf(stdout, + "_memblockimplbase=%p allocating a new block of size=%ld\n", + this, + blockSize); +#endif + + if (m_head == 0) { + m_head = m_current = newBlock; + } else { + m_current->m_next = newBlock; + m_current = newBlock; + } } - + + void deallocate(void* ptr) { ++m_numDeallocate; } + size_t getNumAllocations() { return m_numAllocate; } size_t getNumDeallocations() { return m_numDeallocate; } size_t getNumBytesAllocated() { return m_numBytesAllocated; } - + void clear() { - _memblock<AllocatorImpl> * block = m_head; - while( block ) - { - _memblock<AllocatorImpl> * curr = block; - block = block->m_next; - curr->dispose( m_alloc ); - curr->~_memblock<AllocatorImpl>(); - m_alloc.deallocate( curr ); - } - } - - // The ref counting model does not permit the sharing of - // this object across multiple threads unless an external locking mechanism is applied - // to ensure the atomicity of the reference count. - void incrementRefCount() - { - ++m_refCount; + _memblock<AllocatorImpl>* block = m_head; + while (block) { + _memblock<AllocatorImpl>* curr = block; + block = block->m_next; + curr->dispose(m_alloc); + curr->~_memblock<AllocatorImpl>(); + m_alloc.deallocate(curr); + } + } + + void reset() + { + m_head->reset(); + m_current = m_head; + + this->m_numBytesAllocated = 0; + + _memblock<AllocatorImpl>* block = m_head->m_next; + m_head->m_next = nullptr; + while (block) { + _memblock<AllocatorImpl>* curr = block; + block = block->m_next; + curr->dispose(m_alloc); + curr->~_memblock<AllocatorImpl>(); + m_alloc.deallocate(curr); + } + } + + // The ref counting model does not permit the sharing of + // this object across multiple threads unless an external locking mechanism + // is applied to ensure the atomicity of the reference count. + void incrementRefCount() + { + ++m_refCount; #ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "ref count on _memblockimplbase=%p incremented to %ld\n", this, m_refCount ); -#endif + fprintf(stdout, + "ref count on _memblockimplbase=%p incremented to %ld\n", + this, + m_refCount); +#endif } void decrementRefCount() { - --m_refCount; + --m_refCount; #ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "ref count on _memblockimplbase=%p decremented to %ld\n", this, m_refCount ); -#endif - - if( m_refCount == 0 ) - { - Derived::destroy( static_cast<Derived*>(this) ); - } - } - }; - - - // Each allocator points to an instance of _memblockimpl which - // contains the list of _memblock objects and other tracking info - // including a refcount. - // This object is instantiated in space obtained from the allocator - // implementation. The allocator implementation is the component - // on which allocate/deallocate are called to obtain storage from. - template< typename AllocatorImpl > - struct _memblockimpl : public _memblockimplbase<AllocatorImpl, _memblockimpl<AllocatorImpl> > - { - private: - - typedef struct _memblockimplbase< AllocatorImpl, _memblockimpl<AllocatorImpl> > base_t; - friend struct _memblockimplbase< AllocatorImpl, _memblockimpl<AllocatorImpl> >; - - // to get around some sticky access issues between Alloc<T1> and Alloc<T2> when sharing - // the implementation. - template <typename U, typename A, typename M > + fprintf(stdout, + "ref count on _memblockimplbase=%p decremented to %ld\n", + this, + m_refCount); +#endif + + if (m_refCount == 0) { + Derived::destroy(static_cast<Derived*>(this)); + } + } +}; + +// Each allocator points to an instance of _memblockimpl which +// contains the list of _memblock objects and other tracking info +// including a refcount. +// This object is instantiated in space obtained from the allocator +// implementation. The allocator implementation is the component +// on which allocate/deallocate are called to obtain storage from. +template<typename AllocatorImpl> +struct _memblockimpl + : public _memblockimplbase<AllocatorImpl, _memblockimpl<AllocatorImpl> > { +private: + typedef struct _memblockimplbase<AllocatorImpl, + _memblockimpl<AllocatorImpl> > + base_t; + friend struct _memblockimplbase<AllocatorImpl, + _memblockimpl<AllocatorImpl> >; + + // to get around some sticky access issues between Alloc<T1> and Alloc<T2> + // when sharing the implementation. + template<typename U, typename A, typename M> friend class Alloc; - - template< typename T > - static void assign( const Alloc<T,AllocatorImpl, _memblockimpl<AllocatorImpl> >& src, - _memblockimpl *& dest ); - - static _memblockimpl<AllocatorImpl> * create( size_t defaultSize, AllocatorImpl& alloc ) + + template<typename T> + static void assign( + const Alloc<T, AllocatorImpl, _memblockimpl<AllocatorImpl> >& src, + _memblockimpl*& dest); + + static _memblockimpl<AllocatorImpl>* create(size_t defaultSize, + AllocatorImpl& alloc) { - return new ( alloc.allocate( sizeof( _memblockimpl ) ) ) _memblockimpl<AllocatorImpl>( defaultSize, - alloc ); + return new (alloc.allocate(sizeof(_memblockimpl))) + _memblockimpl<AllocatorImpl>(defaultSize, alloc); } - - static void destroy( _memblockimpl<AllocatorImpl> * objToDestroy ) - { - AllocatorImpl allocImpl = objToDestroy->m_alloc; - objToDestroy-> ~_memblockimpl<AllocatorImpl>(); - allocImpl.deallocate( objToDestroy ); + + static void destroy(_memblockimpl<AllocatorImpl>* objToDestroy) + { + AllocatorImpl allocImpl = objToDestroy->m_alloc; + objToDestroy->~_memblockimpl<AllocatorImpl>(); + allocImpl.deallocate(objToDestroy); } - - _memblockimpl( std::size_t defaultSize, AllocatorImpl& allocImpl ): - _memblockimplbase<AllocatorImpl, _memblockimpl<AllocatorImpl> >( defaultSize, allocImpl ) + + _memblockimpl(std::size_t defaultSize, AllocatorImpl& allocImpl) + : _memblockimplbase<AllocatorImpl, _memblockimpl<AllocatorImpl> >( + defaultSize, allocImpl) { #ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "_memblockimpl=%p constructed with default size=%ld\n", this, - base_t::m_defaultSize ); + fprintf(stdout, + "_memblockimpl=%p constructed with default size=%ld\n", + this, + base_t::m_defaultSize); #endif } - - ~_memblockimpl( ) + + ~_memblockimpl() { #ifdef ARENA_ALLOC_DEBUG - fprintf( stdout, "~memblockimpl() called on _memblockimpl=%p\n", this ); -#endif - base_t::clear(); - } - }; -} + fprintf(stdout, "~memblockimpl() called on _memblockimpl=%p\n", this); +#endif + base_t::clear(); + } +}; +} // namespace ArenaAlloc #endif |