src/misc/blob.hpp
branchnoai
changeset 9631 8a2d1c2ceb88
parent 9601 b499fdd106d5
child 6725 23339968083f
equal deleted inserted replaced
9630:550db5cefcc2 9631:8a2d1c2ceb88
    13 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1)
    13 FORCEINLINE void MemCpyT(Titem_* d, const Titem_* s, int num_items = 1)
    14 {
    14 {
    15 	memcpy(d, s, num_items * sizeof(Titem_));
    15 	memcpy(d, s, num_items * sizeof(Titem_));
    16 }
    16 }
    17 
    17 
    18 
       
    19 /** Base class for simple binary blobs.
    18 /** Base class for simple binary blobs.
    20  *  Item is byte.
    19 *  Item is byte.
    21  *  The word 'simple' means:
    20 *  The word 'simple' means:
    22  *    - no configurable allocator type (always made from heap)
    21 *    - no configurable allocator type (always made from heap)
    23  *    - no smart deallocation - deallocation must be called from the same
    22 *    - no smart deallocation - deallocation must be called from the same
    24  *        module (DLL) where the blob was allocated
    23 *        module (DLL) where the blob was allocated
    25  *    - no configurable allocation policy (how big blocks should be allocated)
    24 *    - no configurable allocation policy (how big blocks should be allocated)
    26  *    - no extra ownership policy (i.e. 'copy on write') when blob is copied
    25 *    - no extra ownership policy (i.e. 'copy on write') when blob is copied
    27  *    - no thread synchronization at all
    26 *    - no thread synchronization at all
    28  *
    27 *
    29  *  Internal member layout:
    28 *  Internal member layout:
    30  *  1. The only class member is pointer to the first item (see union ptr_u).
    29 *  1. The only class member is pointer to the first item (see union ptr_u).
    31  *  2. Allocated block contains the blob header (see CHdr) followed by the raw byte data.
    30 *  2. Allocated block contains the blob header (see CHdr) followed by the raw byte data.
    32  *     Always, when it allocates memory the allocated size is:
    31 *     Always, when it allocates memory the allocated size is:
    33  *                                                      sizeof(CHdr) + <data capacity>
    32 *                                                      sizeof(CHdr) + <data capacity>
    34  *  3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning
    33 *  3. Two 'virtual' members (m_size and m_max_size) are stored in the CHdr at beginning
    35  *     of the alloated block.
    34 *     of the alloated block.
    36  *  4. The pointer (in ptr_u) points behind the header (to the first data byte).
    35 *  4. The pointter (in ptr_u) pobsize_ts behind the header (to the first data byte).
    37  *     When memory block is allocated, the sizeof(CHdr) it added to it.
    36 *     When memory block is allocated, the sizeof(CHdr) it added to it.
    38  *  5. Benefits of this layout:
    37 *  5. Benefits of this layout:
    39  *     - items are accessed in the simplest possible way - just dereferencing the pointer,
    38 *     - items are accessed in the simplest possible way - just dereferencing the pointer,
    40  *       which is good for performance (assuming that data are accessed most often).
    39 *       which is good for performance (assuming that data are accessed most often).
    41  *     - sizeof(blob) is the same as the size of any other pointer
    40 *     - sizeof(blob) is the same as the size of any other pointer
    42  *  6. Drawbacks of this layout:
    41 *  6. Drawbacks of this layout:
    43  *     - the fact, that pointer to the alocated block is adjusted by sizeof(CHdr) before
    42 *     - the fact, that pointer to the alocated block is adjusted by sizeof(CHdr) before
    44  *       it is stored can lead to several confusions:
    43 *       it is stored can lead to several confusions:
    45  *         - it is not common pattern so the implementation code is bit harder to read
    44 *         - it is not common pattern so the implementation code is bit harder to read
    46  *         - valgrind can generate warning that allocated block is lost (not accessible)
    45 *         - valgrind can generate warning that allocated block is lost (not accessible)
    47  * */
    46 * */
    48 class CBlobBaseSimple {
    47 class CBlobBaseSimple {
       
    48 public:
       
    49 	typedef ::ptrdiff_t bsize_t;
       
    50 	typedef ::byte      bitem_t;
       
    51 
    49 protected:
    52 protected:
    50 	/** header of the allocated memory block */
    53 	/** header of the allocated memory block */
    51 	struct CHdr {
    54 	struct CHdr {
    52 		int    m_size;      ///< actual blob size in bytes
    55 		bsize_t    m_size;      ///< actual blob size in bytes
    53 		int    m_max_size;  ///< maximum (allocated) size in bytes
    56 		bsize_t    m_max_size;  ///< maximum (allocated) size in bytes
    54 	};
    57 	};
    55 
    58 
    56 	/** type used as class member */
    59 	/** type used as class member */
    57 	union {
    60 	union {
    58 		int8   *m_pData;    ///< pointer to the first byte of data
    61 		bitem_t    *m_pData;    ///< ptr to the first byte of data
    59 		CHdr   *m_pHdr_1;   ///< pointer just after the CHdr holding m_size and m_max_size
    62 		wchar_t    *m_pwData;   ///< ptr to the first byte of data
       
    63 		CHdr       *m_pHdr_1;   ///< ptr just after the CHdr holding m_size and m_max_size
    60 	} ptr_u;
    64 	} ptr_u;
    61 
    65 
    62 public:
    66 public:
    63 	static const int Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end
    67 	static const bsize_t Ttail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end
    64 
    68 
    65 	/** default constructor - initializes empty blob */
    69 	/** default constructor - initializes empty blob */
    66 	FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
    70 	FORCEINLINE CBlobBaseSimple() { InitEmpty(); }
       
    71 	/** constructor - create blob with data */
       
    72 	FORCEINLINE CBlobBaseSimple(const bitem_t *p, bsize_t num_bytes)
       
    73 	{
       
    74 		InitEmpty();
       
    75 		AppendRaw(p, num_bytes);
       
    76 	}
       
    77 
    67 	/** copy constructor */
    78 	/** copy constructor */
    68 	FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
    79 	FORCEINLINE CBlobBaseSimple(const CBlobBaseSimple& src)
    69 	{
    80 	{
    70 		InitEmpty();
    81 		InitEmpty();
    71 		AppendRaw(src);
    82 		AppendRaw(src);
    72 	}
    83 	}
       
    84 
       
    85 	/** move constructor - take ownership of blob data */
       
    86 	FORCEINLINE CBlobBaseSimple(CHdr * const & pHdr_1)
       
    87 	{
       
    88 		assert(pHdr_1 != NULL);
       
    89 		ptr_u.m_pHdr_1 = pHdr_1;
       
    90 		*(CHdr**)&pHdr_1 = NULL;
       
    91 	}
       
    92 
    73 	/** destructor */
    93 	/** destructor */
    74 	FORCEINLINE ~CBlobBaseSimple() { Free(); }
    94 	FORCEINLINE ~CBlobBaseSimple()
       
    95 	{
       
    96 		Free();
       
    97 	}
       
    98 
    75 protected:
    99 protected:
    76 	/** initialize the empty blob by setting the ptr_u.m_pHdr_1 pointer to the static CHdr with
   100 	/** initialize the empty blob by setting the ptr_u.m_pHdr_1 pointer to the static CHdr with
    77 	 *  both m_size and m_max_size containing zero */
   101 	*  both m_size and m_max_size containing zero */
    78 	FORCEINLINE void InitEmpty() { static CHdr hdrEmpty[] = {{0, 0}, {0, 0}}; ptr_u.m_pHdr_1 = &hdrEmpty[1]; }
   102 	FORCEINLINE void InitEmpty()
       
   103 	{
       
   104 		static CHdr hdrEmpty[] = {{0, 0}, {0, 0}};
       
   105 		ptr_u.m_pHdr_1 = &hdrEmpty[1];
       
   106 	}
       
   107 
    79 	/** initialize blob by attaching it to the given header followed by data */
   108 	/** initialize blob by attaching it to the given header followed by data */
    80 	FORCEINLINE void Init(CHdr* hdr) { ptr_u.m_pHdr_1 = &hdr[1]; }
   109 	FORCEINLINE void Init(CHdr* hdr)
       
   110 	{
       
   111 		ptr_u.m_pHdr_1 = &hdr[1];
       
   112 	}
       
   113 
    81 	/** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */
   114 	/** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */
    82 	FORCEINLINE CHdr& Hdr() { return ptr_u.m_pHdr_1[-1]; }
   115 	FORCEINLINE CHdr& Hdr()
       
   116 	{
       
   117 		return ptr_u.m_pHdr_1[-1];
       
   118 	}
       
   119 
    83 	/** blob header accessor - use it rather than using the pointer arithmetics directly - const version */
   120 	/** blob header accessor - use it rather than using the pointer arithmetics directly - const version */
    84 	FORCEINLINE const CHdr& Hdr() const { return ptr_u.m_pHdr_1[-1]; }
   121 	FORCEINLINE const CHdr& Hdr() const
       
   122 	{
       
   123 		return ptr_u.m_pHdr_1[-1];
       
   124 	}
       
   125 
    85 	/** return reference to the actual blob size - used when the size needs to be modified */
   126 	/** return reference to the actual blob size - used when the size needs to be modified */
    86 	FORCEINLINE int& RawSizeRef() { return Hdr().m_size; };
   127 	FORCEINLINE bsize_t& RawSizeRef()
       
   128 	{
       
   129 		return Hdr().m_size;
       
   130 	};
    87 
   131 
    88 public:
   132 public:
    89 	/** return true if blob doesn't contain valid data */
   133 	/** return true if blob doesn't contain valid data */
    90 	FORCEINLINE bool IsEmpty() const { return RawSize() == 0; }
   134 	FORCEINLINE bool IsEmpty() const
       
   135 	{
       
   136 		return RawSize() == 0;
       
   137 	}
       
   138 
    91 	/** return the number of valid data bytes in the blob */
   139 	/** return the number of valid data bytes in the blob */
    92 	FORCEINLINE int RawSize() const { return Hdr().m_size; };
   140 	FORCEINLINE bsize_t RawSize() const
       
   141 	{
       
   142 		return Hdr().m_size;
       
   143 	};
       
   144 
    93 	/** return the current blob capacity in bytes */
   145 	/** return the current blob capacity in bytes */
    94 	FORCEINLINE int MaxRawSize() const { return Hdr().m_max_size; };
   146 	FORCEINLINE bsize_t MaxRawSize() const
       
   147 	{
       
   148 		return Hdr().m_max_size;
       
   149 	};
       
   150 
    95 	/** return pointer to the first byte of data - non-const version */
   151 	/** return pointer to the first byte of data - non-const version */
    96 	FORCEINLINE int8* RawData() { return ptr_u.m_pData; }
   152 	FORCEINLINE bitem_t* RawData()
       
   153 	{
       
   154 		return ptr_u.m_pData;
       
   155 	}
       
   156 
    97 	/** return pointer to the first byte of data - const version */
   157 	/** return pointer to the first byte of data - const version */
    98 	FORCEINLINE const int8* RawData() const { return ptr_u.m_pData; }
   158 	FORCEINLINE const bitem_t* RawData() const
    99 #if 0 // reenable when needed
   159 	{
       
   160 		return ptr_u.m_pData;
       
   161 	}
       
   162 
   100 	/** return the 32 bit CRC of valid data in the blob */
   163 	/** return the 32 bit CRC of valid data in the blob */
   101 	FORCEINLINE uint32 Crc32() const {return CCrc32::Calc(RawData(), RawSize());}
   164 	//FORCEINLINE bsize_t Crc32() const
   102 #endif //0
   165 	//{
       
   166 	//	return CCrc32::Calc(RawData(), RawSize());
       
   167 	//}
       
   168 
   103 	/** invalidate blob's data - doesn't free buffer */
   169 	/** invalidate blob's data - doesn't free buffer */
   104 	FORCEINLINE void Clear() { RawSizeRef() = 0; }
   170 	FORCEINLINE void Clear()
       
   171 	{
       
   172 		RawSizeRef() = 0;
       
   173 	}
       
   174 
   105 	/** free the blob's memory */
   175 	/** free the blob's memory */
   106 	FORCEINLINE void Free() { if (MaxRawSize() > 0) {RawFree(&Hdr()); InitEmpty();} }
   176 	FORCEINLINE void Free()
       
   177 	{
       
   178 		if (MaxRawSize() > 0) {
       
   179 			RawFree(&Hdr());
       
   180 			InitEmpty();
       
   181 		}
       
   182 	}
       
   183 
   107 	/** copy data from another blob - replaces any existing blob's data */
   184 	/** copy data from another blob - replaces any existing blob's data */
   108 	FORCEINLINE void CopyFrom(const CBlobBaseSimple& src) { Clear(); AppendRaw(src); }
   185 	FORCEINLINE void CopyFrom(const CBlobBaseSimple& src)
       
   186 	{
       
   187 		Clear();
       
   188 		AppendRaw(src);
       
   189 	}
       
   190 
   109 	/** overtake ownership of data buffer from the source blob - source blob will become empty */
   191 	/** overtake ownership of data buffer from the source blob - source blob will become empty */
   110 	FORCEINLINE void MoveFrom(CBlobBaseSimple& src) { Free(); ptr_u.m_pData = src.ptr_u.m_pData; src.InitEmpty(); }
   192 	FORCEINLINE void MoveFrom(CBlobBaseSimple& src)
       
   193 	{
       
   194 		Free();
       
   195 		ptr_u.m_pData = src.ptr_u.m_pData;
       
   196 		src.InitEmpty();
       
   197 	}
       
   198 
   111 	/** swap buffers (with data) between two blobs (this and source blob) */
   199 	/** swap buffers (with data) between two blobs (this and source blob) */
   112 	FORCEINLINE void Swap(CBlobBaseSimple& src) { int8 *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData; src.ptr_u.m_pData = tmp; }
   200 	FORCEINLINE void Swap(CBlobBaseSimple& src)
       
   201 	{
       
   202 		bitem_t *tmp = ptr_u.m_pData; ptr_u.m_pData = src.ptr_u.m_pData;
       
   203 		src.ptr_u.m_pData = tmp;
       
   204 	}
   113 
   205 
   114 	/** append new bytes at the end of existing data bytes - reallocates if necessary */
   206 	/** append new bytes at the end of existing data bytes - reallocates if necessary */
   115 	FORCEINLINE void AppendRaw(int8 *p, int num_bytes)
   207 	FORCEINLINE void AppendRaw(const void *p, bsize_t num_bytes)
   116 	{
   208 	{
   117 		assert(p != NULL);
   209 		assert(p != NULL);
   118 		if (num_bytes > 0) {
   210 		if (num_bytes > 0) {
   119 			memcpy(GrowRawSize(num_bytes), p, num_bytes);
   211 			memcpy(GrowRawSize(num_bytes), p, num_bytes);
   120 		} else {
   212 		} else {
   128 		if (!src.IsEmpty())
   220 		if (!src.IsEmpty())
   129 			memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
   221 			memcpy(GrowRawSize(src.RawSize()), src.RawData(), src.RawSize());
   130 	}
   222 	}
   131 
   223 
   132 	/** Reallocate if there is no free space for num_bytes bytes.
   224 	/** Reallocate if there is no free space for num_bytes bytes.
   133 	 *  @return pointer to the new data to be added */
   225 	*  @return pointer to the new data to be added */
   134 	FORCEINLINE int8* MakeRawFreeSpace(int num_bytes)
   226 	FORCEINLINE bitem_t* MakeRawFreeSpace(bsize_t num_bytes)
   135 	{
   227 	{
   136 		assert(num_bytes >= 0);
   228 		assert(num_bytes >= 0);
   137 		int new_size = RawSize() + num_bytes;
   229 		bsize_t new_size = RawSize() + num_bytes;
   138 		if (new_size > MaxRawSize()) SmartAlloc(new_size);
   230 		if (new_size > MaxRawSize()) SmartAlloc(new_size);
   139 		FixTail();
       
   140 		return ptr_u.m_pData + RawSize();
   231 		return ptr_u.m_pData + RawSize();
   141 	}
   232 	}
   142 
   233 
   143 	/** Increase RawSize() by num_bytes.
   234 	/** Increase RawSize() by num_bytes.
   144 	 *  @return pointer to the new data added */
   235 	*  @return pointer to the new data added */
   145 	FORCEINLINE int8* GrowRawSize(int num_bytes)
   236 	FORCEINLINE bitem_t* GrowRawSize(bsize_t num_bytes)
   146 	{
   237 	{
   147 		int8* pNewData = MakeRawFreeSpace(num_bytes);
   238 		bitem_t* pNewData = MakeRawFreeSpace(num_bytes);
   148 		RawSizeRef() += num_bytes;
   239 		RawSizeRef() += num_bytes;
   149 		return pNewData;
   240 		return pNewData;
   150 	}
   241 	}
   151 
   242 
   152 	/** Decrease RawSize() by num_bytes. */
   243 	/** Decrease RawSize() by num_bytes. */
   153 	FORCEINLINE void ReduceRawSize(int num_bytes)
   244 	FORCEINLINE void ReduceRawSize(bsize_t num_bytes)
   154 	{
   245 	{
   155 		if (MaxRawSize() > 0 && num_bytes > 0) {
   246 		if (MaxRawSize() > 0 && num_bytes > 0) {
   156 			assert(num_bytes <= RawSize());
   247 			assert(num_bytes <= RawSize());
   157 			if (num_bytes < RawSize()) RawSizeRef() -= num_bytes;
   248 			if (num_bytes < RawSize()) RawSizeRef() -= num_bytes;
   158 			else RawSizeRef() = 0;
   249 			else RawSizeRef() = 0;
   159 		}
   250 		}
   160 	}
   251 	}
       
   252 
   161 	/** reallocate blob data if needed */
   253 	/** reallocate blob data if needed */
   162 	void SmartAlloc(int new_size)
   254 	void SmartAlloc(bsize_t new_size)
   163 	{
   255 	{
   164 		int old_max_size = MaxRawSize();
   256 		bsize_t old_max_size = MaxRawSize();
   165 		if (old_max_size >= new_size) return;
   257 		if (old_max_size >= new_size) return;
   166 		// calculate minimum block size we need to allocate
   258 		// calculate minimum block size we need to allocate
   167 		int min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
   259 		bsize_t min_alloc_size = sizeof(CHdr) + new_size + Ttail_reserve;
   168 		// ask allocation policy for some reasonable block size
   260 		// ask allocation policy for some reasonable block size
   169 		int alloc_size = AllocPolicy(min_alloc_size);
   261 		bsize_t alloc_size = AllocPolicy(min_alloc_size);
   170 		// allocate new block
   262 		// allocate new block
   171 		CHdr* pNewHdr = RawAlloc(alloc_size);
   263 		CHdr* pNewHdr = RawAlloc(alloc_size);
   172 		// setup header
   264 		// setup header
   173 		pNewHdr->m_size = RawSize();
   265 		pNewHdr->m_size = RawSize();
   174 		pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
   266 		pNewHdr->m_max_size = alloc_size - (sizeof(CHdr) + Ttail_reserve);
   179 		CHdr* pOldHdr = &Hdr();
   271 		CHdr* pOldHdr = &Hdr();
   180 		Init(pNewHdr);
   272 		Init(pNewHdr);
   181 		if (old_max_size > 0)
   273 		if (old_max_size > 0)
   182 			RawFree(pOldHdr);
   274 			RawFree(pOldHdr);
   183 	}
   275 	}
       
   276 
   184 	/** simple allocation policy - can be optimized later */
   277 	/** simple allocation policy - can be optimized later */
   185 	FORCEINLINE static int AllocPolicy(int min_alloc)
   278 	FORCEINLINE static bsize_t AllocPolicy(bsize_t min_alloc)
   186 	{
   279 	{
   187 		if (min_alloc < (1 << 9)) {
   280 		if (min_alloc < (1 << 9)) {
   188 			if (min_alloc < (1 << 5)) return (1 << 5);
   281 			if (min_alloc < (1 << 5)) return (1 << 5);
   189 			return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
   282 			return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9);
   190 		}
   283 		}
   199 		min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
   292 		min_alloc = (min_alloc | ((1 << 20) - 1)) + 1;
   200 		return min_alloc;
   293 		return min_alloc;
   201 	}
   294 	}
   202 
   295 
   203 	/** all allocation should happen here */
   296 	/** all allocation should happen here */
   204 	static FORCEINLINE CHdr* RawAlloc(int num_bytes) { return (CHdr*)malloc(num_bytes); }
   297 	static FORCEINLINE CHdr* RawAlloc(bsize_t num_bytes)
       
   298 	{
       
   299 		return (CHdr*)malloc(num_bytes);
       
   300 	}
       
   301 
   205 	/** all deallocations should happen here */
   302 	/** all deallocations should happen here */
   206 	static FORCEINLINE void RawFree(CHdr* p) { free(p); }
   303 	static FORCEINLINE void RawFree(CHdr* p)
       
   304 	{
       
   305 		free(p);
       
   306 	}
   207 	/** fixing the four bytes at the end of blob data - useful when blob is used to hold string */
   307 	/** fixing the four bytes at the end of blob data - useful when blob is used to hold string */
   208 	FORCEINLINE void FixTail()
   308 	FORCEINLINE void FixTail() const
   209 	{
   309 	{
   210 		if (MaxRawSize() > 0) {
   310 		if (MaxRawSize() > 0) {
   211 			int8 *p = &ptr_u.m_pData[RawSize()];
   311 			bitem_t *p = &ptr_u.m_pData[RawSize()];
   212 			for (int i = 0; i < Ttail_reserve; i++) p[i] = 0;
   312 			for (bsize_t i = 0; i < Ttail_reserve; i++) {
       
   313 				p[i] = 0;
       
   314 			}
   213 		}
   315 		}
   214 	}
   316 	}
   215 };
   317 };
   216 
   318 
   217 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type.
   319 /** Blob - simple dynamic Titem_ array. Titem_ (template argument) is a placeholder for any type.
   218  *  Titem_ can be any integral type, pointer, or structure. Using Blob instead of just plain C array
   320 *  Titem_ can be any integral type, pointer, or structure. Using Blob instead of just plain C array
   219  *  simplifies the resource management in several ways:
   321 *  simplifies the resource management in several ways:
   220  *  1. When adding new item(s) it automatically grows capacity if needed.
   322 *  1. When adding new item(s) it automatically grows capacity if needed.
   221  *  2. When variable of type Blob comes out of scope it automatically frees the data buffer.
   323 *  2. When variable of type Blob comes out of scope it automatically frees the data buffer.
   222  *  3. Takes care about the actual data size (number of used items).
   324 *  3. Takes care about the actual data size (number of used items).
   223  *  4. Dynamically constructs only used items (as opposite of static array which constructs all items) */
   325 *  4. Dynamically constructs only used items (as opposite of static array which constructs all items) */
   224 template <class Titem_, class Tbase_ = CBlobBaseSimple>
   326 template <class Titem_, class Tbase_ = CBlobBaseSimple>
   225 class CBlobT : public CBlobBaseSimple {
   327 class CBlobT : public Tbase_ {
   226 	// make template arguments public:
   328 	// make template arguments public:
   227 public:
   329 public:
   228 	typedef Titem_ Titem;
   330 	typedef Titem_ Titem;
   229 	typedef Tbase_ Tbase;
   331 	typedef Tbase_ Tbase;
   230 
   332 	typedef typename Tbase::bsize_t bsize_t;
   231 	static const int Titem_size = sizeof(Titem);
   333 
       
   334 	static const bsize_t Titem_size = sizeof(Titem);
       
   335 
       
   336 	struct OnTransfer {
       
   337 		typename Tbase_::CHdr *m_pHdr_1;
       
   338 		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;}
       
   339 		OnTransfer(CBlobT& src) : m_pHdr_1(src.ptr_u.m_pHdr_1) {src.InitEmpty();}
       
   340 		~OnTransfer() {assert(m_pHdr_1 == NULL);}
       
   341 	};
   232 
   342 
   233 	/** Default constructor - makes new Blob ready to accept any data */
   343 	/** Default constructor - makes new Blob ready to accept any data */
   234 	FORCEINLINE CBlobT() : Tbase() {}
   344 	FORCEINLINE CBlobT()
       
   345 		: Tbase()
       
   346 	{}
       
   347 
       
   348 	/** Constructor - makes new Blob with data */
       
   349 	FORCEINLINE CBlobT(const Titem_ *p, bsize_t num_items)
       
   350 		: Tbase((typename Tbase_::bitem_t*)p, num_items * Titem_size)
       
   351 	{}
       
   352 
   235 	/** Copy constructor - make new blob to become copy of the original (source) blob */
   353 	/** Copy constructor - make new blob to become copy of the original (source) blob */
   236 	FORCEINLINE CBlobT(const Tbase& src) : Tbase(src) {assert((RawSize() % Titem_size) == 0);}
   354 	FORCEINLINE CBlobT(const Tbase& src)
       
   355 		: Tbase(src)
       
   356 	{
       
   357 		assert((Tbase::RawSize() % Titem_size) == 0);
       
   358 	}
       
   359 
       
   360 	/** Take ownership constructor */
       
   361 	FORCEINLINE CBlobT(const OnTransfer& ot)
       
   362 		: Tbase(ot.m_pHdr_1)
       
   363 	{}
       
   364 
   237 	/** Destructor - ensures that allocated memory (if any) is freed */
   365 	/** Destructor - ensures that allocated memory (if any) is freed */
   238 	FORCEINLINE ~CBlobT() { Free(); }
   366 	FORCEINLINE ~CBlobT()
       
   367 	{
       
   368 		Free();
       
   369 	}
       
   370 
   239 	/** Check the validity of item index (only in debug mode) */
   371 	/** Check the validity of item index (only in debug mode) */
   240 	FORCEINLINE void CheckIdx(int idx) { assert(idx >= 0); assert(idx < Size()); }
   372 	FORCEINLINE void CheckIdx(bsize_t idx)
       
   373 	{
       
   374 		assert(idx >= 0); assert(idx < Size());
       
   375 	}
       
   376 
   241 	/** Return pointer to the first data item - non-const version */
   377 	/** Return pointer to the first data item - non-const version */
   242 	FORCEINLINE Titem* Data() { return (Titem*)RawData(); }
   378 	FORCEINLINE Titem* Data()
       
   379 	{
       
   380 		return (Titem*)Tbase::RawData();
       
   381 	}
       
   382 
   243 	/** Return pointer to the first data item - const version */
   383 	/** Return pointer to the first data item - const version */
   244 	FORCEINLINE const Titem* Data() const { return (const Titem*)RawData(); }
   384 	FORCEINLINE const Titem* Data() const
       
   385 	{
       
   386 		return (const Titem*)Tbase::RawData();
       
   387 	}
       
   388 
   245 	/** Return pointer to the idx-th data item - non-const version */
   389 	/** Return pointer to the idx-th data item - non-const version */
   246 	FORCEINLINE Titem* Data(int idx) { CheckIdx(idx); return (Data() + idx); }
   390 	FORCEINLINE Titem* Data(bsize_t idx)
       
   391 	{
       
   392 		CheckIdx(idx);
       
   393 		return (Data() + idx);
       
   394 	}
       
   395 
   247 	/** Return pointer to the idx-th data item - const version */
   396 	/** Return pointer to the idx-th data item - const version */
   248 	FORCEINLINE const Titem* Data(int idx) const { CheckIdx(idx); return (Data() + idx); }
   397 	FORCEINLINE const Titem* Data(bsize_t idx) const
       
   398 	{
       
   399 		CheckIdx(idx); return (Data() + idx);
       
   400 	}
       
   401 
   249 	/** Return number of items in the Blob */
   402 	/** Return number of items in the Blob */
   250 	FORCEINLINE int Size() const { return (RawSize() / Titem_size); }
   403 	FORCEINLINE bsize_t Size() const
       
   404 	{
       
   405 		return (Tbase::RawSize() / Titem_size);
       
   406 	}
       
   407 
       
   408 	/** Return total number of items that can fit in the Blob without buffer reallocation */
       
   409 	FORCEINLINE bsize_t MaxSize() const
       
   410 	{
       
   411 		return (Tbase::MaxRawSize() / Titem_size);
       
   412 	}
       
   413 	/** Return number of additional items that can fit in the Blob without buffer reallocation */
       
   414 	FORCEINLINE bsize_t GetReserve() const
       
   415 	{
       
   416 		return ((Tbase::MaxRawSize() - Tbase::RawSize()) / Titem_size);
       
   417 	}
       
   418 
   251 	/** Free the memory occupied by Blob destroying all items */
   419 	/** Free the memory occupied by Blob destroying all items */
   252 	FORCEINLINE void Free()
   420 	FORCEINLINE void Free()
   253 	{
   421 	{
   254 		assert((RawSize() % Titem_size) == 0);
   422 		assert((Tbase::RawSize() % Titem_size) == 0);
   255 		int old_size = Size();
   423 		bsize_t old_size = Size();
   256 		if (old_size > 0) {
   424 		if (old_size > 0) {
   257 			// destroy removed items;
   425 			// destroy removed items;
   258 			Titem* pI_last_to_destroy = Data(0);
   426 			Titem* pI_last_to_destroy = Data(0);
   259 			for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
   427 			for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem_();
   260 		}
   428 		}
   261 		Tbase::Free();
   429 		Tbase::Free();
   262 	}
   430 	}
       
   431 
   263 	/** Grow number of data items in Blob by given number - doesn't construct items */
   432 	/** Grow number of data items in Blob by given number - doesn't construct items */
   264 	FORCEINLINE Titem* GrowSizeNC(int num_items) { return (Titem*)GrowRawSize(num_items * Titem_size); }
   433 	FORCEINLINE Titem* GrowSizeNC(bsize_t num_items)
       
   434 	{
       
   435 		return (Titem*)Tbase::GrowRawSize(num_items * Titem_size);
       
   436 	}
       
   437 
   265 	/** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */
   438 	/** Grow number of data items in Blob by given number - constructs new items (using Titem_'s default constructor) */
   266 	FORCEINLINE Titem* GrowSizeC(int num_items)
   439 	FORCEINLINE Titem* GrowSizeC(bsize_t num_items)
   267 	{
   440 	{
   268 		Titem* pI = GrowSizeNC(num_items);
   441 		Titem* pI = GrowSizeNC(num_items);
   269 		for (int i = num_items; i > 0; i--, pI++) new (pI) Titem();
   442 		for (bsize_t i = num_items; i > 0; i--, pI++) new (pI) Titem();
   270 	}
   443 	}
       
   444 
   271 	/** Destroy given number of items and reduce the Blob's data size */
   445 	/** Destroy given number of items and reduce the Blob's data size */
   272 	FORCEINLINE void ReduceSize(int num_items)
   446 	FORCEINLINE void ReduceSize(bsize_t num_items)
   273 	{
   447 	{
   274 		assert((RawSize() % Titem_size) == 0);
   448 		assert((Tbase::RawSize() % Titem_size) == 0);
   275 		int old_size = Size();
   449 		bsize_t old_size = Size();
   276 		assert(num_items <= old_size);
   450 		assert(num_items <= old_size);
   277 		int new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
   451 		bsize_t new_size = (num_items <= old_size) ? (old_size - num_items) : 0;
   278 		// destroy removed items;
   452 		// destroy removed items;
   279 		Titem* pI_last_to_destroy = Data(new_size);
   453 		Titem* pI_last_to_destroy = Data(new_size);
   280 		for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
   454 		for (Titem* pI = Data(old_size - 1); pI >= pI_last_to_destroy; pI--) pI->~Titem();
   281 		// remove them
   455 		// remove them
   282 		ReduceRawSize(num_items * Titem_size);
   456 		Tbase::ReduceRawSize(num_items * Titem_size);
   283 	}
   457 	}
       
   458 
   284 	/** Append one data item at the end (calls Titem_'s default constructor) */
   459 	/** Append one data item at the end (calls Titem_'s default constructor) */
   285 	FORCEINLINE Titem* AppendNew()
   460 	FORCEINLINE Titem* AppendNew()
   286 	{
   461 	{
   287 		Titem& dst = *GrowSizeNC(1); // Grow size by one item
   462 		Titem& dst = *GrowSizeNC(1); // Grow size by one item
   288 		Titem* pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
   463 		Titem* pNewItem = new (&dst) Titem(); // construct the new item by calling in-place new operator
   289 		return pNewItem;
   464 		return pNewItem;
   290 	}
   465 	}
       
   466 
   291 	/** Append the copy of given item at the end of Blob (using copy constructor) */
   467 	/** Append the copy of given item at the end of Blob (using copy constructor) */
   292 	FORCEINLINE Titem* Append(const Titem& src)
   468 	FORCEINLINE Titem* Append(const Titem& src)
   293 	{
   469 	{
   294 		Titem& dst = *GrowSizeNC(1); // Grow size by one item
   470 		Titem& dst = *GrowSizeNC(1); // Grow size by one item
   295 		Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
   471 		Titem* pNewItem = new (&dst) Titem(src); // construct the new item by calling in-place new operator with copy ctor()
   296 		return pNewItem;
   472 		return pNewItem;
   297 	}
   473 	}
       
   474 
   298 	/** Add given items (ptr + number of items) at the end of blob */
   475 	/** Add given items (ptr + number of items) at the end of blob */
   299 	FORCEINLINE Titem* Append(const Titem* pSrc, int num_items)
   476 	FORCEINLINE Titem* Append(const Titem* pSrc, bsize_t num_items)
   300 	{
   477 	{
   301 		Titem* pDst = GrowSizeNC(num_items);
   478 		Titem* pDst = GrowSizeNC(num_items);
   302 		Titem* pDstOrg = pDst;
   479 		Titem* pDstOrg = pDst;
   303 		Titem* pDstEnd = pDst + num_items;
   480 		Titem* pDstEnd = pDst + num_items;
   304 		while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
   481 		while (pDst < pDstEnd) new (pDst++) Titem(*(pSrc++));
   305 		return pDstOrg;
   482 		return pDstOrg;
   306 	}
   483 	}
       
   484 
   307 	/** Remove item with the given index by replacing it by the last item and reducing the size by one */
   485 	/** Remove item with the given index by replacing it by the last item and reducing the size by one */
   308 	FORCEINLINE void RemoveBySwap(int idx)
   486 	FORCEINLINE void RemoveBySwap(bsize_t idx)
   309 	{
   487 	{
   310 		CheckIdx(idx);
   488 		CheckIdx(idx);
   311 		// destroy removed item
   489 		// destroy removed item
   312 		Titem* pRemoved = Data(idx);
   490 		Titem* pRemoved = Data(idx);
   313 		RemoveBySwap(pRemoved);
   491 		RemoveBySwap(pRemoved);
   314 	}
   492 	}
       
   493 
   315 	/** Remove item given by pointer replacing it by the last item and reducing the size by one */
   494 	/** Remove item given by pointer replacing it by the last item and reducing the size by one */
   316 	FORCEINLINE void RemoveBySwap(Titem* pItem)
   495 	FORCEINLINE void RemoveBySwap(Titem* pItem)
   317 	{
   496 	{
   318 		Titem* pLast = Data(Size() - 1);
   497 		Titem* pLast = Data(Size() - 1);
   319 		assert(pItem >= Data() && pItem <= pLast);
   498 		assert(pItem >= Data() && pItem <= pLast);
   323 			new (pItem) Titem_(*pLast);
   502 			new (pItem) Titem_(*pLast);
   324 		}
   503 		}
   325 		// destroy the last item
   504 		// destroy the last item
   326 		pLast->~Titem_();
   505 		pLast->~Titem_();
   327 		// and reduce the raw blob size
   506 		// and reduce the raw blob size
   328 		ReduceRawSize(Titem_size);
   507 		Tbase::ReduceRawSize(Titem_size);
   329 	}
   508 	}
       
   509 
   330 	/** Ensures that given number of items can be added to the end of Blob. Returns pointer to the
   510 	/** Ensures that given number of items can be added to the end of Blob. Returns pointer to the
   331 	 *  first free (unused) item */
   511 	*  first free (unused) item */
   332 	FORCEINLINE Titem* MakeFreeSpace(int num_items) { return (Titem*)MakeRawFreeSpace(num_items * Titem_size); }
   512 	FORCEINLINE Titem* MakeFreeSpace(bsize_t num_items)
       
   513 	{
       
   514 		return (Titem*)Tbase::MakeRawFreeSpace(num_items * Titem_size);
       
   515 	}
       
   516 
       
   517 	FORCEINLINE OnTransfer Transfer()
       
   518 	{
       
   519 		return OnTransfer(*this);
       
   520 	};
   333 };
   521 };
   334 
   522 
   335 // simple string implementation
       
   336 struct CStrA : public CBlobT<char>
       
   337 {
       
   338 	typedef CBlobT<char> base;
       
   339 	CStrA(const char* str = NULL) {Append(str);}
       
   340 	FORCEINLINE CStrA(const CBlobBaseSimple& src) : base(src) {}
       
   341 	void Append(const char* str) {if (str != NULL && str[0] != '\0') base::Append(str, (int)strlen(str));}
       
   342 };
       
   343 
   523 
   344 #endif /* BLOB_HPP */
   524 #endif /* BLOB_HPP */