3 * binmap, a hybrid of bitmap and binary tree
5 * Created by Victor Grishchenko on 3/28/09.
6 * Copyright 2009 Delft University of Technology. All rights reserved.
13 class iterator; // FIXME shame
15 /** A binmap covering 2^64 range. Binmap is a hybrid of a bitmap (aka
16 bit vector) and a binary tree. The key ability of a binmap is
17 the aggregation of solid (all-0 or all-1) ranges. */
21 /** Need a 3-valued logic as a range might be either all-0 or all-1
22 or some mix. In fact, any value different from 0x0 or 0xffff
23 must be interpreted as MIXED.
24 All read/write operations on a binmap are made in terms of
25 aligned binary intervals (bins).
27 typedef enum { FILLED=0xffff, EMPTY=0x0000, MIXED=0x5555 } fill_t;
28 static const int NOJOIN;
32 /** Copying constructor. */
33 binmap_t(const binmap_t& b);
38 /** Get value for the bin. */
39 uint16_t get (bin64_t bin);
41 /** Set value for the bin. */
42 void set (bin64_t bin, fill_t val=FILLED);
51 /** Copy a range from another binmap. */
52 void range_op (binmap_t& mask, bin64_t range, bin_op_t op);
53 void range_copy (binmap_t& mask, bin64_t range)
54 { range_op(mask, range, COPY_OP); }
55 void range_remove (binmap_t& mask, bin64_t range)
56 { range_op(mask, range, REMOVE_OP); }
57 void range_or (binmap_t& mask, bin64_t range)
58 { range_op(mask, range, OR_OP); }
59 void range_and (binmap_t& mask, bin64_t range)
60 { range_op(mask, range, AND_OP); }
62 /** Find the leftmost bin within the specified range which is
63 either filled or empty. */
64 bin64_t find (const bin64_t range, fill_t seek=EMPTY) ;
66 /** Find the leftmost bin within the specified range which is
67 either filled or empty. Bins set to 1 in the filter binmap cannot
68 be returned. In fact, this is an incremental bitwise op. */
70 (binmap_t& filter, bin64_t range, fill_t seek=EMPTY) ;
72 /** Bitwise SUB; any bins set to one in the filter binmap should
73 be set to 0 in this binmap. */
74 void remove (binmap_t& filter);
76 void dump(const char* note);
78 /** Represent the binmap as a sequence of 0 and 1 stripes; for each
79 new stripe only the starting offset is given. The first stripe
80 is supposed to be empty (if the (0,0) bin is actually filled,
81 the next stripe will also start at 0). */
82 uint64_t* get_stripes (int& count);
84 /** Return the number of cells allocated in the binmap. */
85 uint32_t size() { return cells_allocated; }
87 uint64_t seq_length ();
89 /** Return the topmost solid bin which covers the specified bin. */
90 bin64_t cover(bin64_t val);
94 /** Return true if the range is solid (either all-0 or 1). If val is
95 specified, the interval must be both solid and filled/empty,
96 depending on the value. */
97 bool is_solid (bin64_t range=bin64_t::ALL, fill_t val=MIXED) ;
98 /** Whether range/bin is empty. */
99 bool is_empty (bin64_t range=bin64_t::ALL) { return is_solid(range,EMPTY); }
100 /** Whether range/bin is filled. */
101 bool is_filled (bin64_t range=bin64_t::ALL) { return is_solid(range,FILLED); }
103 /** Clear everything, empty all bins. */
106 /** Returns whether the int is mixed (not all-1 or all-0). */
107 static bool is_mixed (uint16_t val) { return val!=EMPTY && val!=FILLED; }
108 /** Returns whether the int is solid (0x0 or 0xffff). */
109 static bool is_solid (uint16_t val) { return val==EMPTY || val==FILLED; }
111 /** Twisting is some generalization of XOR. For every 1-bit in the mask,
112 the respective layer of the binary tree is flipped, i.e. left and
113 right change places. Twisting is mostly needed for randomization. */
114 void twist (uint64_t mask);
116 void to_coarse_bitmap (void* bits, bin64_t range, uint8_t height);
120 /** Every 16th uint32 is a flag field denoting whether
121 previous 30 halves (in 15 cells) are deep or not.
122 The last bit is used as a fill-flag.
123 Free cells have a value of 0; neither deep nor flat
124 cell could have a value of 0 except for the root
125 cell in case the binmap is all-0. */
130 uint32_t blocks_allocated;
131 uint32_t cells_allocated;
138 static const uint8_t SPLIT[16];
139 static const uint8_t JOIN[16];
141 bool deep(uint32_t half) const {
142 return cells[(half>>1)|0xf] & (1<<(half&0x1f));
144 void mark(uint32_t half) {
145 cells[(half>>1)|0xf] |= (1<<(half&0x1f));
147 void unmark(uint32_t half) {
148 cells[(half>>1)|0xf] &= ~(1<<(half&0x1f));
153 uint16_t alloc_cell ();
154 void free_cell (uint16_t cell);
156 /** Join the cell this half is pointing to
157 (in other words, flatten the half). */
158 bool join(uint32_t half) ;
160 /** Make the half deep. */
161 void split(uint32_t half) ;
163 static uint32_t split16to32(uint16_t half);
164 static int join32to16(uint32_t cell);
166 void map16 (uint16_t* target, bin64_t range);
168 friend class iterator;
170 FRIEND_TEST(BinsTest,Routines);
175 /** Iterates over bins; for deep halves, bin==half.
176 For flat halves, bin is a range of bits in a half.
177 Iterator may split cells if needed.
178 Value is either undefined (deep cell, mixed cell)
183 uint32_t history[64];
186 bin64_t pos; // TODO: half[] layer bin
188 iterator(binmap_t* host, bin64_t start=bin64_t(0,0), bool split=false);
190 bool deep () { return host->deep(half); }
192 return !deep() && binmap_t::is_solid(host->halves[half]);
194 void sibling () { half^=1; pos=pos.sibling(); }
195 bool end () { return half==1; }
196 void to (bool right);
198 void right() {to(1);}
199 /** Move to the next defined (non-deep, flat) cell.
200 If solid==true, move to a solid (0xffff/0x0) cell. */
201 bin64_t next (bool stop_undeep=true, bool stop_solid=false, uint8_t stop_layer=0);
202 bin64_t next_solid () { return next(false, true,0); }
203 bin64_t bin() { return pos; }
204 void towards(bin64_t bin) {
205 bin64_t next = pos.towards(bin);
206 assert(next!=bin64_t::NONE);
210 bool defined() { return !host->deep(half); }
211 uint16_t& operator* () { return host->halves[half]; }
212 uint8_t layer() const { return layer_; }
224 bool empty() const { return !filled_; }