mirror of
https://github.com/nzp-team/vhlt.git
synced 2024-11-24 21:02:22 +00:00
233 lines
6.5 KiB
C
233 lines
6.5 KiB
C
|
// Copyright (C) 2000 Sean Cavanaugh
|
||
|
// This file is licensed under the terms of the Lesser GNU Public License
|
||
|
// (see LPGL.txt, or http://www.gnu.org/copyleft/lesser.txt)
|
||
|
|
||
|
#if !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)
|
||
|
#define AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_
|
||
|
|
||
|
#if _MSC_VER > 1000
|
||
|
#pragma once
|
||
|
#endif // _MSC_VER > 1000
|
||
|
|
||
|
#ifdef WIN32
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include "windows.h"
|
||
|
#endif
|
||
|
#include "assert.h"
|
||
|
#include "limits.h"
|
||
|
|
||
|
#include "ReferenceCounter.h"
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
class ReferenceObjectBlock
|
||
|
{
|
||
|
public:
|
||
|
DATA_T* pData; // User defined data block
|
||
|
mutable ReferenceCounter ReferenceCount;
|
||
|
unsigned int AllocLength; // Current size of array, in T sized units. if AllocLength = 0, pData is const and needs CopyOnWrite
|
||
|
HEADER_T Header; // User defined header block (must be safe to copy with operator=)
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
/*!
|
||
|
\author Sean Cavanaugh
|
||
|
\email sean@dimensionalrift.com
|
||
|
\cvsauthor $Author: sean $
|
||
|
\date $Date: 2000/09/11 20:28:24 $
|
||
|
\version $Revision: 1.1 $
|
||
|
\brief ReferenceObject is a template class designed to be used a base class for pass-by-reference objects, to that things such as returning objects up the stack efficiently are possible.
|
||
|
\bug EVERY non const function needs its very first operation to be CopyForWrite()
|
||
|
\bug EVERY derived class should define its operator=() to call the ReferenceObject base class version (notice this operator is protected,)
|
||
|
\bug HEADER_T will probably need an operator=() defined for all but the most trivial types
|
||
|
\bug Store objects or simple data types, NO POINTERS (use ReferencePtrObject for that) (they will leak like mad)
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
class ReferenceObject
|
||
|
{
|
||
|
public:
|
||
|
ReferenceObject();
|
||
|
ReferenceObject(unsigned int size);
|
||
|
ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other);
|
||
|
virtual ~ReferenceObject();
|
||
|
|
||
|
public:
|
||
|
HEADER_T& getHeader();
|
||
|
DATA_T* getData();
|
||
|
|
||
|
ReferenceObject<HEADER_T,DATA_T>& operator=(const ReferenceObject<HEADER_T,DATA_T>& other);
|
||
|
|
||
|
protected:
|
||
|
void AllocBlock(unsigned int size); // Allocate Header+Data Block (size in T units)
|
||
|
void AllocHeader(); // Allocate Header Block
|
||
|
void AllocData(unsigned int size); // Alocate Data Block (size in T units)
|
||
|
|
||
|
virtual void Release(); // Releases a reference count (possibly freeing memory)
|
||
|
virtual void InitHeader(); // User defined Header Initialization function
|
||
|
virtual void FreeHeader(); // User defined Header destructor function
|
||
|
virtual void CopyForWrite(); // Make unique copy for writing, must first instruction in all non const-functions in derived classes
|
||
|
virtual void CopyForWrite(unsigned int size); // same as CopyForWrite() except takes a resize parameter
|
||
|
|
||
|
ReferenceObjectBlock<HEADER_T,DATA_T>* m_pData;
|
||
|
};
|
||
|
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
ReferenceObject<HEADER_T,DATA_T>::ReferenceObject()
|
||
|
{
|
||
|
m_pData = NULL;
|
||
|
AllocHeader();
|
||
|
InitHeader();
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(unsigned int size)
|
||
|
{
|
||
|
m_pData = NULL;
|
||
|
AllocBlock(size);
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other)
|
||
|
{
|
||
|
m_pData = other.m_pData;
|
||
|
m_pData->ReferenceCount++;
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
ReferenceObject<HEADER_T,DATA_T>::~ReferenceObject()
|
||
|
{
|
||
|
Release();
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
ReferenceObject<HEADER_T,DATA_T>& ReferenceObject<HEADER_T,DATA_T>::operator=(const ReferenceObject<HEADER_T,DATA_T>& other)
|
||
|
{
|
||
|
if (m_pData != other.m_pData)
|
||
|
{
|
||
|
Release();
|
||
|
m_pData = other.m_pData;
|
||
|
m_pData->ReferenceCount++;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::Release()
|
||
|
{
|
||
|
assert(m_pData != NULL);
|
||
|
if (m_pData->ReferenceCount.dec() <= 0)
|
||
|
{
|
||
|
FreeHeader();
|
||
|
delete[] m_pData->pData;
|
||
|
delete m_pData;
|
||
|
m_pData = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::AllocBlock(unsigned int size)
|
||
|
{
|
||
|
AllocHeader();
|
||
|
AllocData(size);
|
||
|
InitHeader(); // Initialize user defined header
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::AllocHeader()
|
||
|
{
|
||
|
m_pData = new ReferenceObjectBlock<HEADER_T,DATA_T>;
|
||
|
|
||
|
m_pData->ReferenceCount = 1;
|
||
|
m_pData->pData = NULL;
|
||
|
m_pData->AllocLength = 0;
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::AllocData(unsigned int size)
|
||
|
{
|
||
|
assert(m_pData != NULL);
|
||
|
assert((size * sizeof(DATA_T)) < INT_MAX);
|
||
|
|
||
|
if (size)
|
||
|
{
|
||
|
m_pData->pData = new DATA_T[size];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_pData->pData = NULL;
|
||
|
}
|
||
|
m_pData->AllocLength = size;
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::InitHeader()
|
||
|
{
|
||
|
// NOTE: Derive this function to initialize the Header object(s)
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::FreeHeader()
|
||
|
{
|
||
|
// NOTE: Derive this function to clean up the Header object(s)
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite()
|
||
|
{
|
||
|
CopyForWrite(m_pData->AllocLength);
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite(unsigned int size)
|
||
|
{
|
||
|
unsigned int oldsize = m_pData->AllocLength;
|
||
|
|
||
|
if (size)
|
||
|
{
|
||
|
if ((m_pData->ReferenceCount > 1) || (size != oldsize))
|
||
|
{
|
||
|
ReferenceObjectBlock<HEADER_T,DATA_T>* pTmp = m_pData;
|
||
|
AllocBlock(size);
|
||
|
m_pData->Header = pTmp->Header;
|
||
|
unsigned int sizetocopy = min(size,oldsize);
|
||
|
// memcpy(m_pData->pData, pTmp->pData, min(size,oldsize) * sizeof(DATA_T)); // memcpy not safe for objects
|
||
|
for (unsigned int x=0;x<sizetocopy;x++)
|
||
|
{
|
||
|
m_pData->pData[x] = pTmp->pData[x];
|
||
|
}
|
||
|
if (pTmp->ReferenceCount.dec() <= 0)
|
||
|
{
|
||
|
delete[] pTmp->pData;
|
||
|
delete pTmp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else // Replace reference to a null object (since size is zero)
|
||
|
{
|
||
|
Release();
|
||
|
AllocHeader();
|
||
|
InitHeader();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
HEADER_T& ReferenceObject<HEADER_T,DATA_T>::getHeader()
|
||
|
{
|
||
|
CopyForWrite();
|
||
|
return m_pData->Header;
|
||
|
}
|
||
|
|
||
|
template<class HEADER_T, class DATA_T>
|
||
|
DATA_T* ReferenceObject<HEADER_T,DATA_T>::getData()
|
||
|
{
|
||
|
CopyForWrite();
|
||
|
return m_pData->pData;
|
||
|
}
|
||
|
|
||
|
#endif // !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)
|