/* * sophia database * sphia.org * * Copyright (c) Dmitry Simonenko * BSD License */ #include static inline int sp_catensure(spcat *c) { if ((c->count + 1) < c->top) return 0; c->top *= 2; c->i = realloc(c->i, c->top * sizeof(sppage*)); if (c->i == NULL) return -1; return 0; } int sp_catinit(spcat *c, spa *a, int top, spcmpf cmp, void *cmparg) { c->a = a; c->cmp = cmp; c->cmparg = cmparg; c->count = 0; c->top = top; c->i = sp_malloc(a, sizeof(sppage*) * top); if (spunlikely(c->i == NULL)) return -1; return 0; } void sp_catfree(spcat *c) { uint32_t p = 0; while (p < c->count) { sp_free(c->a, c->i[p]->min); sp_free(c->a, c->i[p]->max); sp_free(c->a, c->i[p]); p++; } sp_free(c->a, c->i); } static inline int cmppage(spcat *c, sppage *p, sppage *v) { int l = c->cmp(p->min->key, p->min->size, v->min->key, v->min->size, c->cmparg); assert(l == c->cmp(p->max->key, p->max->size, v->max->key, v->max->size, c->cmparg)); return l; } static inline sppage* sp_catsearch(spcat *c, sppage *v, uint32_t *index) { int min = 0; int max = c->count - 1; while (max >= min) { int mid = min + ((max - min) >> 1); switch (cmppage(c, c->i[mid], v)) { case -1: min = mid + 1; continue; case 1: max = mid - 1; continue; default: *index = mid; return c->i[mid]; } } *index = min; return NULL; } int sp_catset(spcat *c, sppage *n, sppage **o) { uint32_t i; sppage *p = sp_catsearch(c, n, &i); if (p) { /* replace */ *o = c->i[i]; c->i[i] = p; return 0; } /* insert */ int rc = sp_catensure(c); if (spunlikely(rc == -1)) return -1; /* split page index and insert new page */ memmove(&c->i[i + 1], &c->i[i], sizeof(sppage*) * (c->count - i)); c->i[i] = n; c->count++; *o = NULL; return 0; } int sp_catdel(spcat *c, uint32_t idx) { assert(idx < c->count); if (splikely(idx != (uint32_t)(c->count-1))) memmove(&c->i[idx], &c->i[idx + 1], sizeof(sppage*) * (c->count - idx - 1)); c->count--; return 0; } static inline int cmpkey(spcat *c, sppage *p, void *rkey, int size) { register int l = c->cmp(p->min->key, p->min->size, rkey, size, c->cmparg); register int r = c->cmp(p->max->key, p->max->size, rkey, size, c->cmparg); /* inside page range */ if (l <= 0 && r >= 0) return 0; /* key > page */ if (l == -1) return -1; /* key < page */ assert(r == 1); return 1; } inline sppage* sp_catfind(spcat *c, char *rkey, int size, uint32_t *index) { register int min = 0; register int max = c->count - 1; while (max >= min) { register int mid = min + ((max - min) >> 1); switch (cmpkey(c, c->i[mid], rkey, size)) { case -1: min = mid + 1; continue; case 1: max = mid - 1; continue; default: *index = mid; return c->i[mid]; } } *index = min; return NULL; } sppage *sp_catroute(spcat *c, char *rkey, int size, uint32_t *idx) { if (spunlikely(c->count == 1)) return c->i[0]; uint32_t i; sppage *p = sp_catfind(c, rkey, size, &i); if (splikely(p)) { *idx = i; return p; } if (spunlikely(i >= c->count)) i = c->count - 1; if (i > 0 && c->cmp(c->i[i]->min->key, c->i[i]->min->size, rkey, size, c->cmparg) == 1) { i = i - 1; } if (idx) *idx = i; return c->i[i]; } int sp_catown(spcat *c, uint32_t idx, spv *v) { register sppage *p = c->i[idx]; /* equal or equal min or equal max */ switch (cmpkey(c, p, v->key, v->size)) { case 0: return 1; case -1: /* key > page */ /* key > max */ if (idx == c->count-1) return 1; break; case 1: /* key < page */ /* key < min */ if (idx == 0) return 1; break; } /* key > page && key < page+1.min */ if (c->cmp(v->key, v->size, c->i[idx + 1]->min->key, c->i[idx + 1]->min->size, c->cmparg) == -1) return 1; return 0; }