add .gitignore
[swift-upb.git] / bins.cpp
index 3641138..6376bad 100644 (file)
--- a/bins.cpp
+++ b/bins.cpp
@@ -6,51 +6,80 @@
  *  Copyright 2009 Delft University of Technology. All rights reserved.
  *
  */
-#include "bins.h"
-#include <string.h>
-#include <stdio.h>
+
 #include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <limits>
+#include <numeric>
+#include <utility>
+
+#include "bins.h"
+
+#undef max
 
 // make it work piece by piece
 
-const uint8_t  bins::SPLIT[16] = 
+const uint8_t    binmap_t::SPLIT[16] = 
 {0, 3, 12, 15, 48, 51, 60, 63, 192, 195, 204, 207, 240, 243, 252, 255};
-const uint8_t    bins::JOIN[16] =
+const uint8_t    binmap_t::JOIN[16] =
 {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15};
-const int bins::NOJOIN = 0x10000;
+const int binmap_t::NOJOIN = 0x10000;
+
+
+void binmap_t::extend () {
+    const size_t nblocks = (blocks_allocated != 0) ? (2 * blocks_allocated) : (1);
+
+    if( 16 * nblocks > 1 + std::numeric_limits<uint16_t>::max() )
+        return /* The limit of cells number reached */;
+
+    uint32_t * const ncells = (uint32_t *) realloc(cells, nblocks * 16 * sizeof(uint32_t));
+    if( ncells == NULL )
+        return /* Memory allocation error */;
+
+    size_t blk = nblocks;
+    while( blk-- != blocks_allocated ) {
+        uint16_t const blk_off =  16 * blk;
+        uint16_t * const blk_ptr = reinterpret_cast<uint16_t *>(ncells + blk_off);
 
+        blk_ptr[28] = free_top;
+
+        for(uint16_t i = 13; i != (uint16_t)-1; --i)
+            blk_ptr[2 * i] = blk_off + i + 1;
+
+        free_top = blk_off;
+    }
 
-void bins::extend () {
-    uint16_t nblocks = blocks_allocated ? (blocks_allocated<<1) : 1;
-    size_t had_bytes = blocks_allocated<<6;
-    size_t need_bytes = nblocks<<6;
-    cells = (uint32_t*) realloc(cells,need_bytes);
-    memset(((char*)cells)+had_bytes,0,need_bytes-had_bytes);
-    for(int b=blocks_allocated; b<nblocks; b++)
-        cells[(b<<4)|0xf] = 0x55555555; // cells are free
     blocks_allocated = nblocks;
+    cells = ncells;
+}
+
+binmap_t::binmap_t() :  height(4), blocks_allocated(0), cells(NULL), 
+                free_top(0), cells_allocated(0), twist_mask(0) {
+    alloc_cell();
+    assert( free_top == 1 );
 }
 
-bins::bins() :  height(4), blocks_allocated(0), cells(NULL), 
-                ap(0), cells_allocated(0), twist_mask(0) {
-    extend();
-    assert(!alloc_cell());
+binmap_t::~binmap_t () {
+    if (cells)
+        free(cells);
 }
 
-void bins::twist (uint64_t mask) {
+void binmap_t::twist (uint64_t mask) {
     while ( (1<<height) <= mask )
         extend_range();
     twist_mask = mask;
 }
 
-bins::bins (const bins& b) : height(b.height), ap(b.ap),
+binmap_t::binmap_t (const binmap_t& b) : height(b.height), free_top(b.free_top),
 blocks_allocated(b.blocks_allocated), cells_allocated(b.cells_allocated) {
     size_t memsz = blocks_allocated*16*32;
     cells = (uint32_t*) malloc(memsz);
     memcpy(cells,b.cells,memsz);
 }
 
-void bins::dump (const char* note) {
+void binmap_t::dump (const char* note) {
     printf("%s\t",note);
     for(int i=0; i<(blocks_allocated<<5); i++) {
         if ( (i&0x1f)>29 )
@@ -65,7 +94,7 @@ void bins::dump (const char* note) {
     printf("\n");
 }
 
-uint32_t bins::split16to32(uint16_t halfval) {
+uint32_t binmap_t::split16to32(uint16_t halfval) {
     uint32_t nval = 0;
     for(int i=0; i<4; i++) {
         nval >>= 8;
@@ -76,7 +105,7 @@ uint32_t bins::split16to32(uint16_t halfval) {
 }
 
 
-int bins::join32to16(uint32_t cval) {
+int binmap_t::join32to16(uint32_t cval) {
     union { uint32_t i; uint8_t a[4]; } uvar;
     uvar.i = cval & (cval>>1) & 0x55555555;
     if ( (uvar.i|(uvar.i<<1)) != cval )
@@ -91,7 +120,7 @@ int bins::join32to16(uint32_t cval) {
 }
 
 
-void        bins::split (uint32_t half) {
+void        binmap_t::split (uint32_t half) {
     if (deep(half))
         return;
     uint32_t cell = alloc_cell(), left=cell<<1, right=left+1;
@@ -104,7 +133,7 @@ void        bins::split (uint32_t half) {
 }
 
 
-bool        bins::join (uint32_t half) {
+bool        binmap_t::join (uint32_t half) {
     uint32_t cellno = halves[half];
     int left = cellno<<1, right=left+1;
     if (deep(left) || deep(right))
@@ -120,52 +149,49 @@ bool        bins::join (uint32_t half) {
     return true;
 }
 
-void    bins::free_cell (uint16_t cell) {
-    cells[cell] = 0;
-    int left = cell<<1, right=left+1;
-    mark(left);
-    unmark(right);
-    if (ap==cell+1)
-        ap--;
-    cells_allocated--;
+void    binmap_t::free_cell (uint16_t cell) {
+    --cells_allocated;
+
+    halves[2 * cell] = free_top;
+    free_top = cell;
 }
 
 /** Get a free cell. */
-uint16_t    bins::alloc_cell () {
-    uint16_t ap1 = ap;
-    cells_allocated++;
-    for(; ap<(blocks_allocated<<4); ap++) {
-        if ((ap&0xf)==0xf)
-            continue;
-        if (!cells[ap] && deep(ap<<1)) {
-            unmark(ap<<1);
-            return ap++;
-        }
-    }
-    if (ap1)
-        ap = 0;
-    else
+uint16_t    binmap_t::alloc_cell () {
+    if( cells_allocated == 15 * blocks_allocated )
         extend();
-    cells_allocated--;
-    return alloc_cell();
+    
+    if( cells_allocated == 15 * blocks_allocated ) {
+        assert( free_top != 0 );
+        return 0;
+    }
+    
+    ++cells_allocated;
+    
+    const uint16_t ref = free_top;
+    free_top = halves[2 * ref];
+    
+    cells[ref] = 0;
+    unmark(2 * ref);
+    unmark(2 * ref + 1);
+    
+    return ref;
 }
 
 
-bin64_t iterator::next (bool need_solid) {
-    assert(!deep());
+bin64_t iterator::next (bool stop_undeep, bool stop_solid, uint8_t stop_layer) {
     while (pos.is_right())
         parent();
-    //parent();
-    //if (need_solid ? !solid() : deep())
-    //    right();
     sibling();
-    while (need_solid ? !solid() : deep())
+    while (     (!stop_undeep || deep()) && 
+                (!stop_solid || (deep() || !solid()) ) && 
+                (layer()>stop_layer)      )
         left();
     return pos;
 }
 
 
-iterator::iterator(bins* host_, bin64_t start, bool split) { 
+iterator::iterator(binmap_t* host_, bin64_t start, bool split) { 
     host = host_;
     half = 0;
     for(int i=0; i<64; i++)
@@ -200,7 +226,7 @@ void iterator::to (bool right) {
 }
 
 
-void bins::extend_range () {
+void binmap_t::extend_range () {
     assert(height<62);
     height++;
     uint16_t newroot = alloc_cell();
@@ -231,7 +257,7 @@ void iterator::parent () {
 }
 
 
-bin64_t bins::find (const bin64_t range, fill_t seek) {
+bin64_t binmap_t::find (const bin64_t range, fill_t seek) {
     iterator i(this,range,true);
     fill_t stop = seek==EMPTY ? FILLED : EMPTY;
     while (true) {
@@ -250,7 +276,7 @@ bin64_t bins::find (const bin64_t range, fill_t seek) {
 }
 
 
-uint16_t bins::get (bin64_t bin) {
+uint16_t binmap_t::get (bin64_t bin) {
     if (bin==bin64_t::NONE)
         return EMPTY;
     iterator i(this,bin,true);
@@ -263,26 +289,26 @@ uint16_t bins::get (bin64_t bin) {
 }
 
 
-void bins::clear () {
+void binmap_t::clear () {
     set(bin64_t(height,0),EMPTY);
 }
 
 
-uint64_t bins::mass () {
+uint64_t binmap_t::mass () {
     iterator i(this,bin64_t(0,0),false);
     uint64_t ret = 0;
     while (!i.solid())
         i.left();
     while (!i.end()) {
-        if (*i==bins::FILLED)
+        if (*i==binmap_t::FILLED)
             ret += i.pos.width();
-        i.next(true);
+        i.next_solid();
     }
     return ret;
 }
 
 
-void bins::set (bin64_t bin, fill_t val) {
+void binmap_t::set (bin64_t bin, fill_t val) {
     if (bin==bin64_t::NONE)
         return;
     assert(val==FILLED || val==EMPTY);
@@ -301,11 +327,11 @@ void bins::set (bin64_t bin, fill_t val) {
 }
 
 
-uint64_t*   bins::get_stripes (int& count) {
+uint64_t*   binmap_t::get_stripes (int& count) {
     int size = 32;
     uint64_t *stripes = (uint64_t*) malloc(32*8);
     count = 0;
-    uint16_t cur = bins::EMPTY;
+    uint16_t cur = binmap_t::EMPTY;
     stripes[count++] = 0;
     iterator i(this,bin64_t(0,0),false);
     while (!i.solid())
@@ -322,7 +348,7 @@ uint64_t*   bins::get_stripes (int& count) {
             }
         }
 
-        i.next(true);
+        i.next_solid();
 
     }
 
@@ -333,7 +359,7 @@ uint64_t*   bins::get_stripes (int& count) {
 }
 
 
-void    bins::remove (bins& b) {
+void    binmap_t::remove (binmap_t& b) {
     uint8_t start_lr = b.height>height ? b.height : height;
     bin64_t top(start_lr,0);
     iterator zis(this,top), zat(&b,top);
@@ -352,7 +378,9 @@ void    bins::remove (bins& b) {
 }
 
 
-bin64_t     bins::cover(bin64_t val) {
+bin64_t     binmap_t::cover(bin64_t val) {
+    if (val==bin64_t::NONE)
+        return val;
     iterator i(this,val,false);
     while (i.pos!=val && !i.solid())
         i.towards(val);
@@ -362,8 +390,8 @@ bin64_t     bins::cover(bin64_t val) {
 }
 
 
-bin64_t     bins::find_filtered 
-    (bins& filter, bin64_t range, fill_t seek)  
+bin64_t     binmap_t::find_filtered 
+    (binmap_t& filter, bin64_t range, fill_t seek)  
 {
     if (range==bin64_t::ALL)
         range = bin64_t ( height>filter.height ? height : filter.height, 0 );
@@ -373,7 +401,8 @@ bin64_t     bins::find_filtered
         while ( 
                 fi.deep() ?
                 (ti.deep() || *ti!=stop)  :
-                (ti.deep() ? *fi!=FILLED : ( ((*ti^stop)&~*fi) && (*ti!=seek || *fi!=EMPTY) ) ) 
+                (ti.deep() ? *fi!=FILLED : 
+                    ( ((*ti^stop)&~*fi) && (*ti!=seek || *fi!=EMPTY) ) ) 
               ) 
         {
             ti.left(); fi.left();                
@@ -389,17 +418,28 @@ bin64_t     bins::find_filtered
     return bin64_t::NONE;    
 }
 
-// FIXME unite with remove(); do bitwise()
-void        bins::copy_range (bins& origin, bin64_t range) { 
+void        binmap_t::range_op (binmap_t& mask, bin64_t range, bin_op_t op) {
     if (range==bin64_t::ALL)
-        range = bin64_t ( height>origin.height ? height : origin.height, 0 );
-    iterator zis(this,range,true), zat(&origin,range,true);
+        range = bin64_t ( height>mask.height ? height : mask.height, 0 );
+    iterator zis(this,range,true), zat(&mask,range,true);
     while (zis.pos.within(range)) {
         while (zis.deep() || zat.deep()) {
             zis.left(); zat.left();
         }
-        
-        *zis = *zat;
+
+        switch (op) {
+            case REMOVE_OP:
+                *zis &= ~*zat;
+                break;
+            case AND_OP:
+                *zis &= *zat;
+                break;
+            case COPY_OP:
+                *zis = *zat;
+                break;
+            case OR_OP:
+                *zis |= *zat;
+        }
         
         while (zis.pos.is_right()) {
             zis.parent(); zat.parent();
@@ -408,8 +448,8 @@ void        bins::copy_range (bins& origin, bin64_t range) {
     }
 }
 
-uint64_t    bins::seq_length () {
-    iterator i(this);
+uint64_t    binmap_t::seq_length () {
+    iterator i(this,bin64_t(height,0));
     if (!i.deep() && *i==FILLED)
         return i.pos.width();
     while (!i.pos.is_base()) {
@@ -422,7 +462,7 @@ uint64_t    bins::seq_length () {
 }
 
 
-bool        bins::is_solid (bin64_t range, fill_t val)  {
+bool        binmap_t::is_solid (bin64_t range, fill_t val)  {
     if (range==bin64_t::ALL) 
         return !deep(0) && (is_mixed(val) || halves[0]==val);
     iterator i(this,range,false);
@@ -432,6 +472,37 @@ bool        bins::is_solid (bin64_t range, fill_t val)  {
 }
 
 
+void    binmap_t::map16 (uint16_t* target, bin64_t range) {
+    iterator lead(this,range,true);
+    if (!lead.deep()) {
+        *target = *lead;
+        return;
+    }
+    lead.left();
+    lead.left();
+    lead.left();
+    lead.left();
+    uint16_t shift = 1;
+    for(int i=0; i<16; i++) {
+        if (!lead.deep() && *lead==FILLED)
+            *target |= shift;
+        shift<<=1;
+        lead.next(false,false,range.layer()-4);
+    }
+}
+
+
+void    binmap_t::to_coarse_bitmap (uint16_t* bits, bin64_t range, uint8_t height) {
+    //assert(range.layer()-height>=4);
+    int height16 = range.layer()-height-4;
+    int wordwidth = height16 > 0 ? (1 << height16) : 1;
+    int offset = height16 > 0 ? (range.offset() << height16) : 
+                                (range.offset() >> -height16); 
+    for(int i=0; i<wordwidth; i++) 
+        map16(bits+i,bin64_t(height+4,offset+i));
+}
+
+
 binheap::binheap() {
     size_ = 32;
     heap_ = (bin64_t*) malloc(size_*sizeof(bin64_t));
@@ -487,3 +558,4 @@ void    binheap::push(bin64_t val) {
 binheap::~binheap() {
     free(heap_);
 }
+