blob: 05e6f2b89578adc74913fedff39e0df612739d86 [file] [log] [blame]
/*****************************************************************************/
// Copyright 2006-2007 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_memory.h#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/** Support for memory allocation.
*/
/*****************************************************************************/
#ifndef __dng_memory__
#define __dng_memory__
/*****************************************************************************/
#include "dng_classes.h"
#include "dng_exceptions.h"
#include "dng_safe_arithmetic.h"
#include "dng_types.h"
#include <cstdlib>
#include <vector>
/*****************************************************************************/
/// \brief Class to provide resource acquisition is instantiation discipline
/// for small memory allocations.
///
/// This class does not use dng_memory_allocator for memory allocation.
class dng_memory_data
{
private:
char *fBuffer;
public:
/// Construct an empty memory buffer using malloc.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data ();
/// Construct memory buffer of size bytes using malloc.
/// \param size Number of bytes of memory needed.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data (uint32 size);
/// Note: This constructor is for internal use only and should not be
/// considered part of the DNG SDK API.
///
/// Construct memory buffer of count elements of elementSize bytes each.
/// \param count Number of elements.
/// \param elementSize Size of each element.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
dng_memory_data (uint32 count, std::size_t elementSize);
/// Release memory buffer using free.
~dng_memory_data ();
/// Clear existing memory buffer and allocate new memory of size bytes.
/// \param size Number of bytes of memory needed.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
void Allocate (uint32 size);
/// Note: This method is for internal use only and should not be
/// considered part of the DNG SDK API.
///
/// Clear existing memory buffer and allocate new memory of count
/// elements of elementSize bytes each.
/// \param count Number of elements.
/// \param elementSize Size of each element.
/// \exception dng_memory_full with fErrorCode equal to dng_error_memory.
void Allocate (uint32 count, std::size_t elementSize);
/// Release any allocated memory using free. Object is still valid and
/// Allocate can be called again.
void Clear ();
/// Return pointer to allocated memory as a void *..
/// \retval void * valid for as many bytes as were allocated.
void * Buffer ()
{
return fBuffer;
}
/// Return pointer to allocated memory as a const void *.
/// \retval const void * valid for as many bytes as were allocated.
const void * Buffer () const
{
return fBuffer;
}
/// Return pointer to allocated memory as a char *.
/// \retval char * valid for as many bytes as were allocated.
char * Buffer_char ()
{
return (char *) Buffer ();
}
/// Return pointer to allocated memory as a const char *.
/// \retval const char * valid for as many bytes as were allocated.
const char * Buffer_char () const
{
return (const char *) Buffer ();
}
/// Return pointer to allocated memory as a uint8 *.
/// \retval uint8 * valid for as many bytes as were allocated.
uint8 * Buffer_uint8 ()
{
return (uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint8 *.
/// \retval const uint8 * valid for as many bytes as were allocated.
const uint8 * Buffer_uint8 () const
{
return (const uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a uint16 *.
/// \retval uint16 * valid for as many bytes as were allocated.
uint16 * Buffer_uint16 ()
{
return (uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint16 *.
/// \retval const uint16 * valid for as many bytes as were allocated.
const uint16 * Buffer_uint16 () const
{
return (const uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a int16 *.
/// \retval int16 * valid for as many bytes as were allocated.
int16 * Buffer_int16 ()
{
return (int16 *) Buffer ();
}
/// Return pointer to allocated memory as a const int16 *.
/// \retval const int16 * valid for as many bytes as were allocated.
const int16 * Buffer_int16 () const
{
return (const int16 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
uint32 * Buffer_uint32 ()
{
return (uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
const uint32 * Buffer_uint32 () const
{
return (const uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
int32 * Buffer_int32 ()
{
return (int32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
const int32 * Buffer_int32 () const
{
return (const int32 *) Buffer ();
}
/// Return pointer to allocated memory as a uint64 *.
/// \retval uint64 * valid for as many bytes as were allocated.
uint64 * Buffer_uint64 ()
{
return (uint64 *) Buffer ();
}
/// Return pointer to allocated memory as a uint64 *.
/// \retval uint64 * valid for as many bytes as were allocated.
const uint64 * Buffer_uint64 () const
{
return (const uint64 *) Buffer ();
}
/// Return pointer to allocated memory as a const int64 *.
/// \retval const int64 * valid for as many bytes as were allocated.
int64 * Buffer_int64 ()
{
return (int64 *) Buffer ();
}
/// Return pointer to allocated memory as a const int64 *.
/// \retval const int64 * valid for as many bytes as were allocated.
const int64 * Buffer_int64 () const
{
return (const int64 *) Buffer ();
}
/// Return pointer to allocated memory as a real32 *.
/// \retval real32 * valid for as many bytes as were allocated.
real32 * Buffer_real32 ()
{
return (real32 *) Buffer ();
}
/// Return pointer to allocated memory as a const real32 *.
/// \retval const real32 * valid for as many bytes as were allocated.
const real32 * Buffer_real32 () const
{
return (const real32 *) Buffer ();
}
/// Return pointer to allocated memory as a real64 *.
/// \retval real64 * valid for as many bytes as were allocated.
real64 * Buffer_real64 ()
{
return (real64 *) Buffer ();
}
/// Return pointer to allocated memory as a const real64 *.
/// \retval const real64 * valid for as many bytes as were allocated.
const real64 * Buffer_real64 () const
{
return (const real64 *) Buffer ();
}
private:
// Hidden copy constructor and assignment operator.
dng_memory_data (const dng_memory_data &data);
dng_memory_data & operator= (const dng_memory_data &data);
};
/*****************************************************************************/
/// \brief Class to provide resource acquisition is instantiation discipline for
/// image buffers and other larger memory allocations.
///
/// This class requires a dng_memory_allocator for allocation.
class dng_memory_block
{
private:
uint32 fLogicalSize;
char *fBuffer;
protected:
dng_memory_block (uint32 logicalSize)
: fLogicalSize (logicalSize)
, fBuffer (NULL)
{
}
uint32 PhysicalSize ()
{
// This size is padded for TWO reasons! The first is allow alignment
// to 16-byte boundaries if the allocator does not do that already. The
// second, which is very important, so to provide safe overread areas for
// SSE2-type bottlenecks, which can often be written faster by allowing them
// to reading slightly block. Someone on the image core them did not
// understand this and removed this padding. I'm undoing this removal
// and restoring this padding, since removing it might lead to memory
// access crashes in some cases.
// This padding is throwing off all of our allocations (f.e. dng_string, pixel buffers, etc)
// that uses dng_memory_block on iOS/Android that is memory limited. Imagecore carefully
// allocates pow2 tile buffers, but this bumps us to the next ssd block (+4K).
// This also makes it difficult to identify memory reports in Instruments since all
// numbers are off by 64. Imagecore never crashed from the removal of the padding.
// The allocator on Win64/Mac64 is 16-byte aligned already. iOS is too.
// Linux is 8 byte, but it's using mem_align.
// We should fix the SIMD routines and revisit removing this padding - Alec.
uint32 result;
if (!SafeUint32Add(fLogicalSize, 64u, &result))
{
ThrowMemoryFull("Arithmetic overflow in PhysicalSize()");
}
return result;
}
void SetBuffer (void *p)
{
fBuffer = (char *) ((((uintptr) p) + 15) & ~((uintptr) 15));
}
public:
virtual ~dng_memory_block ()
{
}
dng_memory_block * Clone (dng_memory_allocator &allocator) const;
/// Getter for available size, in bytes, of memory block.
/// \retval size in bytes of available memory in memory block.
uint32 LogicalSize () const
{
return fLogicalSize;
}
/// Return pointer to allocated memory as a void *..
/// \retval void * valid for as many bytes as were allocated.
void * Buffer ()
{
return fBuffer;
}
/// Return pointer to allocated memory as a const void *.
/// \retval const void * valid for as many bytes as were allocated.
const void * Buffer () const
{
return fBuffer;
}
/// Return pointer to allocated memory as a char *.
/// \retval char * valid for as many bytes as were allocated.
char * Buffer_char ()
{
return (char *) Buffer ();
}
/// Return pointer to allocated memory as a const char *.
/// \retval const char * valid for as many bytes as were allocated.
const char * Buffer_char () const
{
return (const char *) Buffer ();
}
/// Return pointer to allocated memory as a uint8 *.
/// \retval uint8 * valid for as many bytes as were allocated.
uint8 * Buffer_uint8 ()
{
return (uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint8 *.
/// \retval const uint8 * valid for as many bytes as were allocated.
const uint8 * Buffer_uint8 () const
{
return (const uint8 *) Buffer ();
}
/// Return pointer to allocated memory as a uint16 *.
/// \retval uint16 * valid for as many bytes as were allocated.
uint16 * Buffer_uint16 ()
{
return (uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint16 *.
/// \retval const uint16 * valid for as many bytes as were allocated.
const uint16 * Buffer_uint16 () const
{
return (const uint16 *) Buffer ();
}
/// Return pointer to allocated memory as a int16 *.
/// \retval int16 * valid for as many bytes as were allocated.
int16 * Buffer_int16 ()
{
return (int16 *) Buffer ();
}
/// Return pointer to allocated memory as a const int16 *.
/// \retval const int16 * valid for as many bytes as were allocated.
const int16 * Buffer_int16 () const
{
return (const int16 *) Buffer ();
}
/// Return pointer to allocated memory as a uint32 *.
/// \retval uint32 * valid for as many bytes as were allocated.
uint32 * Buffer_uint32 ()
{
return (uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a const uint32 *.
/// \retval const uint32 * valid for as many bytes as were allocated.
const uint32 * Buffer_uint32 () const
{
return (const uint32 *) Buffer ();
}
/// Return pointer to allocated memory as a int32 *.
/// \retval int32 * valid for as many bytes as were allocated.
int32 * Buffer_int32 ()
{
return (int32 *) Buffer ();
}
/// Return pointer to allocated memory as a const int32 *.
/// \retval const int32 * valid for as many bytes as were allocated.
const int32 * Buffer_int32 () const
{
return (const int32 *) Buffer ();
}
/// Return pointer to allocated memory as a real32 *.
/// \retval real32 * valid for as many bytes as were allocated.
real32 * Buffer_real32 ()
{
return (real32 *) Buffer ();
}
/// Return pointer to allocated memory as a const real32 *.
/// \retval const real32 * valid for as many bytes as were allocated.
const real32 * Buffer_real32 () const
{
return (const real32 *) Buffer ();
}
/// Return pointer to allocated memory as a real64 *.
/// \retval real64 * valid for as many bytes as were allocated.
real64 * Buffer_real64 ()
{
return (real64 *) Buffer ();
}
/// Return pointer to allocated memory as a const real64 *.
/// \retval const real64 * valid for as many bytes as were allocated.
const real64 * Buffer_real64 () const
{
return (const real64 *) Buffer ();
}
private:
// Hidden copy constructor and assignment operator.
dng_memory_block (const dng_memory_block &data);
dng_memory_block & operator= (const dng_memory_block &data);
};
/*****************************************************************************/
/// \brief Interface for dng_memory_block allocator.
class dng_memory_allocator
{
public:
virtual ~dng_memory_allocator ()
{
}
/// Allocate a dng_memory block.
/// \param size Number of bytes in memory block.
/// \retval A dng_memory_block with at least size bytes of valid storage.
/// \exception dng_exception with fErrorCode equal to dng_error_memory.
virtual dng_memory_block * Allocate (uint32 size);
};
/*****************************************************************************/
/// \brief Default memory allocator used if NULL is passed in for allocator
/// when constructing a dng_host.
///
/// Uses new and delete for memory block object and malloc/free for underlying
/// buffer.
extern dng_memory_allocator gDefaultDNGMemoryAllocator;
/*****************************************************************************/
// C++ allocator (i.e. an implementation of the Allocator concept) that throws a
// dng_exception with error code dng_error_memory if it cannot allocate memory.
template <typename T>
class dng_std_allocator
{
public:
typedef T value_type;
// Default implementations of default constructor and copy constructor.
dng_std_allocator () = default;
dng_std_allocator (const dng_std_allocator&) = default;
template<typename U> dng_std_allocator (const dng_std_allocator<U>&) {}
T* allocate (size_t n)
{
const size_t size = SafeSizetMult(n, sizeof (T));
T *retval = static_cast<T *> (malloc (size));
if (!retval) {
ThrowMemoryFull ();
}
return retval;
}
void deallocate (T *ptr, size_t n)
{
free (ptr);
}
};
template <class T>
bool operator== (const dng_std_allocator<T> &a1,
const dng_std_allocator<T> &a2)
{
return true;
}
template <class T>
bool operator!= (const dng_std_allocator<T> &a1,
const dng_std_allocator<T> &a2)
{
return false;
}
// std::vector specialized to use dng_std_allocator for allocation.
template <class T> using dng_std_vector = std::vector<T, dng_std_allocator<T> >;
/*****************************************************************************/
#endif
/*****************************************************************************/