/*****************************************************************************/
// Copyright 2006 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.cpp#1 $ */ 
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */

/*****************************************************************************/

#include "dng_memory.h"

#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_safe_arithmetic.h"

/*****************************************************************************/

dng_memory_data::dng_memory_data ()
	
	:	fBuffer (NULL)
	
	{
	
	}

/*****************************************************************************/

dng_memory_data::dng_memory_data (uint32 size)

	:	fBuffer (NULL)
	
	{
	
	Allocate (size);
	
	}

/*****************************************************************************/

dng_memory_data::dng_memory_data (uint32 count, std::size_t elementSize)

	:	fBuffer (NULL)
	
	{
	
	Allocate (count, elementSize);
	
	}

/*****************************************************************************/

dng_memory_data::~dng_memory_data ()
	{
	
	Clear ();
	
	}
				
/*****************************************************************************/

void dng_memory_data::Allocate (uint32 size)
	{
	
	Clear ();
	
	if (size)
		{
		
		fBuffer = (char*)malloc (size);
		
		if (!fBuffer)
			{
			
			ThrowMemoryFull ();
						 
			}
		
		}
	
	}
				
/*****************************************************************************/

void dng_memory_data::Allocate (uint32 count, std::size_t elementSize)
	{
	
	// Convert elementSize to a uint32.
	const uint32 elementSizeAsUint32 = static_cast<uint32> (elementSize);
	if (static_cast<std::size_t> (elementSizeAsUint32) != elementSize)
		{
		ThrowMemoryFull();
		}
	
	// Compute required number of bytes and allocate memory.
	uint32 numBytes;
	if (!SafeUint32Mult(count, elementSizeAsUint32, &numBytes))
		{
		ThrowMemoryFull();
		}
	Allocate(numBytes);
	
	}

void dng_memory_data::Clear ()
	{
	
	if (fBuffer)
		{
		
		free (fBuffer);
		
		fBuffer = NULL;
		
		}
		
	}
				
/*****************************************************************************/

dng_memory_block * dng_memory_block::Clone (dng_memory_allocator &allocator) const
	{
	
	uint32 size = LogicalSize ();
	
	dng_memory_block * result = allocator.Allocate (size);
	
	DoCopyBytes (Buffer (), result->Buffer (), size);
		
	return result;
	
	}

/*****************************************************************************/

class dng_malloc_block : public dng_memory_block
	{
	
	private:
	
		void *fMalloc;
	
	public:
	
		dng_malloc_block (uint32 logicalSize);
		
		virtual ~dng_malloc_block ();
		
	private:
	
		// Hidden copy constructor and assignment operator.
		
		dng_malloc_block (const dng_malloc_block &block);
		
		dng_malloc_block & operator= (const dng_malloc_block &block);
	
	};
	
/*****************************************************************************/

dng_malloc_block::dng_malloc_block (uint32 logicalSize)

	:	dng_memory_block (logicalSize)
	
	,	fMalloc (NULL)
	
	{

#if (qLinux && !defined(__ANDROID_API__)) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 17)

	int err = ::posix_memalign( (void **) &fMalloc, 16, (size_t) PhysicalSize() );

	if (err)
		{

		ThrowMemoryFull ();

		}

#else

	fMalloc = (char*)malloc (PhysicalSize ());
	
	if (!fMalloc)
		{
		
		ThrowMemoryFull ();
					 
		}
		
#endif

	SetBuffer (fMalloc);
	
	}
		
/*****************************************************************************/

dng_malloc_block::~dng_malloc_block ()
	{
	
	if (fMalloc)
		{
		
		free (fMalloc);
		
		}
	
	}
		
/*****************************************************************************/

dng_memory_block * dng_memory_allocator::Allocate (uint32 size)
	{
	
	dng_memory_block *result = new dng_malloc_block (size);
	
	if (!result)
		{
		
		ThrowMemoryFull ();
		
		}
	
	return result;
	
	}

/*****************************************************************************/

dng_memory_allocator gDefaultDNGMemoryAllocator;

/*****************************************************************************/