THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.1KB

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