3 SuperCollider real time audio synthesis system
4 Copyright (c) 2002 James McCartney. All rights reserved.
5 http://www.audiosynth.com
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 This is based on Doug Lea's allocator but rewritten so I can read and understand it...
23 also features of free all-at-once pools are added.
24 Now uses 16 byte alignment, which does increase the minimum allocation size to 32 bytes
25 including the overhead.
26 Improved bit block scanning by using a count leading zeroes instruction.
37 const int kNumAllocBins
= 128;
38 const int kNumSmallBins
= 64;
39 const int kMaxSmallBin
= kNumSmallBins
- 1;
40 const int kBinWidth
= 8;
41 const int kMaxSmallBinSize
= kNumSmallBins
* kBinWidth
;
42 const int kBinBlockWidth
= 4;
43 const int kBinBlockMask
= kBinBlockWidth
- 1;
45 const size_t kAlign
= 64;
46 const size_t kAlignMask
= kAlign
- 1;
47 const size_t kChunkFree
= 0;
48 const size_t kChunkInUse
= 1;
49 const size_t kSizeBits
= ~kChunkInUse
;
53 typedef AllocChunk
*AllocChunkPtr
;
54 typedef Link
<AllocChunk
> AllocBin
;
55 typedef AllocBin
* AllocBinPtr
;
57 class AllocChunk
: public Link
<AllocChunk
>
59 friend class AllocPool
;
62 { return mSize
& kSizeBits
; }
65 { return mPrevSize
& kSizeBits
; }
67 AllocChunkPtr
ChunkAtOffset(long inSize
)
68 { return AllocChunkPtr((char*)this + inSize
); }
70 AllocChunkPtr
NextChunk()
71 { return ChunkAtOffset(Size()); }
73 AllocChunkPtr
PrevChunk()
74 { return ChunkAtOffset(-(long)PrevSize()); }
77 { return (bool)(mSize
& kChunkInUse
); }
80 { return (bool)(mPrevSize
& kChunkInUse
); }
82 void SetSizeFree(size_t inSize
)
83 { mSize
= ChunkAtOffset(inSize
)->mPrevSize
= inSize
; }
85 void SetSizeInUse(size_t inSize
)
86 { mSize
= ChunkAtOffset(inSize
)->mPrevSize
= inSize
| kChunkInUse
; }
88 void SetNeighborsInUse(size_t inOffset
)
89 { mPrevSize
= ChunkAtOffset(inOffset
)->mSize
= kChunkInUse
; }
92 { return mPrevSize
== kChunkInUse
&& NextChunk()->mSize
== kChunkInUse
; }
95 { return (void*)((char*)this + sizeof(AllocChunk
)); }
102 typedef AllocArea
* AllocAreaPtr
;
104 class AllocAreaHdr
/* for size calculations */
107 friend class AllocPool
;
109 AllocAreaPtr mPrev
, mNext
;
111 void *mUnalignedPointerToThis
;
114 class AllocArea
: public AllocAreaHdr
120 friend class AllocPool
;
125 const size_t kMinAllocSize
= 2 * kAlign
;
126 const size_t kAreaOverhead
= sizeof(AllocAreaHdr
) + 2 * sizeof(AllocChunk
) + kAlign
;
128 typedef void* (*NewAreaFunc
)(size_t size
);
129 typedef void (*FreeAreaFunc
)(void *);
134 AllocPool(NewAreaFunc allocArea
, FreeAreaFunc freeArea
,
135 size_t areaInitSize
, size_t areaMoreSize
);
140 void *Alloc(size_t inBytes
);
141 void *Realloc(void* inPtr
, size_t inBytes
);
142 void Free(void* inPtr
);
144 void FreeAllInternal();
148 size_t LargestFreeChunk();
151 void DoCheckInUseChunk(AllocChunkPtr p
);
153 static AllocChunkPtr
MemToChunk(void *inPtr
)
154 { return (AllocChunkPtr
)((char*)(inPtr
) - sizeof(AllocChunk
)); }
159 AllocAreaPtr
NewArea(size_t inAreaSize
);
160 void FreeArea(AllocChunkPtr chunk
);
163 void DoCheckArea(AllocAreaPtr area
);
164 void DoCheckBin(AllocChunkPtr bin
, long idx
);
165 void DoCheckChunk(AllocChunkPtr p
);
166 void DoCheckFreeChunk(AllocChunkPtr p
);
167 void DoCheckAllocedChunk(AllocChunkPtr p
, size_t s
);
168 void DoGarbageFill(AllocChunkPtr p
);
169 void DoGarbageFill(AllocChunkPtr p
, long size
);
173 static size_t RequestToSize(size_t inReqSize
)
175 size_t sizePlusOverhead
= inReqSize
+ sizeof(AllocChunk
);
176 if (sizePlusOverhead
<= kMinAllocSize
) return kMinAllocSize
;
177 else return (sizePlusOverhead
+ kAlignMask
) & ~kAlignMask
;
180 static int SmallBinIndex(size_t inSize
)
181 { return inSize
>> 4; }
183 static int BinIndex2(size_t inSize
)
186 ((inSize
< 1024) ? (inSize
>>4):
187 (inSize
< 2048) ? 56 + (inSize
>>7):
188 (inSize
< 4096) ? 64 + (inSize
>>8):
189 (inSize
< 8192) ? 72 + (inSize
>>9):
190 (inSize
< 16384) ? 80 + (inSize
>>10):
191 (inSize
< 32768) ? 88 + (inSize
>>11):
192 (inSize
< 65536) ? 96 + (inSize
>>12):
193 (inSize
< 131072) ? 104 + (inSize
>>13):
194 (inSize
< 262144) ? 112 + (inSize
>>14):127);
197 static int BinIndex(size_t inSize
)
199 if (inSize
< 1024) return inSize
>> 4;
200 if (inSize
>= 262144) return 127;
201 int bits
= 28 - CLZ(inSize
);
202 return (bits
<< 3) + (inSize
>> bits
) ;
205 void MarkBinBlock(int inIndex
)
207 unsigned long word
= inIndex
>> 5;
208 unsigned long bitPosition
= inIndex
& 31;
209 unsigned long bitValue
= 1L << bitPosition
;
210 mBinBlocks
[word
] |= bitValue
;
213 void ClearBinBlock(int inIndex
)
215 unsigned long word
= inIndex
>> 5;
216 unsigned long bitPosition
= inIndex
& 31;
217 unsigned long bitValue
= 1L << bitPosition
;
218 mBinBlocks
[word
] &= ~bitValue
;
221 int NextFullBin(int inStartingBinIndex
)
223 if (inStartingBinIndex
>= 128) return -1;
224 int word
= inStartingBinIndex
>> 5;
225 int bitPosition
= inStartingBinIndex
& 31;
226 unsigned long bitValue
= 1L << bitPosition
;
227 unsigned long binBits
= mBinBlocks
[word
];
229 if (binBits
>= bitValue
) {
230 binBits
= (~(bitValue
- 1) & binBits
);
232 for (++word
; word
<4 && !mBinBlocks
[word
]; ++word
) {}
233 if (word
==4) return -1;
234 binBits
= mBinBlocks
[word
];
236 bitPosition
= CTZ((int32
)binBits
);
238 return (word
<< 5) + bitPosition
;
241 void LinkFree(AllocChunkPtr inChunk
);
244 size_t size = inChunk->Size();
245 int index = BinIndex(size);
247 AllocChunkPtr bin = mBins + index;
249 if (index < kNumSmallBins || bin->IsEmpty()) {
250 inChunk->InsertAfter(bin);
253 AllocChunkPtr link = bin->Next();
254 while (link != bin && size < link->Size()) link = link->Next();
255 inChunk->InsertBefore(link);
260 void UnlinkFree(AllocChunkPtr inChunk
)
262 inChunk
->RemoveLeaveDangling();
263 size_t size
= inChunk
->Size();
264 int index
= BinIndex(size
);
265 AllocChunkPtr bin
= mBins
+ index
;
266 if (bin
->IsEmpty()) ClearBinBlock(index
);
269 AllocChunk mBins
[kNumAllocBins
];
271 NewAreaFunc mAllocArea
;
272 FreeAreaFunc mFreeArea
;
273 size_t mAreaInitSize
, mAreaMoreSize
;
274 unsigned long mBinBlocks
[4];