blob.hpp

Go to the documentation of this file.
00001 /* $Id: blob.hpp 17516 2009-09-12 20:44:12Z rubidium $ */
00002 
00005 #ifndef BLOB_HPP
00006 #define BLOB_HPP
00007 
00008 #include "../core/alloc_func.hpp"
00009 #include "../core/mem_func.hpp"
00010 
00040 class CBlobBaseSimple {
00041 public:
00042   typedef ::ptrdiff_t bsize_t;
00043   typedef ::byte      bitem_t;
00044 
00045 protected:
00047   struct CHdr {
00048     bsize_t    m_size;      
00049     bsize_t    m_max_size;  
00050   };
00051 
00053   union {
00054     bitem_t    *m_pData;    
00055 #if defined(HAS_WCHAR)
00056     wchar_t    *m_pwData;   
00057 #endif /* HAS_WCHAR */
00058     CHdr       *m_pHdr_1;   
00059   } ptr_u;
00060 
00061 public:
00062   static const bsize_t Ttail_reserve = 4; 
00063 
00065   FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
00067   FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
00068   {
00069     InitEmpty();
00070     AppendRaw(p, num_bytes);
00071   }
00072 
00074   FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
00075   {
00076     InitEmpty();
00077     AppendRaw(src);
00078   }
00079 
00081   FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
00082   {
00083     assert(pHdr_1 != NULL);
00084     ptr_u.m_pHdr_1 = pHdr_1;
00085     *(CHdr**)&pHdr_1 = NULL;
00086   }
00087 
00089   FORCEINLINE ~CBlobBaseSimple()
00090   {
00091     Free();
00092   }
00093 
00094 protected:
00097   FORCEINLINE void InitEmpty()
00098   {
00099     static CHdr hdrEmpty[] = {{0, 0}, {0, 0}};
00100     ptr_u.m_pHdr_1 = &hdrEmpty[1];
00101   }
00102 
00104   FORCEINLINE void Init(CHdr *hdr)
00105   {
00106     ptr_u.m_pHdr_1 = &hdr[1];
00107   }
00108 
00110   FORCEINLINE CHdr& Hdr()
00111   {
00112     return ptr_u.m_pHdr_1[-1];
00113   }
00114 
00116   FORCEINLINE const CHdr& Hdr() const
00117   {
00118     return ptr_u.m_pHdr_1[-1];
00119   }
00120 
00122   FORCEINLINE bsize_t& RawSizeRef()
00123   {
00124     return Hdr().m_size;
00125   };
00126 
00127 public:
00129   FORCEINLINE bool IsEmpty() const
00130   {
00131     return RawSize() == 0;
00132   }
00133 
00135   FORCEINLINE bsize_t RawSize() const
00136   {
00137     return Hdr().m_size;
00138   };
00139 
00141   FORCEINLINE bsize_t MaxRawSize() const
00142   {
00143     return Hdr().m_max_size;
00144   };
00145 
00147   FORCEINLINE bitem_t *RawData()
00148   {
00149     return ptr_u.m_pData;
00150   }
00151 
00153   FORCEINLINE const bitem_t *RawData() const
00154   {
00155     return ptr_u.m_pData;
00156   }
00157 
00159   //FORCEINLINE bsize_t Crc32() const
00160   //{
00161   //  return CCrc32::Calc(RawData(), RawSize());
00162   //}
00163 
00165   FORCEINLINE void Clear()
00166   {
00167     RawSizeRef() = 0;
00168   }
00169 
00171   FORCEINLINE void Free()
00172   {
00173     if (MaxRawSize() > 0) {
00174       RawFree(&Hdr());
00175       InitEmpty();
00176     }
00177   }
00178 
00180   FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00181   {
00182     Clear();
00183     AppendRaw(src);
00184   }
00185 
00187   FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00188   {
00189     Free();
00190     ptr_u.m_pData = src.ptr_u.m_pData;
00191     src.InitEmpty();
00192   }
00193 
00195   FORCEINLINE void Swap(CBlobBaseSimple& src)
00196   {
00197     bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00198     src.ptr_u.m_pData = tmp;
00199   }
00200 
00202   FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00203   {
00204     assert(p != NULL);
00205     if (num_bytes > 0) {
00206       memcpy(GrowRawSize(num_bytes), p, num_bytes);
00207     } else {
00208       assert(num_bytes >= 0);
00209     }
00210   }
00211 
00213   FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00214   {
00215     if (!src.IsEmpty())
00216       memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00217   }
00218 
00221   FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
00222   {
00223     assert(num_bytes >= 0);
00224     bsize_t new_size = RawSize() + num_bytes;
00225     if (new_size > MaxRawSize()) SmartAlloc(new_size);
00226     return ptr_u.m_pData + RawSize();
00227   }
00228 
00231   FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
00232   {
00233     bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
00234     RawSizeRef() += num_bytes;
00235     return pNewData;
00236   }
00237 
00239   FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00240   {
00241     if (MaxRawSize() > 0 && num_bytes > 0) {
00242       assert(num_bytes <= RawSize());
00243       if (num_bytes < RawSize()) RawSizeRef() -= num_bytes;
00244       else RawSizeRef() = 0;
00245     }
00246   }
00247 
00249   void SmartAlloc(bsize_t new_size)
00250   {
00251     bsize_t old_max_size = MaxRawSize();
00252     if (old_max_size >= new_size) return;
00253     /* calculate minimum block size we need to allocate */
00254     bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00255     /* ask allocation policy for some reasonable block size */
00256     bsize_t alloc_size = AllocPolicy(min_alloc_size);
00257     /* allocate new block */
00258     CHdr *pNewHdr = RawAlloc(alloc_size);
00259     /* setup header */
00260     pNewHdr->m_size = RawSize();
00261     pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00262     /* copy existing data */
00263     if (RawSize() > 0)
00264       memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00265     /* replace our block with new one */
00266     CHdr *pOldHdr = &Hdr();
00267     Init(pNewHdr);
00268     if (old_max_size > 0)
00269       RawFree(pOldHdr);
00270   }
00271 
00273   FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00274   {
00275     if (min_alloc < (1 << 9)) {
00276       if (min_alloc < (1 << 5)) return (1 << 5);
00277       return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00278     }
00279     if (min_alloc < (1 << 15)) {
00280       if (min_alloc < (1 << 11)) return (1 << 11);
00281       return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00282     }
00283     if (min_alloc < (1 << 20)) {
00284       if (min_alloc < (1 << 17)) return (1 << 17);
00285       return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00286     }
00287     min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00288     return min_alloc;
00289   }
00290 
00292   static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
00293   {
00294     return (CHdr*)MallocT<byte>(num_bytes);
00295   }
00296 
00298   static FORCEINLINE void RawFree(CHdr *p)
00299   {
00300     /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */
00301     free(p);
00302   }
00304   FORCEINLINE void FixTail() const
00305   {
00306     if (MaxRawSize() > 0) {
00307       bitem_t *p = &ptr_u.m_pData[RawSize()];
00308       for (bsize_t i = 0; i < Ttail_reserve; i++) {
00309         p[i] = 0;
00310       }
00311     }
00312   }
00313 };
00314 
00322 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00323 class CBlobT : public Tbase_ {
00324   /* make template arguments public: */
00325 public:
00326   typedef Titem_ Titem;
00327   typedef Tbase_ Tbase;
00328   typedef typename Tbase::bsize_t bsize_t;
00329 
00330   static const bsize_t Titem_size = sizeof(Titem);
00331 
00332   struct OnTransfer {
00333     typename Tbase_::CHdr *m_pHdr_1;
00334     OnTransfer(const OnTransfer& src) : m_pHdr_1(src.m_pHdr_1) {assert(src.m_pHdr_1 != NULL); *(typename Tbase_::CHdr**)&src.m_pHdr_1 = NULL;}
00335     OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00336     ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00337   };
00338 
00340   FORCEINLINE CBlobT()
00341     : Tbase()
00342   {}
00343 
00345   FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00346     : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00347   {}
00348 
00350   FORCEINLINE CBlobT(const Tbase& src)
00351     : Tbase(src)
00352   {
00353     assert((Tbase::RawSize() % Titem_size) == 0);
00354   }
00355 
00357   FORCEINLINE CBlobT(const OnTransfer& ot)
00358     : Tbase(ot.m_pHdr_1)
00359   {}
00360 
00362   FORCEINLINE ~CBlobT()
00363   {
00364     Free();
00365   }
00366 
00368   FORCEINLINE void CheckIdx(bsize_t idx) const
00369   {
00370     assert(idx >= 0); assert(idx < Size());
00371   }
00372 
00374   FORCEINLINE Titem *Data()
00375   {
00376     return (Titem*)Tbase::RawData();
00377   }
00378 
00380   FORCEINLINE const Titem *Data() const
00381   {
00382     return (const Titem*)Tbase::RawData();
00383   }
00384 
00386   FORCEINLINE Titem *Data(bsize_t idx)
00387   {
00388     CheckIdx(idx);
00389     return (Data() + idx);
00390   }
00391 
00393   FORCEINLINE const Titem *Data(bsize_t idx) const
00394   {
00395     CheckIdx(idx);
00396     return (Data() + idx);
00397   }
00398 
00400   FORCEINLINE bsize_t Size() const
00401   {
00402     return (Tbase::RawSize() / Titem_size);
00403   }
00404 
00406   FORCEINLINE bsize_t MaxSize() const
00407   {
00408     return (Tbase::MaxRawSize() / Titem_size);
00409   }
00411   FORCEINLINE bsize_t GetReserve() const
00412   {
00413     return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00414   }
00415 
00417   FORCEINLINE void Free()
00418   {
00419     assert((Tbase::RawSize() % Titem_size) == 0);
00420     bsize_t old_size = Size();
00421     if (old_size > 0) {
00422       /* destroy removed items; */
00423       Titem *pI_last_to_destroy = Data(0);
00424       for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00425     }
00426     Tbase::Free();
00427   }
00428 
00430   FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
00431   {
00432     return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00433   }
00434 
00436   FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
00437   {
00438     Titem *pI = GrowSizeNC(num_items);
00439     for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00440   }
00441 
00443   FORCEINLINE void ReduceSize(bsize_t num_items)
00444   {
00445     assert((Tbase::RawSize() % Titem_size) == 0);
00446     bsize_t old_size = Size();
00447     assert(num_items <= old_size);
00448     bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00449     /* destroy removed items; */
00450     Titem *pI_last_to_destroy = Data(new_size);
00451     for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00452     /* remove them */
00453     Tbase::ReduceRawSize(num_items * Titem_size);
00454   }
00455 
00457   FORCEINLINE Titem *AppendNew()
00458   {
00459     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00460     Titem *pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
00461     return pNewItem;
00462   }
00463 
00465   FORCEINLINE Titem *Append(const Titem& src)
00466   {
00467     Titem& dst = *GrowSizeNC(1); // Grow size by one item
00468     Titem *pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
00469     return pNewItem;
00470   }
00471 
00473   FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
00474   {
00475     Titem *pDst = GrowSizeNC(num_items);
00476     Titem *pDstOrg = pDst;
00477     Titem *pDstEnd = pDst + num_items;
00478     while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00479     return pDstOrg;
00480   }
00481 
00483   FORCEINLINE void RemoveBySwap(bsize_t idx)
00484   {
00485     CheckIdx(idx);
00486     /* destroy removed item */
00487     Titem *pRemoved = Data(idx);
00488     RemoveBySwap(pRemoved);
00489   }
00490 
00492   FORCEINLINE void RemoveBySwap(Titem *pItem)
00493   {
00494     Titem *pLast = Data(Size() - 1);
00495     assert(pItem >= Data() && pItem <= pLast);
00496     /* move last item to its new place */
00497     if (pItem != pLast) {
00498       pItem->~Titem_();
00499       new (pItem) Titem_(*pLast);
00500     }
00501     /* destroy the last item */
00502     pLast->~Titem_();
00503     /* and reduce the raw blob size */
00504     Tbase::ReduceRawSize(Titem_size);
00505   }
00506 
00509   FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
00510   {
00511     return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00512   }
00513 
00514   FORCEINLINE OnTransfer Transfer()
00515   {
00516     return OnTransfer(*this);
00517   };
00518 };
00519 
00520 
00521 #endif /* BLOB_HPP */

Generated on Mon Dec 14 20:59:59 2009 for OpenTTD by  doxygen 1.5.6