new file mode 100644
@@ -0,0 +1,122 @@
+/* radixlink.c - on-disk radixtree index pointing to linked list data
+ *
+ * Copyright 2017 Facebook, Inc.
+ *
+ * This software may be used and distributed according to the terms of the
+ * GNU General Public License version 2 or any later version. */
+
+#include <stdlib.h>
+#include "radixlink.h"
+
+/* safe read utilities (assuming "return -1" is error reporting) */
+#define read8(dest, rlbuf, offset) \
+ if (rlbuf->size < (offset) + 1) return -1; \
+ else dest = rlbuf->buf[(offset)];
+#define read16(dest, rlbuf, offset) \
+ if (rlbuf->size < (offset) + 2) return -1; \
+ else dest = getbeuint16((const char *)(rlbuf->buf + (offset)));
+#define read32(dest, rlbuf, offset) \
+ if (rlbuf->size < (offset) + 4) return -1; \
+ else dest = getbe32((const char *)(rlbuf->buf + (offset)));
+
+#define getb16(dest, key, boffset) { \
+ uint8_t _v = key[(boffset) / 2]; \
+ dest = ((boffset) & 1) ? (_v & 0xf) : (_v >> 4); }
+
+static const uint8_t RADIX_TYPE = 0;
+static const uint8_t LEAF_TYPE = 1;
+
+static int comparebkey(size_t boff, const uint8_t k[], size_t klen, /* bytes */
+ const uint8_t b[], size_t blen /* base16 */)
+{
+ if (klen * 2 - boff != blen)
+ return -1;
+ for (size_t i = 0; i < blen; ++i) {
+ uint8_t v;
+ getb16(v, k, boff);
+ boff += 1;
+ if (v != b[i])
+ return -1;
+ }
+ return 0;
+}
+
+static int follow(radixlink_buffer_t *index, const uint8_t key[], size_t keylen,
+ uint32_t *pioff, size_t *pboff, uint32_t *ppoff)
+{
+ uint8_t type;
+ read8(type, index, *pioff);
+ if (type == LEAF_TYPE) {
+ size_t koff = (*pioff) + 1 + 4;
+ uint16_t klen;
+ int c;
+ read16(klen, index, koff);
+ koff += 2;
+ if (index->size < koff + klen)
+ return -1;
+ c = comparebkey(*pboff, key, keylen, index->buf + koff, klen);
+ if (c == 0) /* matched */
+ *pboff = keylen * 2;
+ else /* not matched */
+ *pioff = 0;
+ return 0;
+ } else if (type == RADIX_TYPE) {
+ uint32_t nextioff;
+ uint8_t v;
+ uint32_t poff;
+ getb16(v, key, *pboff);
+ poff = *pioff + 1 + v * 4;
+ read32(nextioff, index, poff);
+ *pioff = nextioff;
+ *pboff += 1;
+ *ppoff = poff;
+ return 0;
+ }
+ return -1;
+}
+
+static int readlinkoffset(radixlink_buffer_t *index, uint32_t *pioff,
+ uint32_t *ploff)
+{
+ uint8_t type;
+ uint32_t ioff = *pioff;
+ read8(type, index, ioff);
+ if (type != LEAF_TYPE)
+ return -1;
+ ioff += 1;
+ read32(*ploff, index, ioff);
+ *pioff = ioff;
+ return 0;
+}
+
+int radixlink_index_find(radixlink_buffer_t *index, const uint8_t key[],
+ size_t keylen, uint32_t *ploffset)
+{
+ uint32_t ioff = 8;
+ size_t boff = 0;
+ uint32_t poff = 0;
+ while (boff < keylen * 2) {
+ if (follow(index, key, keylen, &ioff, &boff, &poff) != 0)
+ return -1;
+ if (ioff == 0) {
+ *ploffset = 0;
+ return 0;
+ }
+ }
+
+ if (readlinkoffset(index, &ioff, ploffset) != 0)
+ return -1;
+
+ return 0;
+}
+
+int radixlink_link_read(radixlink_buffer_t *link, uint32_t *pvalue,
+ uint32_t *ploffset)
+{
+ uint32_t loff = *ploffset;
+ uint32_t nextloff;
+ read32(nextloff, link, loff);
+ read32(*pvalue, link, loff + 4);
+ *ploffset = nextloff;
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,16 @@
+#ifndef _HG_RADIXLINK_H_
+#define _HG_RADIXLINK_H_
+
+#include "bitmanipulation.h"
+
+typedef struct {
+ uint8_t *buf;
+ size_t size;
+} radixlink_buffer_t;
+
+int radixlink_index_find(radixlink_buffer_t *index, const uint8_t key[],
+ size_t keylen, uint32_t *ploffset);
+
+int radixlink_link_read(radixlink_buffer_t *link, uint32_t *pvalue,
+ uint32_t *ploffset);
+#endif