blob.hpp
Go to the documentation of this file.00001
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
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
00160
00161
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
00254 bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00255
00256 bsize_t alloc_size = AllocPolicy(min_alloc_size);
00257
00258 CHdr *pNewHdr = RawAlloc(alloc_size);
00259
00260 pNewHdr->m_size = RawSize();
00261 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00262
00263 if (RawSize() > 0)
00264 memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00265
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
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
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
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
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
00453 Tbase::ReduceRawSize(num_items * Titem_size);
00454 }
00455
00457 FORCEINLINE Titem *AppendNew()
00458 {
00459 Titem& dst = *GrowSizeNC(1);
00460 Titem *pNewItem = new (&dst) Titem();
00461 return pNewItem;
00462 }
00463
00465 FORCEINLINE Titem *Append(const Titem& src)
00466 {
00467 Titem& dst = *GrowSizeNC(1);
00468 Titem *pNewItem = new (&dst) Titem(src);
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
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
00497 if (pItem != pLast) {
00498 pItem->~Titem_();
00499 new (pItem) Titem_(*pLast);
00500 }
00501
00502 pLast->~Titem_();
00503
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