blob.hpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef BLOB_HPP
00013 #define BLOB_HPP
00014
00015 #include "../core/alloc_func.hpp"
00016 #include "../core/mem_func.hpp"
00017 #include <new>
00018
00048 class CBlobBaseSimple {
00049 public:
00050 typedef ::ptrdiff_t bsize_t;
00051 typedef ::byte bitem_t;
00052
00053 protected:
00055 struct CHdr {
00056 bsize_t m_size;
00057 bsize_t m_max_size;
00058 };
00059
00061 union {
00062 bitem_t *m_pData;
00063 CHdr *m_pHdr_1;
00064 } ptr_u;
00065
00066 private:
00068 static const CHdr hdrEmpty[];
00069
00070 public:
00071 static const bsize_t Ttail_reserve = 4;
00072
00074 FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
00076 FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
00077 {
00078 InitEmpty();
00079 AppendRaw(p, num_bytes);
00080 }
00081
00083 FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
00084 {
00085 InitEmpty();
00086 AppendRaw(src);
00087 }
00088
00090 FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
00091 {
00092 assert(pHdr_1 != NULL);
00093 ptr_u.m_pHdr_1 = pHdr_1;
00094 *const_cast<CHdr**>(&pHdr_1) = NULL;
00095 }
00096
00098 FORCEINLINE ~CBlobBaseSimple()
00099 {
00100 Free();
00101 }
00102
00103 protected:
00106 FORCEINLINE void InitEmpty()
00107 {
00108 ptr_u.m_pHdr_1 = const_cast<CHdr *>(&CBlobBaseSimple::hdrEmpty[1]);
00109 }
00110
00112 FORCEINLINE void Init(CHdr *hdr)
00113 {
00114 ptr_u.m_pHdr_1 = &hdr[1];
00115 }
00116
00118 FORCEINLINE CHdr& Hdr()
00119 {
00120 return ptr_u.m_pHdr_1[-1];
00121 }
00122
00124 FORCEINLINE const CHdr& Hdr() const
00125 {
00126 return ptr_u.m_pHdr_1[-1];
00127 }
00128
00130 FORCEINLINE bsize_t& RawSizeRef()
00131 {
00132 return Hdr().m_size;
00133 };
00134
00135 public:
00137 FORCEINLINE bool IsEmpty() const
00138 {
00139 return RawSize() == 0;
00140 }
00141
00143 FORCEINLINE bsize_t RawSize() const
00144 {
00145 return Hdr().m_size;
00146 };
00147
00149 FORCEINLINE bsize_t MaxRawSize() const
00150 {
00151 return Hdr().m_max_size;
00152 };
00153
00155 FORCEINLINE bitem_t *RawData()
00156 {
00157 return ptr_u.m_pData;
00158 }
00159
00161 FORCEINLINE const bitem_t *RawData() const
00162 {
00163 return ptr_u.m_pData;
00164 }
00165
00167
00168
00169
00170
00171
00173 FORCEINLINE void Clear()
00174 {
00175 RawSizeRef() = 0;
00176 }
00177
00179 FORCEINLINE void Free()
00180 {
00181 if (MaxRawSize() > 0) {
00182 RawFree(&Hdr());
00183 InitEmpty();
00184 }
00185 }
00186
00188 FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
00189 {
00190 Clear();
00191 AppendRaw(src);
00192 }
00193
00195 FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
00196 {
00197 Free();
00198 ptr_u.m_pData = src.ptr_u.m_pData;
00199 src.InitEmpty();
00200 }
00201
00203 FORCEINLINE void Swap(CBlobBaseSimple& src)
00204 {
00205 bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
00206 src.ptr_u.m_pData = tmp;
00207 }
00208
00210 FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
00211 {
00212 assert(p != NULL);
00213 if (num_bytes > 0) {
00214 memcpy(GrowRawSize(num_bytes), p, num_bytes);
00215 } else {
00216 assert(num_bytes >= 0);
00217 }
00218 }
00219
00221 FORCEINLINE void AppendRaw(const CBlobBaseSimple& src)
00222 {
00223 if (!src.IsEmpty())
00224 memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
00225 }
00226
00229 FORCEINLINE bitem_t *MakeRawFreeSpace(bsize_t num_bytes)
00230 {
00231 assert(num_bytes >= 0);
00232 bsize_t new_size = RawSize() + num_bytes;
00233 if (new_size > MaxRawSize()) SmartAlloc(new_size);
00234 return ptr_u.m_pData + RawSize();
00235 }
00236
00239 FORCEINLINE bitem_t *GrowRawSize(bsize_t num_bytes)
00240 {
00241 bitem_t *pNewData = MakeRawFreeSpace(num_bytes);
00242 RawSizeRef() += num_bytes;
00243 return pNewData;
00244 }
00245
00247 FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
00248 {
00249 if (MaxRawSize() > 0 && num_bytes > 0) {
00250 assert(num_bytes <= RawSize());
00251 if (num_bytes < RawSize()) {
00252 RawSizeRef() -= num_bytes;
00253 } else {
00254 RawSizeRef() = 0;
00255 }
00256 }
00257 }
00258
00260 void SmartAlloc(bsize_t new_size)
00261 {
00262 bsize_t old_max_size = MaxRawSize();
00263 if (old_max_size >= new_size) return;
00264
00265 bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
00266
00267 bsize_t alloc_size = AllocPolicy(min_alloc_size);
00268
00269 CHdr *pNewHdr = RawAlloc(alloc_size);
00270
00271 pNewHdr->m_size = RawSize();
00272 pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
00273
00274 if (RawSize() > 0)
00275 memcpy(pNewHdr + 1, ptr_u.m_pData, pNewHdr->m_size);
00276
00277 CHdr *pOldHdr = &Hdr();
00278 Init(pNewHdr);
00279 if (old_max_size > 0)
00280 RawFree(pOldHdr);
00281 }
00282
00284 FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
00285 {
00286 if (min_alloc < (1 << 9)) {
00287 if (min_alloc < (1 << 5)) return (1 << 5);
00288 return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
00289 }
00290 if (min_alloc < (1 << 15)) {
00291 if (min_alloc < (1 << 11)) return (1 << 11);
00292 return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15);
00293 }
00294 if (min_alloc < (1 << 20)) {
00295 if (min_alloc < (1 << 17)) return (1 << 17);
00296 return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20);
00297 }
00298 min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
00299 return min_alloc;
00300 }
00301
00303 static FORCEINLINE CHdr *RawAlloc(bsize_t num_bytes)
00304 {
00305 return (CHdr*)MallocT<byte>(num_bytes);
00306 }
00307
00309 static FORCEINLINE void RawFree(CHdr *p)
00310 {
00311
00312 assert(p != CBlobBaseSimple::hdrEmpty);
00313
00314
00315 free(p);
00316 }
00318 FORCEINLINE void FixTail() const
00319 {
00320 if (MaxRawSize() > 0) {
00321 bitem_t *p = &ptr_u.m_pData[RawSize()];
00322 for (bsize_t i = 0; i < Ttail_reserve; i++) {
00323 p[i] = 0;
00324 }
00325 }
00326 }
00327 };
00328
00336 template <class Titem_, class Tbase_ = CBlobBaseSimple>
00337 class CBlobT : public Tbase_ {
00338
00339 public:
00340 typedef Titem_ Titem;
00341 typedef Tbase_ Tbase;
00342 typedef typename Tbase::bsize_t bsize_t;
00343
00344 static const bsize_t Titem_size = sizeof(Titem);
00345
00346 struct OnTransfer {
00347 typename Tbase_::CHdr *m_pHdr_1;
00348 OnTransfer(const OnTransfer& src) : m_pHdr_1(src.m_pHdr_1) {assert(src.m_pHdr_1 != NULL); *const_cast<typename Tbase_::CHdr**>(&src.m_pHdr_1) = NULL;}
00349 OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
00350 ~OnTransfer() {assert(m_pHdr_1 == NULL);}
00351 };
00352
00354 FORCEINLINE CBlobT()
00355 : Tbase()
00356 {}
00357
00359 FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
00360 : Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
00361 {}
00362
00364 FORCEINLINE CBlobT(const Tbase& src)
00365 : Tbase(src)
00366 {
00367 assert((Tbase::RawSize() % Titem_size) == 0);
00368 }
00369
00371 FORCEINLINE CBlobT(const OnTransfer& ot)
00372 : Tbase(ot.m_pHdr_1)
00373 {}
00374
00376 FORCEINLINE ~CBlobT()
00377 {
00378 Free();
00379 }
00380
00382 FORCEINLINE void CheckIdx(bsize_t idx) const
00383 {
00384 assert(idx >= 0); assert(idx < Size());
00385 }
00386
00388 FORCEINLINE Titem *Data()
00389 {
00390 return (Titem*)Tbase::RawData();
00391 }
00392
00394 FORCEINLINE const Titem *Data() const
00395 {
00396 return (const Titem*)Tbase::RawData();
00397 }
00398
00400 FORCEINLINE Titem *Data(bsize_t idx)
00401 {
00402 CheckIdx(idx);
00403 return (Data() + idx);
00404 }
00405
00407 FORCEINLINE const Titem *Data(bsize_t idx) const
00408 {
00409 CheckIdx(idx);
00410 return (Data() + idx);
00411 }
00412
00414 FORCEINLINE bsize_t Size() const
00415 {
00416 return (Tbase::RawSize() / Titem_size);
00417 }
00418
00420 FORCEINLINE bsize_t MaxSize() const
00421 {
00422 return (Tbase::MaxRawSize() / Titem_size);
00423 }
00425 FORCEINLINE bsize_t GetReserve() const
00426 {
00427 return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
00428 }
00429
00431 FORCEINLINE void Free()
00432 {
00433 assert((Tbase::RawSize() % Titem_size) == 0);
00434 bsize_t old_size = Size();
00435 if (old_size > 0) {
00436
00437 Titem *pI_last_to_destroy = Data(0);
00438 for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
00439 }
00440 Tbase::Free();
00441 }
00442
00444 FORCEINLINE Titem *GrowSizeNC(bsize_t num_items)
00445 {
00446 return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
00447 }
00448
00450 FORCEINLINE Titem *GrowSizeC(bsize_t num_items)
00451 {
00452 Titem *pI = GrowSizeNC(num_items);
00453 for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
00454 }
00455
00457 FORCEINLINE void ReduceSize(bsize_t num_items)
00458 {
00459 assert((Tbase::RawSize() % Titem_size) == 0);
00460 bsize_t old_size = Size();
00461 assert(num_items <= old_size);
00462 bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
00463
00464 Titem *pI_last_to_destroy = Data(new_size);
00465 for (Titem *pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
00466
00467 Tbase::ReduceRawSize(num_items * Titem_size);
00468 }
00469
00471 FORCEINLINE Titem *AppendNew()
00472 {
00473 Titem& dst = *GrowSizeNC(1);
00474 Titem *pNewItem = new (&dst) Titem();
00475 return pNewItem;
00476 }
00477
00479 FORCEINLINE Titem *Append(const Titem& src)
00480 {
00481 Titem& dst = *GrowSizeNC(1);
00482 Titem *pNewItem = new (&dst) Titem(src);
00483 return pNewItem;
00484 }
00485
00487 FORCEINLINE Titem *Append(const Titem *pSrc, bsize_t num_items)
00488 {
00489 Titem *pDst = GrowSizeNC(num_items);
00490 Titem *pDstOrg = pDst;
00491 Titem *pDstEnd = pDst + num_items;
00492 while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
00493 return pDstOrg;
00494 }
00495
00497 FORCEINLINE void RemoveBySwap(bsize_t idx)
00498 {
00499 CheckIdx(idx);
00500
00501 Titem *pRemoved = Data(idx);
00502 RemoveBySwap(pRemoved);
00503 }
00504
00506 FORCEINLINE void RemoveBySwap(Titem *pItem)
00507 {
00508 Titem *pLast = Data(Size() - 1);
00509 assert(pItem >= Data() && pItem <= pLast);
00510
00511 if (pItem != pLast) {
00512 pItem->~Titem_();
00513 new (pItem) Titem_(*pLast);
00514 }
00515
00516 pLast->~Titem_();
00517
00518 Tbase::ReduceRawSize(Titem_size);
00519 }
00520
00523 FORCEINLINE Titem *MakeFreeSpace(bsize_t num_items)
00524 {
00525 return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
00526 }
00527
00528 FORCEINLINE OnTransfer Transfer()
00529 {
00530 return OnTransfer(*this);
00531 };
00532 };
00533
00534
00535 #endif