This source file includes following definitions.
- pack_revindex_ix
- init_pack_revindex
- sort_revindex
- create_pack_revindex
- revindex_for_pack
- find_revindex_position
- find_pack_revindex
#include "cache.h"
#include "pack-revindex.h"
static struct pack_revindex *pack_revindex;
static int pack_revindex_hashsz;
static int pack_revindex_ix(struct packed_git *p)
{
unsigned long ui = (unsigned long)(intptr_t)p;
int i;
ui = ui ^ (ui >> 16);
i = (int)(ui % pack_revindex_hashsz);
while (pack_revindex[i].p) {
if (pack_revindex[i].p == p)
return i;
if (++i == pack_revindex_hashsz)
i = 0;
}
return -1 - i;
}
static void init_pack_revindex(void)
{
int num;
struct packed_git *p;
for (num = 0, p = packed_git; p; p = p->next)
num++;
if (!num)
return;
pack_revindex_hashsz = num * 11;
pack_revindex = xcalloc(pack_revindex_hashsz, sizeof(*pack_revindex));
for (p = packed_git; p; p = p->next) {
num = pack_revindex_ix(p);
num = - 1 - num;
pack_revindex[num].p = p;
}
}
static void sort_revindex(struct revindex_entry *entries, unsigned n, off_t max)
{
#define DIGIT_SIZE (16)
#define BUCKETS (1 << DIGIT_SIZE)
#define BUCKET_FOR(a, i, bits) (((a)[(i)].offset >> (bits)) & (BUCKETS-1))
struct revindex_entry *tmp = xmalloc(n * sizeof(*tmp));
struct revindex_entry *from = entries, *to = tmp;
int bits;
unsigned *pos = xmalloc(BUCKETS * sizeof(*pos));
for (bits = 0; max >> bits; bits += DIGIT_SIZE) {
struct revindex_entry *swap;
unsigned i;
memset(pos, 0, BUCKETS * sizeof(*pos));
for (i = 0; i < n; i++)
pos[BUCKET_FOR(from, i, bits)]++;
for (i = 1; i < BUCKETS; i++)
pos[i] += pos[i-1];
for (i = n - 1; i != UINT_MAX; i--)
to[--pos[BUCKET_FOR(from, i, bits)]] = from[i];
swap = from;
from = to;
to = swap;
}
if (from != entries)
memcpy(entries, tmp, n * sizeof(*entries));
free(tmp);
free(pos);
#undef BUCKET_FOR
#undef BUCKETS
#undef DIGIT_SIZE
}
static void create_pack_revindex(struct pack_revindex *rix)
{
struct packed_git *p = rix->p;
unsigned num_ent = p->num_objects;
unsigned i;
const char *index = p->index_data;
rix->revindex = xmalloc(sizeof(*rix->revindex) * (num_ent + 1));
index += 4 * 256;
if (p->index_version > 1) {
const uint32_t *off_32 =
(uint32_t *)(index + 8 + p->num_objects * (20 + 4));
const uint32_t *off_64 = off_32 + p->num_objects;
for (i = 0; i < num_ent; i++) {
uint32_t off = ntohl(*off_32++);
if (!(off & 0x80000000)) {
rix->revindex[i].offset = off;
} else {
rix->revindex[i].offset =
((uint64_t)ntohl(*off_64++)) << 32;
rix->revindex[i].offset |=
ntohl(*off_64++);
}
rix->revindex[i].nr = i;
}
} else {
for (i = 0; i < num_ent; i++) {
uint32_t hl = *((uint32_t *)(index + 24 * i));
rix->revindex[i].offset = ntohl(hl);
rix->revindex[i].nr = i;
}
}
rix->revindex[num_ent].offset = p->pack_size - 20;
rix->revindex[num_ent].nr = -1;
sort_revindex(rix->revindex, num_ent, p->pack_size);
}
struct pack_revindex *revindex_for_pack(struct packed_git *p)
{
int num;
struct pack_revindex *rix;
if (!pack_revindex_hashsz)
init_pack_revindex();
num = pack_revindex_ix(p);
if (num < 0)
die("internal error: pack revindex fubar");
rix = &pack_revindex[num];
if (!rix->revindex)
create_pack_revindex(rix);
return rix;
}
int find_revindex_position(struct pack_revindex *pridx, off_t ofs)
{
int lo = 0;
int hi = pridx->p->num_objects + 1;
struct revindex_entry *revindex = pridx->revindex;
do {
unsigned mi = lo + (hi - lo) / 2;
if (revindex[mi].offset == ofs) {
return mi;
} else if (ofs < revindex[mi].offset)
hi = mi;
else
lo = mi + 1;
} while (lo < hi);
error("bad offset for revindex");
return -1;
}
struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs)
{
struct pack_revindex *pridx = revindex_for_pack(p);
int pos = find_revindex_position(pridx, ofs);
if (pos < 0)
return NULL;
return pridx->revindex + pos;
}