|
| 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 |
0 commit comments