1#include"cache.h" 2#include"sha1-lookup.h" 3 4static uint32_ttake2(const unsigned char*sha1) 5{ 6return((sha1[0] <<8) | sha1[1]); 7} 8 9/* 10 * Conventional binary search loop looks like this: 11 * 12 * do { 13 * int mi = lo + (hi - lo) / 2; 14 * int cmp = "entry pointed at by mi" minus "target"; 15 * if (!cmp) 16 * return (mi is the wanted one) 17 * if (cmp > 0) 18 * hi = mi; "mi is larger than target" 19 * else 20 * lo = mi+1; "mi is smaller than target" 21 * } while (lo < hi); 22 * 23 * The invariants are: 24 * 25 * - When entering the loop, lo points at a slot that is never 26 * above the target (it could be at the target), hi points at a 27 * slot that is guaranteed to be above the target (it can never 28 * be at the target). 29 * 30 * - We find a point 'mi' between lo and hi (mi could be the same 31 * as lo, but never can be the same as hi), and check if it hits 32 * the target. There are three cases: 33 * 34 * - if it is a hit, we are happy. 35 * 36 * - if it is strictly higher than the target, we update hi with 37 * it. 38 * 39 * - if it is strictly lower than the target, we update lo to be 40 * one slot after it, because we allow lo to be at the target. 41 * 42 * When choosing 'mi', we do not have to take the "middle" but 43 * anywhere in between lo and hi, as long as lo <= mi < hi is 44 * satisfied. When we somehow know that the distance between the 45 * target and lo is much shorter than the target and hi, we could 46 * pick mi that is much closer to lo than the midway. 47 */ 48/* 49 * The table should contain "nr" elements. 50 * The sha1 of element i (between 0 and nr - 1) should be returned 51 * by "fn(i, table)". 52 */ 53intsha1_pos(const unsigned char*sha1,void*table,size_t nr, 54 sha1_access_fn fn) 55{ 56size_t hi = nr; 57size_t lo =0; 58size_t mi =0; 59 60if(!nr) 61return-1; 62 63if(nr !=1) { 64size_t lov, hiv, miv, ofs; 65 66for(ofs =0; ofs <18; ofs +=2) { 67 lov =take2(fn(0, table) + ofs); 68 hiv =take2(fn(nr -1, table) + ofs); 69 miv =take2(sha1 + ofs); 70if(miv < lov) 71return-1; 72if(hiv < miv) 73return-1- nr; 74if(lov != hiv) { 75/* 76 * At this point miv could be equal 77 * to hiv (but sha1 could still be higher); 78 * the invariant of (mi < hi) should be 79 * kept. 80 */ 81 mi = (nr -1) * (miv - lov) / (hiv - lov); 82if(lo <= mi && mi < hi) 83break; 84BUG("assertion failed in binary search"); 85} 86} 87} 88 89do{ 90int cmp; 91 cmp =hashcmp(fn(mi, table), sha1); 92if(!cmp) 93return mi; 94if(cmp >0) 95 hi = mi; 96else 97 lo = mi +1; 98 mi = lo + (hi - lo) /2; 99}while(lo < hi); 100return-lo-1; 101} 102 103intbsearch_hash(const unsigned char*sha1,const uint32_t*fanout_nbo, 104const unsigned char*table,size_t stride,uint32_t*result) 105{ 106uint32_t hi, lo; 107 108 hi =ntohl(fanout_nbo[*sha1]); 109 lo = ((*sha1 ==0x0) ?0:ntohl(fanout_nbo[*sha1 -1])); 110 111while(lo < hi) { 112unsigned mi = lo + (hi - lo) /2; 113int cmp =hashcmp(table + mi * stride, sha1); 114 115if(!cmp) { 116if(result) 117*result = mi; 118return1; 119} 120if(cmp >0) 121 hi = mi; 122else 123 lo = mi +1; 124} 125 126if(result) 127*result = lo; 128return0; 129}