1 /* Written by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module addrstore
is aliced
;
20 // ////////////////////////////////////////////////////////////////////////// //
22 Byte
= 1<<0, // 8 bits
23 Word
= 1<<1, // 16 bits
24 Int
= 1<<2, // 32 bits
25 Long
= 1<<3, // 64 bits
26 Float
= 1<<4, // 32 bits
27 Double
= 1<<5, // 64 bits
33 uint maxVTSize (ubyte vt
) {
34 if (vt
&VType
.Double
) return 8;
35 if (vt
&VType
.Long
) return 8;
36 if (vt
&VType
.Float
) return 4;
37 if (vt
&VType
.Int
) return 4;
38 if (vt
&VType
.Word
) return 2;
43 string
vtName (ubyte vt
) {
44 if (vt
&VType
.Double
) return "f8";
45 if (vt
&VType
.Long
) return "i8";
46 if (vt
&VType
.Float
) return "f4";
47 if (vt
&VType
.Int
) return "i4";
48 if (vt
&VType
.Word
) return "i2";
49 if (vt
&VType
.Byte
) return "i1";
54 // ////////////////////////////////////////////////////////////////////////// //
56 // first 4 bytes: base address
57 // next byte; value type
60 // ==0: 3-byte offset to next address follows
61 // ==255: 4-byte next address follows
62 // other: this is byte offset to next address
63 // next byte: value type
66 // ////////////////////////////////////////////////////////////////////////// //
67 static struct AddrVal
{ uint addr
; ubyte vt
; }
69 alias ASRange
= ASRangeImpl
!false;
70 alias ASRangeD
= ASRangeImpl
!true;
72 struct ASRangeImpl(bool destructive
) {
74 private import core
.stdc
.stdlib
: free
;
76 AddrStore
.PoolHead
* ph
;
77 ubyte* dp
; // data pointer in ph
78 uint dataLeft
; // in ph
79 uint addr
; // front element -- address
80 ubyte vt
; // front element -- vtype
81 uint len
; // addresses left (total)
84 void finish () nothrow @nogc {
85 static if (destructive
) {
86 // free all remaining pools
87 import core
.stdc
.stdlib
: free
;
105 this (ref AddrStore fv
) nothrow @nogc { setup(fv
); }
106 ~this () { finish(); }
108 void setup (ref AddrStore fv
) nothrow @nogc {
112 static if (destructive
) fv
.reset(); // reset store, so it can accept new addresses
114 ++len
; // 'cause popFront will dec it
119 @property bool empty () const pure { pragma(inline
, true); return (len
== 0); }
120 @property AddrVal
front () const pure { pragma(inline
, true); return AddrVal(addr
, vt
); }
121 @property uint length () const pure { pragma(inline
, true); return len
; }
124 if (len
<= 1) { finish(); return; } // no more
125 --len
; // front item removed
126 while (ph
!is null) {
127 if (dp
is null || dataLeft
< 2) {
129 // free current block, get next one
130 static if (destructive
) {
131 import core
.stdc
.stdlib
: free
;
139 if (ph
is null) break;
141 // first entry of new block
143 if (dataLeft
< 5) { dataLeft
= 0; continue; } // out of data
145 addr
= *cast(uint*)dp
; dp
+= 4;
151 if (ofs
!= 0 && ofs
!= 255) {
156 } else if (ofs
== 255) {
158 if (dataLeft
< 6) { dataLeft
= 0; continue; } // out of data in this chunk
165 } else if (ofs
== 0) {
167 if (dataLeft
< 5) { dataLeft
= 0; continue; } // out of data in this chunk
184 // ////////////////////////////////////////////////////////////////////////// //
187 enum PoolSize
= 32*1024;
189 align(1) struct PoolHead
{
191 PoolHead
* next
; // null for last one
192 uint size
; // data size, excluding head
193 uint used
; // data used
196 nothrow @trusted @nogc:
197 void putByte (ubyte b
) {
198 if (used
>= size || size
-used
< 1) assert(0, "wtf?!");
199 *(data
.ptr
+(used
++)) = b
;
210 import core
.stdc
.stdlib
: malloc
;
211 PoolHead
* ph
= cast(PoolHead
*)malloc(PoolSize
);
212 if (ph
is null) assert(0, "out of memory");
213 if (lastPool
!is null) lastPool
.next
= ph
; else firstPool
= ph
;
216 ph
.size
= PoolSize
-PoolHead
.sizeof
;
221 // reset pools, but don't clear
222 void reset () nothrow @trusted @nogc {
223 firstPool
= lastPool
= null;
230 @disable this (this);
231 ~this () { clear(); }
233 uint count () const pure nothrow @safe @nogc { pragma(inline
, true); return addrCount
; }
234 uint poolCount () const pure nothrow @safe @nogc { pragma(inline
, true); return poolsUsed
; }
236 // not opIndex, 'cause it is slow as hell
237 AddrVal
at (uint idx
) {
238 if (idx
>= addrCount
) throw new Exception("invalid index");
239 auto rng
= ASRange(this);
241 if (rng
.empty
) assert(0, "wtf?!");
245 if (rng
.empty
) assert(0, "wtf?!");
250 import core
.stdc
.stdlib
: free
;
251 while (firstPool
!is null) {
259 void addAddress (uint addr
, ubyte vt
) {
260 // we can waste up to 4 bytes with this; idc
261 if (lastPool
!is null && lastPool
.size
-lastPool
.used
>= 6) {
262 if (lastAddr
<= addr
&& addr
-lastAddr
<= 0xffffff) {
263 uint diff
= addr
-lastAddr
;
264 if (diff
== 0 || diff
> 254) {
267 lastPool
.putByte(diff
&0xff);
268 lastPool
.putByte((diff
>>8)&0xff);
269 lastPool
.putByte((diff
>>16)&0xff);
272 lastPool
.putByte(cast(ubyte)diff
);
276 lastPool
.putByte(255);
277 lastPool
.putByte(addr
&0xff);
278 lastPool
.putByte((addr
>>8)&0xff);
279 lastPool
.putByte((addr
>>16)&0xff);
280 lastPool
.putByte((addr
>>24)&0xff);
285 *cast(uint*)(lastPool
.data
.ptr
) = addr
;
288 lastPool
.putByte(vt
);