Skip to content

Commit 49b21d0

Browse files
committed
WIP: StencilVector
1 parent 0d10064 commit 49b21d0

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-1
lines changed

lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ build:
1414
$(COMPILER) ./bst.trp -l
1515
$(COMPILER) ./localregistry.trp -l
1616
$(COMPILER) ./hash.trp -l
17-
$(COMPILER) ./hamt.trp -l
1817
$(COMPILER) ./Unit.trp -l
18+
$(COMPILER) ./StencilVector.trp -l
1919

2020
clean:
2121
rm -rf out

lib/StencilVector.trp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import List
2+
3+
let (*--- Constants ---*)
4+
5+
(** Using 32 bit integers bitmasks, we have a branch factor of 32 which
6+
* requires 5 bits *)
7+
val maskWidthLog = 5
8+
9+
(** Maximum length of stencil vector: 2^`maskWidthLog` *)
10+
val maskWidth = 1 << maskWidthLog
11+
12+
(** Bitmask with `maskWidth` number of values *)
13+
val mask = maskWidth - 1
14+
15+
(** Maximum value for a 32 bit unsigned integer *)
16+
val max_int32 = 4294967296 - 1
17+
18+
(*--- Bitmap ---*)
19+
20+
(** An empty bitmap. *)
21+
val bitmapEmpty = 0
22+
23+
(** Bitmap with the `i`th bit set to `true` *)
24+
fun bitmapPos i = (1 << i)
25+
26+
(** Get whether the `i`th bit is set to true in the given bitmap `bm` *)
27+
fun bitmapGet bm i = ((bitmapPos i) andb bm) <> bitmapEmpty
28+
29+
(** A bitmap that is like `bm` but with the `i`th bit to `true`. *)
30+
fun bitmapSet bm i = bm orb (bitmapPos i)
31+
32+
(** Returns a bitmap that is like `bm` but with the `i`th bit to `false`. *)
33+
fun bitmapUnset bm i = bm andb (max_int32 xorb (bitmapPos i))
34+
35+
(** Count the number of `true` bits in the given bitmap `bm` *)
36+
fun bitmapPopcount bm =
37+
let (* Uses parallel bit counting - ~30x faster than bit-by-bit. The following are masks to
38+
* extract a disjoint set of bytes. Here, we can abuse the fact, that the '+' operator
39+
* can sum several numbers together, if each number is shifted (and one does not
40+
* overflow into the other). See also: Gödel Numbers. *)
41+
val m1 = 1431655765 (* 0b_01010101010101010101010101010101 *)
42+
val m2 = 858993459 (* 0b_00110011001100110011001100110011 *)
43+
val m4 = 252645135 (* 0b_00001111000011110000111100001111 *)
44+
val m8 = 16843009 (* 0b_00000001000000010000000100000001 *)
45+
46+
(* Count bits in groups of 2. This makes each pair of bits contain the number of
47+
* 'true' bits set. *)
48+
val bm1 = (bm andb m1) + ((bm >> 1) andb m1)
49+
50+
(* Count bits in groups of 4. Same as above, but now in 4-bit (nibble) subresults. *)
51+
val bm2 = (bm1 andb m2) + ((bm1 >> 2) andb m2)
52+
53+
(* Count bits in groups of 8. Same as above, but now in 8-bit (byte) subresults. *)
54+
val bm4 = (bm2 andb m4) + ((bm2 >> 4) andb m4)
55+
in
56+
(* At this point, each group of 8 bits can cover 32+ different values. Since the
57+
* original number is 32 bits, they cannot overflow into each other. Hence, we can now
58+
* safely multiply this with `m8` which sums all groups together in bits 25..32; this
59+
* byte can then be moved back down. *)
60+
((bm4 * m8) >> 24) andb 255
61+
end
62+
63+
(** Count the number of `true` bits prior to the given index. *)
64+
fun bitmapPopcountPos bm i =
65+
let val iMask = (bitmapPos i) - 1
66+
val bmMasked = bm andb iMask
67+
in bitmapPopcount bmMasked
68+
end
69+
70+
(*--- Stencil Vector ---*)
71+
72+
(* A Stencil Vector is represented as a tuple `(bitmap, array)` where `bitmap` is a 32 bit
73+
* accessed with the functions above and `array` is a `list` which simulates an immutable
74+
* array.
75+
*
76+
* The documentation comments for most of these are lifted from the Racket documentation.
77+
*)
78+
79+
(** The empty stencil vector. *)
80+
val empty = (0, [])
81+
82+
(** Get the element stored in slot `i` in the given stencil vector. The first slot is `0`, and
83+
* the last slot is one less than `maskWidth`. *)
84+
(* TODO: Default argument or `NONE`? *)
85+
fun get (bm, xs) i = () (* TODO *)
86+
87+
(** Inserts `x` into slot `i` on the given stencil vector. If the slot already is occupied, then
88+
* the element is replaced with the new value. *)
89+
fun set (bm, xs) i x = () (* TODO *)
90+
91+
(** Removes the element stored in slot `i` in the given stencil vector. If the slot is empty,
92+
* then the vector is unchanged. *)
93+
fun unset (bm, xs) i =
94+
if bitmapGet bm i
95+
then () (* TODO *)
96+
else (bm, xs)
97+
98+
(** Returns `true` if a value is stored at slot `i`. *)
99+
fun mem (bm, xs) i = bitmapGet bm i
100+
101+
(** Returns `true` if the given value is a valid stencil vector. *)
102+
fun valid (bm, xs) =
103+
if "number" = getType bm
104+
then if bm = floor bm
105+
then if isList xs
106+
then (bitmapPopcount bm) = (List.length xs)
107+
else false
108+
else false
109+
else false
110+
| valid _ = false
111+
112+
(** Returns `true` if the stencil vector is empty. *)
113+
fun null (0, _) = true
114+
| null _ = false
115+
116+
(** Returns the mask of a stencil vector. Note that the mask of a stencil vector is determined
117+
* at creation time and cannot be changed later. *)
118+
fun mask (bm, _) = bm
119+
120+
(** Returns the length of a stencil vector (i.e., the number of slots occupied). *)
121+
fun length (bm, _) = bitmapPopcount bm
122+
123+
(* TODO: Lift list functions `map`, `mapi`, `foldl`, `foldr`, `find`, and `filter`? *)
124+
125+
val StencilVector = {
126+
(* Constants *)
127+
maskWidthLog = maskWidthLog,
128+
maskWidth = maskWidth,
129+
(* Functions *)
130+
empty = empty,
131+
get = get,
132+
set = set,
133+
unset = unset,
134+
mem = mem,
135+
valid = valid,
136+
null = null,
137+
mask = mask,
138+
length = length
139+
}
140+
in (* Export public functions *)
141+
[ ("StencilVector", StencilVector)
142+
]
143+
end

tests/lib/StencilVector.trp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Unit
2+
import StencilVector
3+
4+
Unit.run authority
5+
(Unit.group "StencilVector" [
6+
let val sv = StencilVector.empty
7+
in Unit.group "empty" [
8+
Unit.it "has no members" [
9+
Unit.isFalse (StencilVector.mem sv 0)
10+
, Unit.isFalse (StencilVector.mem sv 1)
11+
, Unit.isFalse (StencilVector.mem sv 2)
12+
, Unit.isFalse (StencilVector.mem sv 3)
13+
, Unit.isFalse (StencilVector.mem sv 7)
14+
, Unit.isFalse (StencilVector.mem sv 16)
15+
, Unit.isFalse (StencilVector.mem sv 31)
16+
]
17+
, Unit.it "is valid" (Unit.isTrue (StencilVector.valid sv))
18+
, Unit.it "is null" (Unit.isTrue (StencilVector.null sv))
19+
, Unit.it "has 0 as its mask" (Unit.isEq 0 (StencilVector.mask sv))
20+
, Unit.it "has length 0" (Unit.isEq 0 (StencilVector.length sv))
21+
]
22+
end
23+
])

0 commit comments

Comments
 (0)