1// Block.h
2
3#ifndef BLOCK_H
4#define BLOCK_H
5
6class Block;
7class BlockHeader;
8class BlockReference;
9class TFreeBlock;
10
11#include <SupportDefs.h>
12
13// debugging
14//#define inline
15#define BA_DEFINE_INLINES	1
16
17// BlockHeader
18class BlockHeader {
19public:
20	inline Block *ToBlock()				{ return (Block*)this; }
21	inline TFreeBlock *ToFreeBlock()	{ return (TFreeBlock*)this; }
22
23	inline void SetPreviousBlock(Block *block);
24	inline Block *GetPreviousBlock();
25
26	inline void SetNextBlock(Block *block);
27	inline Block *GetNextBlock();
28	inline bool HasNextBlock()			{ return (fSize & HAS_NEXT_FLAG); }
29
30	inline void SetSize(size_t size, bool hasNext = false);
31	inline size_t GetSize() const;
32	static inline size_t GetUsableSizeFor(size_t size);
33	inline size_t GetUsableSize() const;
34
35	inline void *GetData();
36
37	inline void SetFree(bool flag);
38	inline bool IsFree() const;
39
40	inline void SetReference(BlockReference *ref);
41	inline BlockReference *GetReference() const		{ return fReference; }
42	inline void FixReference();
43
44	inline void SetTo(Block *previous, size_t size, bool isFree, bool hasNext,
45					  BlockReference *reference = NULL);
46
47private:
48	enum {
49		FREE_FLAG		= 0x80000000,
50		BACK_SKIP_MASK	= 0x7fffffff,
51	};
52
53	enum {
54		HAS_NEXT_FLAG	= 0x80000000,
55		SIZE_MASK		= 0x7fffffff,
56	};
57
58private:
59	BlockHeader();
60	~BlockHeader();
61
62protected:
63	size_t			fBackSkip;
64	size_t			fSize;
65	BlockReference	*fReference;
66};
67
68// Block
69class Block : public BlockHeader {
70public:
71	static inline Block *MakeBlock(void *address, ssize_t offset,
72								  Block *previous, size_t size, bool isFree,
73								  bool hasNext,
74								  BlockReference *reference = NULL);
75
76private:
77	Block();
78	~Block();
79};
80
81// TFreeBlock
82class TFreeBlock : public Block {
83public:
84
85	inline void SetPreviousFreeBlock(TFreeBlock *block)	{ fPrevious = block; }
86	inline void SetNextFreeBlock(TFreeBlock *block)		{ fNext = block; }
87	inline TFreeBlock *GetPreviousFreeBlock()			{ return fPrevious; }
88	inline TFreeBlock *GetNextFreeBlock()				{ return fNext; }
89
90	inline void SetTo(Block *previous, size_t size, bool hasNext,
91					  TFreeBlock *previousFree, TFreeBlock *nextFree);
92
93//	static inline TFreeBlock *MakeFreeBlock(void *address, ssize_t offset,
94//		Block *previous, size_t size, bool hasNext, TFreeBlock *previousFree,
95//		TFreeBlock *nextFree);
96
97private:
98	TFreeBlock();
99	~TFreeBlock();
100
101private:
102	TFreeBlock	*fPrevious;
103	TFreeBlock	*fNext;
104};
105
106// BlockReference
107class BlockReference {
108public:
109	inline BlockReference()				: fBlock(NULL) {}
110	inline BlockReference(Block *block) : fBlock(block) {}
111
112	inline void SetBlock(Block *block)	{ fBlock = block; }
113	inline Block *GetBlock() const		{ return fBlock; }
114
115	inline void *GetData() const		{ return fBlock->GetData(); }
116	inline void *GetDataAt(ssize_t offset) const;
117
118private:
119	Block	*fBlock;
120};
121
122
123// ---------------------------------------------------------------------------
124// inline methods
125
126// debugging
127#if BA_DEFINE_INLINES
128
129// BlockHeader
130
131// SetPreviousBlock
132inline
133void
134BlockHeader::SetPreviousBlock(Block *block)
135{
136	size_t offset = (block ? (char*)this - (char*)block : 0);
137	fBackSkip = fBackSkip & FREE_FLAG | offset;
138}
139
140// GetPreviousBlock
141inline
142Block *
143BlockHeader::GetPreviousBlock()
144{
145	if (fBackSkip & BACK_SKIP_MASK)
146		return (Block*)((char*)this - (fBackSkip & BACK_SKIP_MASK));
147	return NULL;
148}
149
150// SetNextBlock
151inline
152void
153BlockHeader::SetNextBlock(Block *block)
154{
155	if (block)
156		fSize = ((char*)block - (char*)this) | HAS_NEXT_FLAG;
157	else
158		fSize &= SIZE_MASK;
159}
160
161// GetNextBlock
162inline
163Block *
164BlockHeader::GetNextBlock()
165{
166	if (fSize & HAS_NEXT_FLAG)
167		return (Block*)((char*)this + (SIZE_MASK & fSize));
168	return NULL;
169}
170
171// SetSize
172inline
173void
174BlockHeader::SetSize(size_t size, bool hasNext)
175{
176	fSize = size;
177	if (hasNext)
178		fSize |= HAS_NEXT_FLAG;
179}
180
181// GetSize
182inline
183size_t
184BlockHeader::GetSize() const
185{
186	return (fSize & SIZE_MASK);
187}
188
189// GetUsableSizeFor
190inline
191size_t
192BlockHeader::GetUsableSizeFor(size_t size)
193{
194	return (size - sizeof(BlockHeader));
195}
196
197// GetUsableSize
198inline
199size_t
200BlockHeader::GetUsableSize() const
201{
202	return GetUsableSizeFor(GetSize());
203}
204
205// GetData
206inline
207void *
208BlockHeader::GetData()
209{
210	return (char*)this + sizeof(BlockHeader);
211}
212
213// SetFree
214inline
215void
216BlockHeader::SetFree(bool flag)
217{
218	if (flag)
219		fBackSkip |= FREE_FLAG;
220	else
221		fBackSkip &= ~FREE_FLAG;
222}
223
224// IsFree
225inline
226bool
227BlockHeader::IsFree() const
228{
229	return (fBackSkip & FREE_FLAG);
230}
231
232// SetTo
233inline
234void
235BlockHeader::SetTo(Block *previous, size_t size, bool isFree, bool hasNext,
236				   BlockReference *reference)
237{
238	SetPreviousBlock(previous);
239	SetSize(size, hasNext);
240	SetFree(isFree);
241	SetReference(reference);
242}
243
244// SetReference
245inline
246void
247BlockHeader::SetReference(BlockReference *ref)
248{
249	fReference = ref;
250	FixReference();
251}
252
253// FixReference
254inline
255void
256BlockHeader::FixReference()
257{
258	if (fReference)
259		fReference->SetBlock(ToBlock());
260}
261
262
263// Block
264
265// MakeBlock
266/*inline
267Block *
268Block::MakeBlock(void *address, ssize_t offset, Block *previous, size_t size,
269				 bool isFree, bool hasNext, BlockReference *reference)
270{
271	Block *block = (Block*)((char*)address + offset);
272	block->SetTo(previous, size, isFree, hasNext, reference);
273	return block;
274}*/
275
276
277// TFreeBlock
278
279// SetTo
280inline
281void
282TFreeBlock::SetTo(Block *previous, size_t size, bool hasNext,
283				  TFreeBlock *previousFree, TFreeBlock *nextFree)
284{
285	Block::SetTo(previous, size, true, hasNext, NULL);
286	SetPreviousFreeBlock(previousFree);
287	SetNextFreeBlock(nextFree);
288}
289
290// MakeFreeBlock
291/*inline
292TFreeBlock *
293TFreeBlock::MakeFreeBlock(void *address, ssize_t offset, Block *previous,
294						  size_t size, bool hasNext, TFreeBlock *previousFree,
295						  TFreeBlock *nextFree)
296{
297	TFreeBlock *block = (TFreeBlock*)((char*)address + offset);
298	block->SetTo(previous, size, hasNext, previousFree, nextFree);
299	if (hasNext)
300		block->GetNextBlock()->SetPreviousBlock(block);
301	return block;
302}*/
303
304
305// BlockReference
306
307// GetDataAt
308inline
309void *
310BlockReference::GetDataAt(ssize_t offset) const
311{
312	return (char*)fBlock->GetData() + offset;
313}
314
315#endif	// BA_DEFINE_INLINES
316
317#endif	// BLOCK_H
318