/*****************************************************************************/
// 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_ref_counted_block.cpp#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/*****************************************************************************/
#include <new>
#include "dng_ref_counted_block.h"
#include "dng_exceptions.h"
/*****************************************************************************/
dng_ref_counted_block::dng_ref_counted_block ()
: fBuffer (NULL)
{
}
/*****************************************************************************/
dng_ref_counted_block::dng_ref_counted_block (uint32 size)
: fBuffer (NULL)
{
Allocate (size);
}
/*****************************************************************************/
dng_ref_counted_block::~dng_ref_counted_block ()
{
Clear ();
}
/*****************************************************************************/
void dng_ref_counted_block::Allocate (uint32 size)
{
Clear ();
if (size)
{
fBuffer = malloc (size + sizeof (header));
if (!fBuffer)
{
ThrowMemoryFull ();
}
new (fBuffer) header (size);
}
}
/*****************************************************************************/
void dng_ref_counted_block::Clear ()
{
if (fBuffer)
{
bool doFree = false;
header *blockHeader = (struct header *)fBuffer;
{
dng_lock_mutex lock (&blockHeader->fMutex);
if (--blockHeader->fRefCount == 0)
doFree = true;
}
if (doFree)
{
blockHeader->~header ();
free (fBuffer);
}
fBuffer = NULL;
}
}
/*****************************************************************************/
dng_ref_counted_block::dng_ref_counted_block (const dng_ref_counted_block &data)
: fBuffer (NULL)
{
header *blockHeader = (struct header *)data.fBuffer;
dng_lock_mutex lock (&blockHeader->fMutex);
blockHeader->fRefCount++;
fBuffer = blockHeader;
}
/*****************************************************************************/
dng_ref_counted_block & dng_ref_counted_block::operator= (const dng_ref_counted_block &data)
{
if (this != &data)
{
Clear ();
header *blockHeader = (struct header *)data.fBuffer;
dng_lock_mutex lock (&blockHeader->fMutex);
blockHeader->fRefCount++;
fBuffer = blockHeader;
}
return *this;
}
/*****************************************************************************/
void dng_ref_counted_block::EnsureWriteable ()
{
if (fBuffer)
{
header *possiblySharedHeader = (header *)fBuffer;
{
dng_lock_mutex lock (&possiblySharedHeader->fMutex);
if (possiblySharedHeader->fRefCount > 1)
{
fBuffer = NULL;
Allocate ((uint32)possiblySharedHeader->fSize);
memcpy (Buffer (),
((char *)possiblySharedHeader) + sizeof (struct header), // could just do + 1 w/o cast, but this makes the type mixing more explicit
possiblySharedHeader->fSize);
possiblySharedHeader->fRefCount--;
}
}
}
}
/*****************************************************************************/