/****************************************************************************** libx42pp - skinned vertex animation library (C++ API) Copyright (C) 2007 HermitWorks Entertainment Corporation This program is free software; you can 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA. ******************************************************************************/ #include "local.h" namespace x42 { namespace util { /***** heap_mem */ heap_mem::heap_mem( void ) : mem( NULL ) { } heap_mem::heap_mem( size_t cb, size_t a ) : mem( NULL ) { alloc( cb, a ); } heap_mem::~heap_mem( void ) { unref(); } heap_mem::heap_mem( const heap_mem &src ) : mem( NULL ) { setmem( src.mem ); } heap_mem& heap_mem::operator = ( const heap_mem &src ) { setmem( src.mem ); return *this; } void heap_mem::alloc( size_t cb, size_t a ) { void *m = getmem( cb, a ); setmem( m ); } void heap_mem::realloc( size_t cb, size_t a ) { demand( mem != NULL, ErrCode::InvalidOp, "can't realloc a NULL buffer" ); if( cb == size() ) return; void *m = getmem( cb, a ); memcpy( m, mem, math::min( cb, size() ) ); setmem( m ); } size_t heap_mem::size( void ) const { size_t *spec = (size_t*)mem; return spec[size_ofs]; } size_t heap_mem::alignment( void ) const { size_t *spec = (size_t*)mem; return spec[align_ofs]; } void heap_mem::swap( heap_mem &other ) { std::swap( mem, other.mem ); } void* heap_mem::getmem( size_t cb, size_t a ) { size_t ia = a; if( ia < sizeof( size_t ) ) ia = sizeof( size_t ); void *buf = malloc( cb + sizeof( size_t ) * 4 + ia ); demand( buf, ErrCode::OutOfMemory, "failed to allocate memory" ); size_t *m = (size_t*)buf; m = align( m + 4, ia ); m[ref_ofs] = 0; m[size_ofs] = cb; m[align_ofs] = a; m[ptrofs_ofs] = (byte*)m - (byte*)buf; return m; } void heap_mem::freemem( void ) { size_t *m = (size_t*)mem; void *buf = (byte*)m - m[ptrofs_ofs]; free( buf ); mem = NULL; } void heap_mem::setmem( void *m ) { unref(); mem = m; ref(); } size_t& heap_mem::ref_count( void ) { size_t *spec = (size_t*)mem; return spec[ref_ofs]; } void heap_mem::ref( void ) { if( !mem ) return; ref_count()++; } void heap_mem::unref( void ) { if( !mem ) return; if( --ref_count() == 0 ) freemem(); } void heap_mem::require_unique( void ) { if( !mem ) return; if( ref_count() > 1 ) { void *m = getmem( size(), alignment() ); memcpy( m, mem, size() ); setmem( m ); } } }; };