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) / 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; 84die("BUG: 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 = (hi + lo) /2; 99}while(lo < hi); 100return-lo-1; 101}