Commit b796c031 authored by Rusty Russell's avatar Rusty Russell

intmap: clean up iterators.

By returning the value, we have a nice sentinal and we save a second lookup
if they want it.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent d9e93014
...@@ -142,13 +142,13 @@ void *intmap_del_(struct intmap *map, intmap_index_t index) ...@@ -142,13 +142,13 @@ void *intmap_del_(struct intmap *map, intmap_index_t index)
return value; return value;
} }
intmap_index_t intmap_first_(const struct intmap *map) void *intmap_first_(const struct intmap *map, intmap_index_t *indexp)
{ {
const struct intmap *n; const struct intmap *n;
if (intmap_empty_(map)) { if (intmap_empty_(map)) {
errno = ENOENT; errno = ENOENT;
return UINTMAP_NONE; return NULL;
} }
n = map; n = map;
...@@ -156,43 +156,45 @@ intmap_index_t intmap_first_(const struct intmap *map) ...@@ -156,43 +156,45 @@ intmap_index_t intmap_first_(const struct intmap *map)
while (!n->v) while (!n->v)
n = &n->u.n->child[0]; n = &n->u.n->child[0];
errno = 0; errno = 0;
return n->u.i; *indexp = n->u.i;
return n->v;
} }
intmap_index_t intmap_after_(const struct intmap *map, intmap_index_t index) void *intmap_after_(const struct intmap *map, intmap_index_t *indexp)
{ {
const struct intmap *n, *prev = NULL; const struct intmap *n, *prev = NULL;
/* Special case of unincrementable value, or empty map */ /* Special case of empty map */
if (index == UINTMAP_NONE || intmap_empty_(map)) { if (intmap_empty_(map)) {
errno = ENOENT; errno = ENOENT;
return UINTMAP_NONE; return NULL;
} }
/* Follow down, track the last place where we could have set a bit /* Follow down, track the last place where we could have set a bit
* instead of clearing it: this is the higher alternative tree. */ * instead of clearing it: this is the higher alternative tree. */
n = map; n = map;
while (!n->v) { while (!n->v) {
u8 direction = (index >> n->u.n->bit_num) & 1; u8 direction = (*indexp >> n->u.n->bit_num) & 1;
if (!direction) if (!direction)
prev = n; prev = n;
n = &n->u.n->child[direction]; n = &n->u.n->child[direction];
} }
/* Found a successor? */ /* Found a successor? */
if (n->u.i > index) { if (n->u.i > *indexp) {
errno = 0; errno = 0;
return n->u.i; *indexp = n->u.i;
return n->v;
} }
/* Nowhere to go back up to? */ /* Nowhere to go back up to? */
if (!prev) { if (!prev) {
errno = ENOENT; errno = ENOENT;
return UINTMAP_NONE; return NULL;
} }
/* Get first one from that other branch. */ /* Get first one from that other branch. */
return intmap_first_(&prev->u.n->child[1]); return intmap_first_(&prev->u.n->child[1], indexp);
} }
static void clear(struct intmap n) static void clear(struct intmap n)
......
...@@ -11,12 +11,9 @@ ...@@ -11,12 +11,9 @@
/* Must be an unsigned type. */ /* Must be an unsigned type. */
#ifndef intmap_index_t #ifndef intmap_index_t
#define intmap_index_t uint64_t #define intmap_index_t uint64_t
#define sintmap_index_t int64_t
#endif #endif
/* Maximum possible values of each type */
#define UINTMAP_NONE ((intmap_index_t)-1)
#define SINTMAP_NONE (((intmap_index_t)1 << (sizeof(intmap_index_t)*8))-1)
/** /**
* struct intmap - representation of an integer map * struct intmap - representation of an integer map
* *
...@@ -261,52 +258,58 @@ void *intmap_del_(struct intmap *map, intmap_index_t index); ...@@ -261,52 +258,58 @@ void *intmap_del_(struct intmap *map, intmap_index_t index);
void intmap_clear_(struct intmap *map); void intmap_clear_(struct intmap *map);
/** /**
* uintmap_first - get first index in an unsigned intmap * uintmap_first - get first value in an unsigned intmap
* @umap: the typed intmap to iterate through. * @umap: the typed intmap to iterate through.
* @indexp: a pointer to store the index.
* *
* Returns UINTMAP_NONE and sets errno to ENOENT if it's empty. * Returns NULL if the map is empty, otherwise populates *@indexp and
* Otherwise errno is set to 0. * returns the lowest entry.
*/ */
#define uintmap_first(umap) \ #define uintmap_first(umap, indexp) \
intmap_first_(uintmap_unwrap_(umap)) tcon_cast((umap), uintmap_canary, \
intmap_first_(uintmap_unwrap_(umap), (indexp)))
void *intmap_first_(const struct intmap *map, intmap_index_t *indexp);
/** /**
* sintmap_first - get first index in a signed intmap * sintmap_first - get first value in a signed intmap
* @smap: the typed intmap to iterate through. * @smap: the typed intmap to iterate through.
* @indexp: a pointer to store the index.
* *
* Returns SINTMAP_NONE and sets errno to ENOENT if it's * Returns NULL if the map is empty, otherwise populates *@indexp and
* empty. Otherwise errno is set to 0. * returns the lowest entry.
*/ */
#define sintmap_first(smap) \ #define sintmap_first(smap, indexp) \
SINTMAP_UNOFF(intmap_first_(sintmap_unwrap_(smap))) tcon_cast((smap), sintmap_canary, \
sintmap_first_(sintmap_unwrap_(smap), (indexp)))
intmap_index_t intmap_first_(const struct intmap *map);
/** /**
* uintmap_after - get the closest following index in an unsigned intmap * uintmap_after - get the closest following index in an unsigned intmap
* @umap: the typed intmap to iterate through. * @umap: the typed intmap to iterate through.
* @i: the preceeding index (may not exist) * @indexp: the preceeding index (may not exist)
* *
* Returns UINTMAP_NONE and sets errno to ENOENT if there are no * Returns NULL if the there is no entry > @indexp, otherwise
* others. Otherwise errno is set to 0. * populates *@indexp and returns the lowest entry > @indexp.
*/ */
#define uintmap_after(umap, i) \ #define uintmap_after(umap, indexp) \
intmap_after_(uintmap_unwrap_(umap), (i)) tcon_cast((umap), uintmap_canary, \
intmap_after_(uintmap_unwrap_(umap), (indexp)))
void *intmap_after_(const struct intmap *map, intmap_index_t *indexp);
/** /**
* sintmap_after - get the closest following index in a signed intmap * sintmap_after - get the closest following index in a signed intmap
* @smap: the typed intmap to iterate through. * @smap: the typed intmap to iterate through.
* @i: the preceeding index. * @indexp: the preceeding index (may not exist)
* *
* Returns SINTMAP_NONE and sets errno to ENOENT if there are no * Returns NULL if the there is no entry > @indexp, otherwise
* others. Otherwise errno is set to 0. * populates *@indexp and returns the lowest entry > @indexp.
*/ */
#define sintmap_after(smap, i) \ #define sintmap_after(smap, indexp) \
SINTMAP_UNOFF(intmap_after_(sintmap_unwrap_(smap), SINTMAP_OFF((i)))) tcon_cast((smap), sintmap_canary, \
sintmap_after_(sintmap_unwrap_(smap), (indexp)))
intmap_index_t intmap_after_(const struct intmap *map, intmap_index_t i);
/* TODO: We could implement intmap_prefix, intmap_iterate... */ /* TODO: We could implement intmap_prefix. */
/* These make sure it really is a uintmap/sintmap */ /* These make sure it really is a uintmap/sintmap */
#define uintmap_unwrap_(u) (tcon_unwrap(u) + 0*tcon_sizeof((u), uintmap_canary)) #define uintmap_unwrap_(u) (tcon_unwrap(u) + 0*tcon_sizeof((u), uintmap_canary))
...@@ -317,4 +320,23 @@ intmap_index_t intmap_after_(const struct intmap *map, intmap_index_t i); ...@@ -317,4 +320,23 @@ intmap_index_t intmap_after_(const struct intmap *map, intmap_index_t i);
#define SINTMAP_OFF(index) ((intmap_index_t)(index) + SINTMAP_OFFSET) #define SINTMAP_OFF(index) ((intmap_index_t)(index) + SINTMAP_OFFSET)
#define SINTMAP_UNOFF(index) ((intmap_index_t)(index) - SINTMAP_OFFSET) #define SINTMAP_UNOFF(index) ((intmap_index_t)(index) - SINTMAP_OFFSET)
/* Due to multi-evaluation, these can't be macros */
static inline void *sintmap_first_(const struct intmap *map,
sintmap_index_t *indexp)
{
intmap_index_t i;
void *ret = intmap_first_(map, &i);
*indexp = SINTMAP_UNOFF(i);
return ret;
}
static inline void *sintmap_after_(const struct intmap *map,
sintmap_index_t *indexp)
{
intmap_index_t i = SINTMAP_OFF(*indexp);
void *ret = intmap_after_(map, &i);
*indexp = SINTMAP_UNOFF(i);
return ret;
}
#endif /* CCAN_INTMAP_H */ #endif /* CCAN_INTMAP_H */
#define intmap_index_t uint8_t #define intmap_index_t uint8_t
#define sintmap_index_t int8_t
#include <ccan/intmap/intmap.c> #include <ccan/intmap/intmap.c>
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
...@@ -12,16 +13,16 @@ typedef SINTMAP(int8_t *) smap; ...@@ -12,16 +13,16 @@ typedef SINTMAP(int8_t *) smap;
static bool check_umap(const umap *map) static bool check_umap(const umap *map)
{ {
/* This is a larger type than unsigned, and allows negative */ /* This is a larger type than unsigned, and allows negative */
int64_t i, prev; int64_t prev;
intmap_index_t i;
uint8_t *v;
/* Must be in order, must contain value. */ /* Must be in order, must contain value. */
prev = -1; prev = -1;
for (i = uintmap_first(map); for (v = uintmap_first(map, &i); v; v = uintmap_after(map, &i)) {
i != UINTMAP_NONE || errno == 0;
i = uintmap_after(map, i)) {
if (i <= prev) if (i <= prev)
return false; return false;
if (*(uint8_t *)uintmap_get(map, i) != i) if (*v != i)
return false; return false;
prev = i; prev = i;
} }
...@@ -31,16 +32,16 @@ static bool check_umap(const umap *map) ...@@ -31,16 +32,16 @@ static bool check_umap(const umap *map)
static bool check_smap(const smap *map) static bool check_smap(const smap *map)
{ {
/* This is a larger type than int, and allows negative */ /* This is a larger type than int, and allows negative */
int64_t i, prev; int64_t prev;
sintmap_index_t i;
int8_t *v;
/* Must be in order, must contain value. */ /* Must be in order, must contain value. */
prev = -0x80000001ULL; prev = -0x80000001ULL;
for (i = sintmap_first(map); for (v = sintmap_first(map, &i); v; v = sintmap_after(map, &i)) {
i != 127 || errno == 0;
i = sintmap_after(map, i)) {
if (i <= prev) if (i <= prev)
return false; return false;
if (*(int8_t *)sintmap_get(map, i) != i) if (*v != i)
return false; return false;
prev = i; prev = i;
} }
......
...@@ -10,14 +10,16 @@ typedef SINTMAP(int *) smap; ...@@ -10,14 +10,16 @@ typedef SINTMAP(int *) smap;
static bool check_umap(const umap *map) static bool check_umap(const umap *map)
{ {
/* This is a larger type than unsigned, and allows negative */ /* This is a larger type than unsigned, and allows negative */
int64_t i, prev; int64_t prev;
uint64_t i;
unsigned int *v;
/* Must be in order, must contain value. */ /* Must be in order, must contain value. */
prev = -1; prev = -1;
for (i = uintmap_first(map); i != -1ULL; i = uintmap_after(map, i)) { for (v = uintmap_first(map, &i); v; v = uintmap_after(map, &i)) {
if (i <= prev) if ((int64_t)i <= prev)
return false; return false;
if (*(unsigned int *)uintmap_get(map, i) != i) if (*v != i)
return false; return false;
prev = i; prev = i;
} }
...@@ -27,16 +29,15 @@ static bool check_umap(const umap *map) ...@@ -27,16 +29,15 @@ static bool check_umap(const umap *map)
static bool check_smap(const smap *map) static bool check_smap(const smap *map)
{ {
/* This is a larger type than int, and allows negative */ /* This is a larger type than int, and allows negative */
int64_t i, prev; int64_t prev, i;
int *v;
/* Must be in order, must contain value. */ /* Must be in order, must contain value. */
prev = -0x80000001ULL; prev = -0x80000001ULL;
for (i = sintmap_first(map); for (v = sintmap_first(map, &i); v; v = sintmap_after(map, &i)) {
i != 0x7FFFFFFFFFFFFFFFLL;
i = sintmap_after(map, i)) {
if (i <= prev) if (i <= prev)
return false; return false;
if (*(int *)sintmap_get(map, i) != i) if (*v != i)
return false; return false;
prev = i; prev = i;
} }
......
...@@ -6,6 +6,7 @@ int main(void) ...@@ -6,6 +6,7 @@ int main(void)
{ {
SINTMAP(const char *) map; SINTMAP(const char *) map;
const char *first = "first", *second = "second"; const char *first = "first", *second = "second";
int64_t s;
/* This is how many tests you plan to run */ /* This is how many tests you plan to run */
plan_tests(35); plan_tests(35);
...@@ -14,36 +15,43 @@ int main(void) ...@@ -14,36 +15,43 @@ int main(void)
/* Test boundaries. */ /* Test boundaries. */
ok1(!sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL)); ok1(!sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL));
ok1(!sintmap_get(&map, -0x8000000000000000LL)); ok1(!sintmap_get(&map, -0x8000000000000000LL));
ok1(sintmap_first(&map) == 0x7FFFFFFFFFFFFFFFLL); ok1(sintmap_first(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_after(&map, 0x7FFFFFFFFFFFFFFFLL) == 0x7FFFFFFFFFFFFFFFLL); s = 0x7FFFFFFFFFFFFFFFLL;
ok1(sintmap_after(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_after(&map, -0x8000000000000000LL) == 0x7FFFFFFFFFFFFFFFLL); s = -0x8000000000000000LL;
ok1(sintmap_after(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_after(&map, 0x7FFFFFFFFFFFFFFELL) == 0x7FFFFFFFFFFFFFFFLL); s = 0x7FFFFFFFFFFFFFFELL;
ok1(sintmap_after(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first)); ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first));
ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first); ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first);
ok1(sintmap_first(&map) == 0x7FFFFFFFFFFFFFFFLL); ok1(sintmap_first(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL);
ok1(errno == 0); ok1(errno == 0);
ok1(sintmap_add(&map, -0x8000000000000000LL, second)); ok1(sintmap_add(&map, -0x8000000000000000LL, second));
ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first); ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first);
ok1(sintmap_get(&map, -0x8000000000000000LL) == second); ok1(sintmap_get(&map, -0x8000000000000000LL) == second);
ok1(sintmap_first(&map) == -0x8000000000000000LL); ok1(sintmap_first(&map, &s) == second && s == -0x8000000000000000LL);
ok1(sintmap_after(&map, -0x8000000000000000LL) == 0x7FFFFFFFFFFFFFFFLL); ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL);
ok1(errno == 0); ok1(errno == 0);
ok1(sintmap_after(&map, 0x7FFFFFFFFFFFFFFELL) == 0x7FFFFFFFFFFFFFFFLL); s = 0x7FFFFFFFFFFFFFFELL;
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL);
ok1(errno == 0); ok1(errno == 0);
ok1(sintmap_after(&map, -0x7FFFFFFFFFFFFFFFLL) == 0x7FFFFFFFFFFFFFFFLL); s = -0x7FFFFFFFFFFFFFFFLL;
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL);
ok1(errno == 0); ok1(errno == 0);
ok1(sintmap_after(&map, 0x7FFFFFFFFFFFFFFFLL) == 0x7FFFFFFFFFFFFFFFLL); ok1(sintmap_after(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first); ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first);
ok1(sintmap_after(&map, -0x8000000000000000LL) == 0x7FFFFFFFFFFFFFFFLL); s = -0x8000000000000000LL;
ok1(sintmap_after(&map, &s) == NULL);
ok1(errno == ENOENT); ok1(errno == ENOENT);
ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first)); ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first));
ok1(sintmap_del(&map, 0x8000000000000000LL) == second); ok1(sintmap_del(&map, 0x8000000000000000LL) == second);
ok1(sintmap_after(&map, -0x8000000000000000LL) == 0x7FFFFFFFFFFFFFFFLL); s = -0x8000000000000000LL;
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL);
ok1(errno == 0); ok1(errno == 0);
ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first); ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first);
ok1(sintmap_empty(&map)); ok1(sintmap_empty(&map));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment