Skip to content

Commit

Permalink
ccan: Added ccan/intmap
Browse files Browse the repository at this point in the history
  • Loading branch information
cdecker authored and rustyrussell committed Feb 2, 2017
1 parent 999472d commit 05cf316
Show file tree
Hide file tree
Showing 9 changed files with 893 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ CCAN_OBJS := \
ccan-htable.o \
ccan-ilog.o \
ccan-io-io.o \
ccan-intmap.o \
ccan-io-poll.o \
ccan-io-fdpass.o \
ccan-isaac.o \
Expand Down Expand Up @@ -130,6 +131,7 @@ CCAN_HEADERS := \
$(CCANDIR)/ccan/htable/htable.h \
$(CCANDIR)/ccan/htable/htable_type.h \
$(CCANDIR)/ccan/ilog/ilog.h \
$(CCANDIR)/ccan/intmap/intmap.h \
$(CCANDIR)/ccan/io/backend.h \
$(CCANDIR)/ccan/io/fdpass/fdpass.h \
$(CCANDIR)/ccan/io/io.h \
Expand Down Expand Up @@ -438,6 +440,8 @@ ccan-htable.o: $(CCANDIR)/ccan/htable/htable.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-ilog.o: $(CCANDIR)/ccan/ilog/ilog.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-intmap.o: $(CCANDIR)/ccan/intmap/intmap.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-isaac.o: $(CCANDIR)/ccan/isaac/isaac.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-isaac64.o: $(CCANDIR)/ccan/isaac/isaac64.c
Expand Down
1 change: 1 addition & 0 deletions ccan/ccan/intmap/LICENSE
34 changes: 34 additions & 0 deletions ccan/ccan/intmap/_info
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "config.h"
#include <stdio.h>
#include <string.h>

/**
* intmap - ordered map integers to various types
*
* This code an ordered map of strings to values
*
* This code implements an ordered map of strings as a critbit tree. See:
*
* http://cr.yp.to/critbit.html
* http://github.com/agl/critbit (which this code is based on)
*
* License: CC0
* Author: Rusty Russell <[email protected]>
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;

if (strcmp(argv[1], "depends") == 0) {
printf("ccan/ilog\n"
"ccan/short_types\n"
"ccan/str\n"
"ccan/tcon\n"
"ccan/typesafe_cb\n");
return 0;
}

return 1;
}
214 changes: 214 additions & 0 deletions ccan/ccan/intmap/intmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/* CC0 license (public domain) - see LICENSE file for details */
/* This code is based on ccan/strmap.c. */
#include <ccan/intmap/intmap.h>
#include <ccan/short_types/short_types.h>
#include <ccan/str/str.h>
#include <ccan/ilog/ilog.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>

struct node {
/* These point to strings or nodes. */
struct intmap child[2];
/* The bit where these children differ (0 == lsb) */
u8 bit_num;
};

/* Closest member to this in a non-empty map. */
static struct intmap *closest(struct intmap *n, intmap_index_t index)
{
/* Anything with NULL value is a node. */
while (!n->v) {
u8 direction = (index >> n->u.n->bit_num) & 1;
n = &n->u.n->child[direction];
}
return n;
}

void *intmap_get_(const struct intmap *map, intmap_index_t index)
{
struct intmap *n;

/* Not empty map? */
if (!intmap_empty_(map)) {
n = closest((struct intmap *)map, index);
if (index == n->u.i)
return n->v;
}
errno = ENOENT;
return NULL;
}

bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value)
{
struct intmap *n;
struct node *newn;
u8 bit_num, new_dir;

assert(value);

/* Empty map? */
if (intmap_empty_(map)) {
map->u.i = index;
map->v = (void *)value;
return true;
}

/* Find closest existing member. */
n = closest(map, index);

/* Find highest bit where they differ. */
bit_num = ilog64(n->u.i ^ index);
if (bit_num == 0) {
errno = EEXIST;
return false;
}
bit_num--;

assert(bit_num < CHAR_BIT*sizeof(index));

/* Which direction do we go at this bit? */
new_dir = (index >> bit_num) & 1;

/* Allocate new node. */
newn = malloc(sizeof(*newn));
if (!newn) {
errno = ENOMEM;
return false;
}
newn->bit_num = bit_num;
newn->child[new_dir].v = (void *)value;
newn->child[new_dir].u.i = index;

/* Find where to insert: not closest, but first which differs! */
n = map;
while (!n->v) {
u8 direction;

/* Subtle: bit numbers are "backwards" for comparison */
if (n->u.n->bit_num < bit_num)
break;

direction = (index >> n->u.n->bit_num) & 1;
n = &n->u.n->child[direction];
}

newn->child[!new_dir] = *n;
n->u.n = newn;
n->v = NULL;
return true;
}

void *intmap_del_(struct intmap *map, intmap_index_t index)
{
struct intmap *parent = NULL, *n;
u8 direction;
void *value;

/* Empty map? */
if (intmap_empty_(map)) {
errno = ENOENT;
return NULL;
}

/* Find closest, but keep track of parent. */
n = map;
/* Anything with NULL value is a node. */
while (!n->v) {
parent = n;
direction = (index >> n->u.n->bit_num) & 1;
n = &n->u.n->child[direction];
}

/* Did we find it? */
if (index != n->u.i) {
errno = ENOENT;
return NULL;
}

value = n->v;

if (!parent) {
/* We deleted last node. */
intmap_init_(map);
} else {
struct node *old = parent->u.n;
/* Raise other node to parent. */
*parent = old->child[!direction];
free(old);
}
errno = 0;
return value;
}

void *intmap_first_(const struct intmap *map, intmap_index_t *indexp)
{
const struct intmap *n;

if (intmap_empty_(map)) {
errno = ENOENT;
return NULL;
}

n = map;
/* Anything with NULL value is a node. */
while (!n->v)
n = &n->u.n->child[0];
errno = 0;
*indexp = n->u.i;
return n->v;
}

void *intmap_after_(const struct intmap *map, intmap_index_t *indexp)
{
const struct intmap *n, *prev = NULL;

/* Special case of empty map */
if (intmap_empty_(map)) {
errno = ENOENT;
return NULL;
}

/* Follow down, track the last place where we could have set a bit
* instead of clearing it: this is the higher alternative tree. */
n = map;
while (!n->v) {
u8 direction = (*indexp >> n->u.n->bit_num) & 1;
if (!direction)
prev = n;
n = &n->u.n->child[direction];
}

/* Found a successor? */
if (n->u.i > *indexp) {
errno = 0;
*indexp = n->u.i;
return n->v;
}

/* Nowhere to go back up to? */
if (!prev) {
errno = ENOENT;
return NULL;
}

/* Get first one from that other branch. */
return intmap_first_(&prev->u.n->child[1], indexp);
}

static void clear(struct intmap n)
{
if (!n.v) {
clear(n.u.n->child[0]);
clear(n.u.n->child[1]);
free(n.u.n);
}
}

void intmap_clear_(struct intmap *map)
{
if (!intmap_empty_(map))
clear(*map);
intmap_init_(map);
}
Loading

0 comments on commit 05cf316

Please sign in to comment.