2009-09-17 13:08:33 +00:00
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
2012-09-09 16:57:42 +01:00
Rubber Band Library
2009-09-17 13:08:33 +00:00
An audio time - stretching and pitch - shifting library .
2023-01-10 11:10:06 +00:00
Copyright 2007 - 2023 Particular Programs Ltd .
2012-09-09 16:57:42 +01:00
2009-09-17 13:08:33 +00:00
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 . See the file
COPYING included with this distribution for more information .
2012-09-09 16:57:42 +01:00
Alternatively , if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders , you may redistribute and / or modify it under the terms
described in that licence .
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License ,
you must obtain a valid commercial licence before doing so .
2009-09-17 13:08:33 +00:00
*/
2020-10-21 15:05:14 +01:00
# ifndef RUBBERBAND_ALLOCATORS_H
# define RUBBERBAND_ALLOCATORS_H
2009-09-17 13:08:33 +00:00
# include "VectorOps.h"
# include <new> // for std::bad_alloc
# include <stdlib.h>
2021-05-10 18:11:35 +01:00
# include <stdexcept>
2009-09-17 13:08:33 +00:00
# ifndef HAVE_POSIX_MEMALIGN
# ifndef _WIN32
# ifndef __APPLE__
# ifndef LACK_POSIX_MEMALIGN
# define HAVE_POSIX_MEMALIGN
# endif
# endif
# endif
# endif
2018-11-29 09:12:59 +00:00
# ifndef MALLOC_IS_ALIGNED
# ifndef MALLOC_IS_NOT_ALIGNED
# ifdef __APPLE__
# define MALLOC_IS_ALIGNED
# endif
# endif
# endif
# ifndef HAVE__ALIGNED_MALLOC
# ifndef LACK__ALIGNED_MALLOC
# ifdef _WIN32
# define HAVE__ALIGNED_MALLOC
# endif
# endif
# endif
2009-09-17 13:08:33 +00:00
# ifdef HAVE_POSIX_MEMALIGN
# include <sys/mman.h>
2018-11-29 09:12:59 +00:00
# include <errno.h>
2009-09-17 13:08:33 +00:00
# endif
2012-09-09 16:57:42 +01:00
# ifdef LACK_BAD_ALLOC
namespace std { struct bad_alloc { } ; }
# endif
2011-11-25 11:11:59 +00:00
2009-09-17 13:08:33 +00:00
namespace RubberBand {
template < typename T >
T * allocate ( size_t count )
{
void * ptr = 0 ;
2018-11-29 09:12:59 +00:00
// We'd like to check HAVE_IPP first and, if it's defined, call
// ippsMalloc_8u(count * sizeof(T)). But that isn't a general
// replacement for malloc() because it only takes an int
// argument. So we save it for the specialisations of
// allocate<float> and allocate<double> below, where we're more
// likely to get away with it.
# ifdef MALLOC_IS_ALIGNED
ptr = malloc ( count * sizeof ( T ) ) ;
# else /* !MALLOC_IS_ALIGNED */
// That's the "sufficiently aligned" functions dealt with, the
2022-08-09 15:50:02 +01:00
// rest need a specific alignment provided to the call. 64-byte
// alignment is enough for 8x8 double operations
static const int alignment = 64 ;
2018-11-29 09:12:59 +00:00
# ifdef HAVE__ALIGNED_MALLOC
ptr = _aligned_malloc ( count * sizeof ( T ) , alignment ) ;
# else /* !HAVE__ALIGNED_MALLOC */
# ifdef HAVE_POSIX_MEMALIGN
int rv = posix_memalign ( & ptr , alignment , count * sizeof ( T ) ) ;
if ( rv ) {
# ifndef NO_EXCEPTIONS
if ( rv = = EINVAL ) {
2018-11-29 10:34:43 +00:00
throw " Internal error: invalid alignment " ;
2018-11-29 09:12:59 +00:00
} else {
throw std : : bad_alloc ( ) ;
}
# else
abort ( ) ;
# endif
}
# else /* !HAVE_POSIX_MEMALIGN */
2012-09-09 16:57:42 +01:00
# ifdef USE_OWN_ALIGNED_MALLOC
2018-11-29 09:12:59 +00:00
# pragma message("Rolling own aligned malloc: this is unlikely to perform as well as the alternatives")
2012-09-09 16:57:42 +01:00
// Alignment must be a power of two, bigger than the pointer
// size. Stuff the actual malloc'd pointer in just before the
// returned value. This is the least desirable way to do this --
// the other options below are all better
size_t allocd = count * sizeof ( T ) + alignment ;
void * buf = malloc ( allocd ) ;
if ( buf ) {
char * adj = ( char * ) buf ;
while ( ( unsigned long long ) adj & ( alignment - 1 ) ) - - adj ;
ptr = ( ( char * ) adj ) + alignment ;
2018-11-29 09:12:59 +00:00
new ( ( ( void * * ) ptr ) [ - 1 ] ) ( void * ) ;
2012-09-09 16:57:42 +01:00
( ( void * * ) ptr ) [ - 1 ] = buf ;
}
2018-11-29 09:12:59 +00:00
2012-09-09 16:57:42 +01:00
# else /* !USE_OWN_ALIGNED_MALLOC */
2018-11-29 09:12:59 +00:00
# error "No aligned malloc available: define MALLOC_IS_ALIGNED to use system malloc, HAVE_POSIX_MEMALIGN if posix_memalign is available, HAVE__ALIGNED_MALLOC if _aligned_malloc is available, or USE_OWN_ALIGNED_MALLOC to roll our own"
2012-09-09 16:57:42 +01:00
# endif /* !USE_OWN_ALIGNED_MALLOC */
2018-11-29 09:12:59 +00:00
# endif /* !HAVE_POSIX_MEMALIGN */
# endif /* !HAVE__ALIGNED_MALLOC */
# endif /* !MALLOC_IS_ALIGNED */
2011-11-25 11:11:59 +00:00
if ( ! ptr ) {
2012-09-09 16:57:42 +01:00
# ifndef NO_EXCEPTIONS
2018-11-29 09:12:59 +00:00
throw std : : bad_alloc ( ) ;
2012-09-09 16:57:42 +01:00
# else
abort ( ) ;
# endif
2011-11-25 11:11:59 +00:00
}
2018-11-29 09:12:59 +00:00
T * typed_ptr = static_cast < T * > ( ptr ) ;
for ( size_t i = 0 ; i < count ; + + i ) {
new ( typed_ptr + i ) T ;
}
return typed_ptr ;
2009-09-17 13:08:33 +00:00
}
2012-09-09 16:57:42 +01:00
# ifdef HAVE_IPP
template < >
float * allocate ( size_t count ) ;
template < >
double * allocate ( size_t count ) ;
# endif
2009-09-17 13:08:33 +00:00
template < typename T >
T * allocate_and_zero ( size_t count )
{
T * ptr = allocate < T > ( count ) ;
v_zero ( ptr , count ) ;
return ptr ;
}
template < typename T >
void deallocate ( T * ptr )
{
2018-11-29 09:12:59 +00:00
if ( ! ptr ) return ;
# ifdef MALLOC_IS_ALIGNED
free ( ( void * ) ptr ) ;
# else /* !MALLOC_IS_ALIGNED */
# ifdef HAVE__ALIGNED_MALLOC
_aligned_free ( ( void * ) ptr ) ;
# else /* !HAVE__ALIGNED_MALLOC */
# ifdef HAVE_POSIX_MEMALIGN
free ( ( void * ) ptr ) ;
# else /* !HAVE_POSIX_MEMALIGN */
2012-09-09 16:57:42 +01:00
# ifdef USE_OWN_ALIGNED_MALLOC
2018-11-29 09:12:59 +00:00
free ( ( ( void * * ) ptr ) [ - 1 ] ) ;
2012-09-09 16:57:42 +01:00
# else /* !USE_OWN_ALIGNED_MALLOC */
2018-11-29 09:12:59 +00:00
# error "No aligned malloc available: define MALLOC_IS_ALIGNED to use system malloc, HAVE_POSIX_MEMALIGN if posix_memalign is available, or USE_OWN_ALIGNED_MALLOC to roll our own"
2012-09-09 16:57:42 +01:00
# endif /* !USE_OWN_ALIGNED_MALLOC */
2018-11-29 09:12:59 +00:00
# endif /* !HAVE_POSIX_MEMALIGN */
# endif /* !HAVE__ALIGNED_MALLOC */
# endif /* !MALLOC_IS_ALIGNED */
2009-09-17 13:08:33 +00:00
}
2012-09-09 16:57:42 +01:00
# ifdef HAVE_IPP
template < >
void deallocate ( float * ) ;
template < >
void deallocate ( double * ) ;
# endif
2011-03-19 12:41:38 +00:00
/// Reallocate preserving contents but leaving additional memory uninitialised
2009-09-17 13:08:33 +00:00
template < typename T >
T * reallocate ( T * ptr , size_t oldcount , size_t count )
{
2011-11-25 11:11:59 +00:00
T * newptr = allocate < T > ( count ) ;
2009-09-17 13:08:33 +00:00
if ( oldcount & & ptr ) {
v_copy ( newptr , ptr , oldcount < count ? oldcount : count ) ;
}
if ( ptr ) deallocate < T > ( ptr ) ;
return newptr ;
}
2011-03-19 12:41:38 +00:00
/// Reallocate, zeroing all contents
2011-01-07 21:46:36 +00:00
template < typename T >
T * reallocate_and_zero ( T * ptr , size_t oldcount , size_t count )
{
ptr = reallocate ( ptr , oldcount , count ) ;
v_zero ( ptr , count ) ;
return ptr ;
}
2011-03-19 12:41:38 +00:00
/// Reallocate preserving contents and zeroing any additional memory
template < typename T >
T * reallocate_and_zero_extension ( T * ptr , size_t oldcount , size_t count )
{
ptr = reallocate ( ptr , oldcount , count ) ;
if ( count > oldcount ) v_zero ( ptr + oldcount , count - oldcount ) ;
return ptr ;
}
2009-09-17 13:08:33 +00:00
template < typename T >
T * * allocate_channels ( size_t channels , size_t count )
{
T * * ptr = allocate < T * > ( channels ) ;
for ( size_t c = 0 ; c < channels ; + + c ) {
ptr [ c ] = allocate < T > ( count ) ;
}
return ptr ;
}
template < typename T >
T * * allocate_and_zero_channels ( size_t channels , size_t count )
{
T * * ptr = allocate < T * > ( channels ) ;
for ( size_t c = 0 ; c < channels ; + + c ) {
ptr [ c ] = allocate_and_zero < T > ( count ) ;
}
return ptr ;
}
template < typename T >
void deallocate_channels ( T * * ptr , size_t channels )
{
if ( ! ptr ) return ;
for ( size_t c = 0 ; c < channels ; + + c ) {
deallocate < T > ( ptr [ c ] ) ;
}
deallocate < T * > ( ptr ) ;
}
template < typename T >
T * * reallocate_channels ( T * * ptr ,
size_t oldchannels , size_t oldcount ,
size_t channels , size_t count )
{
2011-11-25 11:11:59 +00:00
T * * newptr = allocate_channels < T > ( channels , count ) ;
2009-09-17 13:08:33 +00:00
if ( oldcount & & ptr ) {
2020-09-16 17:47:30 +01:00
for ( size_t c = 0 ; c < oldchannels & & c < channels ; + + c ) {
for ( size_t i = 0 ; i < oldcount & & i < count ; + + i ) {
newptr [ c ] [ i ] = ptr [ c ] [ i ] ;
}
}
2009-09-17 13:08:33 +00:00
}
2020-09-16 17:47:30 +01:00
if ( ptr ) deallocate_channels < T > ( ptr , oldchannels ) ;
2010-03-24 09:44:51 +00:00
return newptr ;
}
template < typename T >
T * * reallocate_and_zero_extend_channels ( T * * ptr ,
size_t oldchannels , size_t oldcount ,
size_t channels , size_t count )
{
2011-11-25 11:11:59 +00:00
T * * newptr = allocate_and_zero_channels < T > ( channels , count ) ;
2010-03-24 09:44:51 +00:00
if ( oldcount & & ptr ) {
2020-09-16 17:47:30 +01:00
for ( size_t c = 0 ; c < oldchannels & & c < channels ; + + c ) {
for ( size_t i = 0 ; i < oldcount & & i < count ; + + i ) {
newptr [ c ] [ i ] = ptr [ c ] [ i ] ;
}
}
2010-03-24 09:44:51 +00:00
}
2020-09-16 17:47:30 +01:00
if ( ptr ) deallocate_channels < T > ( ptr , oldchannels ) ;
2009-09-17 13:08:33 +00:00
return newptr ;
}
2012-09-09 16:57:42 +01:00
/// RAII class to call deallocate() on destruction
template < typename T >
class Deallocator
{
public :
Deallocator ( T * t ) : m_t ( t ) { }
~ Deallocator ( ) { deallocate < T > ( m_t ) ; }
private :
T * m_t ;
} ;
2021-05-10 18:11:35 +01:00
/** Allocator for use with STL classes, e.g. vector, to ensure
* alignment . Based on example code by Stephan T . Lavavej .
*
* e . g . std : : vector < float , StlAllocator < float > > v ;
*/
template < typename T >
class StlAllocator
{
public :
typedef T * pointer ;
typedef const T * const_pointer ;
typedef T & reference ;
typedef const T & const_reference ;
typedef T value_type ;
typedef size_t size_type ;
typedef ptrdiff_t difference_type ;
StlAllocator ( ) { }
StlAllocator ( const StlAllocator & ) { }
template < typename U > StlAllocator ( const StlAllocator < U > & ) { }
~ StlAllocator ( ) { }
T *
allocate ( const size_t n ) const {
if ( n = = 0 ) return 0 ;
if ( n > max_size ( ) ) {
# ifndef NO_EXCEPTIONS
throw std : : length_error ( " Size overflow in StlAllocator::allocate() " ) ;
# else
abort ( ) ;
# endif
}
2021-10-12 16:27:19 +01:00
return RubberBand : : allocate < T > ( n ) ;
2021-05-10 18:11:35 +01:00
}
void
deallocate ( T * const p , const size_t ) const {
2021-10-12 16:27:19 +01:00
RubberBand : : deallocate ( p ) ;
2021-05-10 18:11:35 +01:00
}
template < typename U >
T *
allocate ( const size_t n , const U * ) const {
return allocate ( n ) ;
}
T *
address ( T & r ) const {
return & r ;
}
const T *
address ( const T & s ) const {
return & s ;
}
size_t
max_size ( ) const {
return ( static_cast < size_t > ( 0 ) - static_cast < size_t > ( 1 ) ) / sizeof ( T ) ;
}
template < typename U > struct rebind {
typedef StlAllocator < U > other ;
} ;
bool
operator = = ( const StlAllocator & ) const {
return true ;
}
bool
operator ! = ( const StlAllocator & ) const {
return false ;
}
void
construct ( T * const p , const T & t ) const {
void * const pv = static_cast < void * > ( p ) ;
new ( pv ) T ( t ) ;
}
void
destroy ( T * const p ) const {
p - > ~ T ( ) ;
}
private :
StlAllocator & operator = ( const StlAllocator & ) ;
} ;
2009-09-17 13:08:33 +00:00
}
# endif