add .gitignore
[swift-upb.git] / bins.h
diff --git a/bins.h b/bins.h
index 45ef4ea..df48c48 100644 (file)
--- a/bins.h
+++ b/bins.h
@@ -1,6 +1,6 @@
 /*
  *  sbit.cpp
- *  serp++
+ *  binmap, a hybrid of bitmap and binary tree
  *
  *  Created by Victor Grishchenko on 3/28/09.
  *  Copyright 2009 Delft University of Technology. All rights reserved.
 #define BINS_H
 #include "bin64.h"
 
-/**  A binmap covering 2^64 range. Complexity limit: 100+200LoC  */
-class bins {
+class iterator; // FIXME shame
+
+/** A binmap covering 2^64 range. Binmap is a hybrid of a bitmap (aka
+    bit vector) and a binary tree. The key ability of a binmap is
+    the aggregation of solid (all-0 or all-1) ranges. */
+class binmap_t {
     
 public:
-    typedef enum { FILLED=0xffff, EMPTY=0x0000 } fill_t;
+    /** Need a 3-valued logic as a range might be either all-0 or all-1
+        or some mix. In fact, any value different from 0x0 or 0xffff
+        must be interpreted as MIXED. 
+        All read/write operations on a binmap are made in terms of
+        aligned binary intervals (bins).
+     */
+    typedef enum { FILLED=0xffff, EMPTY=0x0000, MIXED=0x5555 } fill_t;
     static const int NOJOIN;
     
-    bins();
+    binmap_t();
     
-    bins(const bins& b);
+    /** Copying constructor. */
+    binmap_t(const binmap_t& b);
     
+    /** Destructor. */
+    ~binmap_t(); 
+
+    /** Get value for the bin. */
     uint16_t    get (bin64_t bin); 
     
+    /** Set value for the bin. */
     void        set (bin64_t bin, fill_t val=FILLED); 
     
-    void        copy_range (bins& origin, bin64_t range);
-    
+    typedef enum {
+        OR_OP,
+        AND_OP,
+        REMOVE_OP,
+        COPY_OP
+    } bin_op_t;
+    
+    /** Copy a range from another binmap. */
+    void        range_op (binmap_t& mask, bin64_t range, bin_op_t op);
+    void        range_copy (binmap_t& mask, bin64_t range)
+        {   range_op(mask, range, COPY_OP);   }
+    void        range_remove (binmap_t& mask, bin64_t range)
+        {   range_op(mask, range, REMOVE_OP);   }
+    void        range_or (binmap_t& mask, bin64_t range)
+        {   range_op(mask, range, OR_OP);   }
+    void        range_and (binmap_t& mask, bin64_t range)
+        {   range_op(mask, range, AND_OP);   }
+    
+    /** Find the leftmost bin within the specified range which is
+        either filled or empty. */
     bin64_t     find (const bin64_t range, fill_t seek=EMPTY) ;
     
+    /** Find the leftmost bin within the specified range which is
+        either filled or empty. Bins set to 1 in the filter binmap cannot
+        be returned. In fact, this is an incremental bitwise op. */
     bin64_t     find_filtered
-        (bins& filter, bin64_t range, fill_t seek=EMPTY) ;
+        (binmap_t& filter, bin64_t range, fill_t seek=EMPTY) ;
     
-    void        remove (bins& b);
+    /** Bitwise SUB; any bins set to one in the filter binmap should
+        be set to 0 in this binmap. */
+    void        remove (binmap_t& filter);
     
     void        dump(const char* note);
 
+    /** Represent the binmap as a sequence of 0 and 1 stripes; for each
+        new stripe only the starting offset is given. The first stripe
+        is supposed to be empty (if the (0,0) bin is actually filled,
+        the next stripe will also start at 0). */
     uint64_t*   get_stripes (int& count);
 
+    /** Return the number of cells allocated in the binmap. */
     uint32_t    size() { return cells_allocated; }
     
     uint64_t    seq_length ();
     
+    /** Return the topmost solid bin which covers the specified bin. */
     bin64_t     cover(bin64_t val);
 
     uint64_t    mass ();
     
-    bool        is_empty () const { return !deep(0) && !halves[0]; }
+    /** Return true if the range is solid (either all-0 or 1). If val is
+        specified, the interval must be both solid and filled/empty,
+        depending on the value. */
+    bool        is_solid (bin64_t range=bin64_t::ALL, fill_t val=MIXED) ;
+    /** Whether range/bin is empty. */
+    bool        is_empty (bin64_t range=bin64_t::ALL) { return is_solid(range,EMPTY); }
+    /** Whether range/bin is filled. */
+    bool        is_filled (bin64_t range=bin64_t::ALL) { return is_solid(range,FILLED); }
 
+    /** Clear everything, empty all bins. */
     void        clear ();
     
+    /** Returns whether the int is mixed (not all-1 or all-0). */
     static bool is_mixed (uint16_t val) { return val!=EMPTY && val!=FILLED; }
+    /** Returns whether the int is solid (0x0 or 0xffff). */
+    static bool is_solid (uint16_t val) { return val==EMPTY || val==FILLED; }
 
+    /** Twisting is some generalization of XOR. For every 1-bit in the mask,
+        the respective layer of the binary tree is flipped, i.e. left and
+        right change places. Twisting is mostly needed for randomization.  */
     void        twist (uint64_t mask);
     
+    /** Convert binmap to a conventional flat bitmap; only bits corresponding
+        to solid filled bins are set to 1.
+        @param range  the bin (the range) to cover
+        @param height aggregation level; use 2**height bins (2**height base
+                layer bits per one bitmap bit). 
+        @param bits   uint16_t array to put bitmap into; must have enough
+                      of space, i.e. 2**(range.layer()-height-4) cells.  */
+    void        to_coarse_bitmap (uint16_t* bits, bin64_t range, uint8_t height);
+    
 private:
     
     /** Every 16th uint32 is a flag field denoting whether
@@ -69,8 +137,8 @@ private:
     uint32_t    blocks_allocated;
     uint32_t    cells_allocated;
     int         height;
-    uint32_t    ap;
     uint64_t    twist_mask;
+    uint16_t    free_top;
     
     void extend();
     
@@ -101,6 +169,8 @@ private:
     
     static uint32_t split16to32(uint16_t half);
     static int join32to16(uint32_t cell);
+
+    void        map16 (uint16_t* target, bin64_t range);
     
     friend class iterator;
 #ifdef FRIEND_TEST
@@ -116,18 +186,17 @@ private:
  or FILLED/EMPTY. */
 class iterator {
 public: // rm this
-    bins        *host;
+    binmap_t        *host;
     uint32_t    history[64];
     uint32_t    half;
     uint8_t     layer_;
     bin64_t     pos;  // TODO: half[] layer bin
 public:
-    iterator(bins* host, bin64_t start=bin64_t(0,0), bool split=false);
+    iterator(binmap_t* host, bin64_t start=bin64_t(0,0), bool split=false);
     ~iterator();
     bool deep () { return host->deep(half); }
     bool solid () { 
-        return !deep() && (host->halves[half]==bins::FILLED || 
-                host->halves[half]==bins::EMPTY); 
+        return !deep() && binmap_t::is_solid(host->halves[half]); 
     }
     void sibling () { half^=1; pos=pos.sibling(); }
     bool end () { return half==1; }
@@ -136,7 +205,8 @@ public:
     void right() {to(1);}
     /** Move to the next defined (non-deep, flat) cell.
         If solid==true, move to a solid (0xffff/0x0) cell. */
-    bin64_t next (bool solid=false);
+    bin64_t next (bool stop_undeep=true, bool stop_solid=false, uint8_t stop_layer=0);
+    bin64_t next_solid () { return next(false, true,0); }
     bin64_t bin() { return pos; }
     void towards(bin64_t bin) {
         bin64_t next = pos.towards(bin);