ReferenceObject.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright (C) 2000 Sean Cavanaugh
  2. // This file is licensed under the terms of the Lesser GNU Public License
  3. // (see LPGL.txt, or http://www.gnu.org/copyleft/lesser.txt)
  4. #if !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)
  5. #define AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_
  6. #if _MSC_VER > 1000
  7. #pragma once
  8. #endif // _MSC_VER > 1000
  9. #ifdef WIN32
  10. #define WIN32_LEAN_AND_MEAN
  11. #include "windows.h"
  12. #endif
  13. #include "assert.h"
  14. #include "limits.h"
  15. #include "ReferenceCounter.h"
  16. template<class HEADER_T, class DATA_T>
  17. class ReferenceObjectBlock
  18. {
  19. public:
  20. DATA_T* pData; // User defined data block
  21. mutable ReferenceCounter ReferenceCount;
  22. unsigned int AllocLength; // Current size of array, in T sized units. if AllocLength = 0, pData is const and needs CopyOnWrite
  23. HEADER_T Header; // User defined header block (must be safe to copy with operator=)
  24. };
  25. /*!
  26. \author Sean Cavanaugh
  27. \email [email protected]
  28. \cvsauthor $Author: sean $
  29. \date $Date: 2000/09/11 20:28:24 $
  30. \version $Revision: 1.1 $
  31. \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.
  32. \bug EVERY non const function needs its very first operation to be CopyForWrite()
  33. \bug EVERY derived class should define its operator=() to call the ReferenceObject base class version (notice this operator is protected,)
  34. \bug HEADER_T will probably need an operator=() defined for all but the most trivial types
  35. \bug Store objects or simple data types, NO POINTERS (use ReferencePtrObject for that) (they will leak like mad)
  36. */
  37. template<class HEADER_T, class DATA_T>
  38. class ReferenceObject
  39. {
  40. public:
  41. ReferenceObject();
  42. ReferenceObject(unsigned int size);
  43. ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other);
  44. virtual ~ReferenceObject();
  45. public:
  46. HEADER_T& getHeader();
  47. DATA_T* getData();
  48. ReferenceObject<HEADER_T,DATA_T>& operator=(const ReferenceObject<HEADER_T,DATA_T>& other);
  49. protected:
  50. void AllocBlock(unsigned int size); // Allocate Header+Data Block (size in T units)
  51. void AllocHeader(); // Allocate Header Block
  52. void AllocData(unsigned int size); // Alocate Data Block (size in T units)
  53. virtual void Release(); // Releases a reference count (possibly freeing memory)
  54. virtual void InitHeader(); // User defined Header Initialization function
  55. virtual void FreeHeader(); // User defined Header destructor function
  56. virtual void CopyForWrite(); // Make unique copy for writing, must first instruction in all non const-functions in derived classes
  57. virtual void CopyForWrite(unsigned int size); // same as CopyForWrite() except takes a resize parameter
  58. ReferenceObjectBlock<HEADER_T,DATA_T>* m_pData;
  59. };
  60. template<class HEADER_T, class DATA_T>
  61. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject()
  62. {
  63. m_pData = NULL;
  64. AllocHeader();
  65. InitHeader();
  66. }
  67. template<class HEADER_T, class DATA_T>
  68. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(unsigned int size)
  69. {
  70. m_pData = NULL;
  71. AllocBlock(size);
  72. }
  73. template<class HEADER_T, class DATA_T>
  74. ReferenceObject<HEADER_T,DATA_T>::ReferenceObject(const ReferenceObject<HEADER_T,DATA_T>& other)
  75. {
  76. m_pData = other.m_pData;
  77. m_pData->ReferenceCount++;
  78. }
  79. template<class HEADER_T, class DATA_T>
  80. ReferenceObject<HEADER_T,DATA_T>::~ReferenceObject()
  81. {
  82. Release();
  83. }
  84. template<class HEADER_T, class DATA_T>
  85. ReferenceObject<HEADER_T,DATA_T>& ReferenceObject<HEADER_T,DATA_T>::operator=(const ReferenceObject<HEADER_T,DATA_T>& other)
  86. {
  87. if (m_pData != other.m_pData)
  88. {
  89. Release();
  90. m_pData = other.m_pData;
  91. m_pData->ReferenceCount++;
  92. }
  93. return *this;
  94. }
  95. template<class HEADER_T, class DATA_T>
  96. void ReferenceObject<HEADER_T,DATA_T>::Release()
  97. {
  98. assert(m_pData != NULL);
  99. if (m_pData->ReferenceCount.dec() <= 0)
  100. {
  101. FreeHeader();
  102. delete[] m_pData->pData;
  103. delete m_pData;
  104. m_pData = NULL;
  105. }
  106. }
  107. template<class HEADER_T, class DATA_T>
  108. void ReferenceObject<HEADER_T,DATA_T>::AllocBlock(unsigned int size)
  109. {
  110. AllocHeader();
  111. AllocData(size);
  112. InitHeader(); // Initialize user defined header
  113. }
  114. template<class HEADER_T, class DATA_T>
  115. void ReferenceObject<HEADER_T,DATA_T>::AllocHeader()
  116. {
  117. m_pData = new ReferenceObjectBlock<HEADER_T,DATA_T>;
  118. m_pData->ReferenceCount = 1;
  119. m_pData->pData = NULL;
  120. m_pData->AllocLength = 0;
  121. }
  122. template<class HEADER_T, class DATA_T>
  123. void ReferenceObject<HEADER_T,DATA_T>::AllocData(unsigned int size)
  124. {
  125. assert(m_pData != NULL);
  126. assert((size * sizeof(DATA_T)) < INT_MAX);
  127. if (size)
  128. {
  129. m_pData->pData = new DATA_T[size];
  130. }
  131. else
  132. {
  133. m_pData->pData = NULL;
  134. }
  135. m_pData->AllocLength = size;
  136. }
  137. template<class HEADER_T, class DATA_T>
  138. void ReferenceObject<HEADER_T,DATA_T>::InitHeader()
  139. {
  140. // NOTE: Derive this function to initialize the Header object(s)
  141. }
  142. template<class HEADER_T, class DATA_T>
  143. void ReferenceObject<HEADER_T,DATA_T>::FreeHeader()
  144. {
  145. // NOTE: Derive this function to clean up the Header object(s)
  146. }
  147. template<class HEADER_T, class DATA_T>
  148. void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite()
  149. {
  150. CopyForWrite(m_pData->AllocLength);
  151. }
  152. template<class HEADER_T, class DATA_T>
  153. void ReferenceObject<HEADER_T,DATA_T>::CopyForWrite(unsigned int size)
  154. {
  155. unsigned int oldsize = m_pData->AllocLength;
  156. if (size)
  157. {
  158. if ((m_pData->ReferenceCount > 1) || (size != oldsize))
  159. {
  160. ReferenceObjectBlock<HEADER_T,DATA_T>* pTmp = m_pData;
  161. AllocBlock(size);
  162. m_pData->Header = pTmp->Header;
  163. unsigned int sizetocopy = min(size,oldsize);
  164. // memcpy(m_pData->pData, pTmp->pData, min(size,oldsize) * sizeof(DATA_T)); // memcpy not safe for objects
  165. for (unsigned int x=0;x<sizetocopy;x++)
  166. {
  167. m_pData->pData[x] = pTmp->pData[x];
  168. }
  169. if (pTmp->ReferenceCount.dec() <= 0)
  170. {
  171. delete[] pTmp->pData;
  172. delete pTmp;
  173. }
  174. }
  175. }
  176. else // Replace reference to a null object (since size is zero)
  177. {
  178. Release();
  179. AllocHeader();
  180. InitHeader();
  181. }
  182. }
  183. template<class HEADER_T, class DATA_T>
  184. HEADER_T& ReferenceObject<HEADER_T,DATA_T>::getHeader()
  185. {
  186. CopyForWrite();
  187. return m_pData->Header;
  188. }
  189. template<class HEADER_T, class DATA_T>
  190. DATA_T* ReferenceObject<HEADER_T,DATA_T>::getData()
  191. {
  192. CopyForWrite();
  193. return m_pData->pData;
  194. }
  195. #endif // !defined(AFX_REFERENCEOBJECT_H__BAEBCE9D_CD68_40AF_8A54_B23A0D14E807__INCLUDED_)