/*****************************************************************************/
// 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
	
/*****************************************************************************/