blob: 951a6ee84f9d4ecc42b0d2131ed64bcf249acdd4 [file] [log] [blame]
/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/
#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_std_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;
if (blockHeader)
{
dng_lock_std_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;
if (blockHeader)
{
dng_lock_std_mutex lock (blockHeader->fMutex);
blockHeader->fRefCount++;
fBuffer = blockHeader;
}
}
return *this;
}
/*****************************************************************************/
void dng_ref_counted_block::EnsureWriteable ()
{
if (fBuffer)
{
header *possiblySharedHeader = (header *) fBuffer;
{
dng_lock_std_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--;
}
}
}
}
/*****************************************************************************/