// TmplBlockBuffer.cpp // #pragma once #ifndef ASSERT #include #define ASSERT assert #endif #include "TmplBlockBuffer.tlh" #define DataNull nullptr template TmplBlockBuffer ::TmplBlockBuffer () { Init (); } template TmplBlockBuffer ::~TmplBlockBuffer () { if (GetData () == DataNull) return; if (InterlockedDecrement (&GetData ()->nRefs) <= 0) { delete m_pMetaData; delete m_pObject; } } template void TmplBlockBuffer ::Init (void) { m_pObject = nullptr; m_pMetaData = (MetaData *) DataNull; } template TmplBlockBuffer ::TmplBlockBuffer (const TmplBlockBuffer & h) { Init (); ShadowCopyFrom (h); } template TmplBlockBuffer ::TmplBlockBuffer (TmplBlockBuffer && h) { Init (); MoveAssign (h); } // 从 h 构造一个新的对象, 但是我只要前面的 count 个字符 // 如果 count 比 h.nCount 大, 那就重新分配然后 memcpy template TmplBlockBuffer ::TmplBlockBuffer (TmplBlockBuffer && h, int count) { Init (); // 如果啥都不想要 if (count <= 0) return; // 如果源是 null if (h.GetData () == DataNull) { GetBufferSetCount (count); return; } // 如果要的很少 if (count <= h.GetData ()->nCount) { MoveAssign (h); ASSERT (m_pMetaData->nCount >= count); m_pMetaData->nCount = count; return; } // 如果要的太多了 { auto pDst = GetBufferSetCount (count); auto pSrc = h.As (); memcpy (pDst, pSrc, h.GetCount ()); h.Init (); return; } } template TmplBlockBuffer ::TmplBlockBuffer (T * object, int count) { Init (); Attach (object, count); } template void TmplBlockBuffer ::Attach (T * object, int count) { Release (); if (count <= 0) return; if (object == nullptr) return; m_pObject = object; m_pMetaData = new MetaData; m_pMetaData->nRefs = 1; m_pMetaData->nCount = count; } // 注意, 有可能无法 Detach 的, 因为对象可能被其他地方引用了 // 如果 Detach 失败, 数据不受影响 template T * TmplBlockBuffer ::Detach () { if (GetData () == DataNull) return nullptr; ASSERT (GetData ()->nRefs != 0); if (GetData ()->nRefs > 1) return nullptr; long nRef = InterlockedDecrement (&GetData ()->nRefs); ASSERT (nRef <= 0); if (nRef > 0) // 前面已经判断过, 因此不会出现减一后还大于 0 的情况. 以下代码只是以防万一 { Init (); // 前面既然已经减了 1, 我只好变成 Init 了 return NULL; } T * object = m_pObject; m_pObject = nullptr; delete m_pMetaData; m_pMetaData = nullptr; Init (); return object; } template void TmplBlockBuffer ::Release () { T * object = Detach (); delete object; Init (); } template void TmplBlockBuffer ::CopyFrom (const TmplBlockBuffer & h) { Release (); if (! h.m_pObject) return; int count = h.GetData ()->nCount; if (count <= 0) return; T * object = new T [count]; ASSERT (object); memcpy (object, h.m_pObject, sizeof (T) * count); Attach (object, count); } template void TmplBlockBuffer ::ShadowCopyFrom (const TmplBlockBuffer & h) { if (m_pObject == h.m_pObject) return; if (h.GetData () == DataNull) { Release (); return; } if (GetData () != DataNull) if (GetData ()->nRefs < 0) { CopyFrom (h); return; } if (h.GetData ()->nRefs < 0) { CopyFrom (h); return; } // else { // can just copy references around Release (); m_pObject = h.m_pObject; m_pMetaData = h.m_pMetaData; InterlockedIncrement (&GetData ()->nRefs); } } // 移动赋值 template TmplBlockBuffer & TmplBlockBuffer ::operator = (TmplBlockBuffer && Src) { MoveAssign (Src); return *this; } // 移动赋值 template void TmplBlockBuffer ::MoveAssign (TmplBlockBuffer & Src) { Release (); m_pObject = Src.m_pObject; m_pMetaData = Src.m_pMetaData; Src.Init (); } template T * TmplBlockBuffer ::GetBufferSetCount (int count) { Release (); if (count <= 0) return nullptr; T * object = new T [count]; ASSERT (object); Attach (object, count); return object; } template void TmplBlockBuffer ::CopyFrom (const T * from, int count) { Release (); if (count <= 0) return; if (! from) return; T * object = new T [count]; ASSERT (object); memcpy (object, from, sizeof (T) * count); Attach (object, count); } template void TmplBlockBuffer ::CopyTo (T * to, int count) const { if (count <= 0) return; if (! to) return; if (! m_pObject) return; memcpy (to, m_pObject, sizeof (T) * min (count, GetData ()->nCount)); } template TmplBlockBuffer & TmplBlockBuffer ::operator = (const TmplBlockBuffer & h) { ShadowCopyFrom (h); return *this; } template TmplBlockBuffer ::operator bool () const { return m_pObject; } template TmplBlockBuffer ::operator T * () { return m_pObject; } template TmplBlockBuffer ::operator const T * () const { return m_pObject; } template bool TmplBlockBuffer ::IsEmpty () const { return (m_pObject == nullptr); }