Christian Decker
8 years ago
committed by
Rusty Russell
9 changed files with 893 additions and 0 deletions
@ -0,0 +1 @@ |
|||
../../licenses/CC0 |
@ -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 <rusty@rustcorp.com.au> |
|||
*/ |
|||
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; |
|||
} |
@ -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); |
|||
} |
@ -0,0 +1,342 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
#ifndef CCAN_INTMAP_H |
|||
#define CCAN_INTMAP_H |
|||
#include "config.h" |
|||
#include <ccan/tcon/tcon.h> |
|||
#include <ccan/typesafe_cb/typesafe_cb.h> |
|||
#include <inttypes.h> |
|||
#include <stdlib.h> |
|||
#include <stdbool.h> |
|||
|
|||
/* Must be an unsigned type. */ |
|||
#ifndef intmap_index_t |
|||
#define intmap_index_t uint64_t |
|||
#define sintmap_index_t int64_t |
|||
#endif |
|||
|
|||
/**
|
|||
* struct intmap - representation of an integer map |
|||
* |
|||
* It's exposed here to allow you to embed it and so we can inline the |
|||
* trivial functions. |
|||
*/ |
|||
struct intmap { |
|||
union { |
|||
struct node *n; |
|||
intmap_index_t i; |
|||
} u; |
|||
void *v; |
|||
}; |
|||
|
|||
/**
|
|||
* UINTMAP - declare a type-specific intmap (for unsigned integers) |
|||
* @membertype: type for this map's values, or void * for any pointer. |
|||
* |
|||
* You use this to create your own typed intmap for a particular |
|||
* (non-NULL) pointer type. |
|||
* |
|||
* Example: |
|||
* UINTMAP(int *) uint_intmap; |
|||
* uintmap_init(&uint_intmap); |
|||
*/ |
|||
#define UINTMAP(membertype) \ |
|||
TCON_WRAP(struct intmap, membertype uintmap_canary) |
|||
|
|||
/**
|
|||
* SINTMAP - declare a type-specific intmap (for signed integers) |
|||
* @membertype: type for this map's values, or void * for any pointer. |
|||
* |
|||
* You use this to create your own typed intmap for a particular type. |
|||
* You can use an integer type as membertype, *but* remember you can't |
|||
* use "0" as a value! |
|||
* |
|||
* This is different from UINTMAP because we want it to sort into |
|||
* least (most negative) to largest order. |
|||
* |
|||
* Example: |
|||
* SINTMAP(int *) sint_intmap; |
|||
* sintmap_init(&sint_intmap); |
|||
*/ |
|||
#define SINTMAP(membertype) \ |
|||
TCON_WRAP(struct intmap, membertype sintmap_canary) |
|||
|
|||
/**
|
|||
* uintmap_init - initialize an unsigned integer map (empty) |
|||
* @umap: the typed intmap to initialize. |
|||
* |
|||
* For completeness; if you've arranged for it to be NULL already you don't |
|||
* need this. |
|||
* |
|||
* Example: |
|||
* UINTMAP(int *) uint_intmap; |
|||
* |
|||
* uintmap_init(&uint_intmap); |
|||
*/ |
|||
#define uintmap_init(umap) intmap_init_(uintmap_unwrap_(umap)) |
|||
|
|||
/**
|
|||
* sintmap_init - initialize a signed integer map (empty) |
|||
* @smap: the typed intmap to initialize. |
|||
* |
|||
* For completeness; if you've arranged for it to be NULL already you don't |
|||
* need this. |
|||
* |
|||
* Example: |
|||
* SINTMAP(int *) sint_intmap; |
|||
* |
|||
* sintmap_init(&sint_intmap); |
|||
*/ |
|||
#define sintmap_init(smap) intmap_init_(sintmap_unwrap_(smap)) |
|||
|
|||
static inline void intmap_init_(struct intmap *map) |
|||
{ |
|||
map->u.n = NULL; |
|||
map->v = NULL; |
|||
} |
|||
|
|||
/**
|
|||
* uintmap_empty - is this unsigned integer map empty? |
|||
* @umap: the typed intmap to check. |
|||
* |
|||
* Example: |
|||
* if (!uintmap_empty(&uint_intmap)) |
|||
* abort(); |
|||
*/ |
|||
#define uintmap_empty(umap) intmap_empty_(uintmap_unwrap_(umap)) |
|||
|
|||
/**
|
|||
* sintmap_empty - is this signed integer map empty? |
|||
* @smap: the typed intmap to check. |
|||
* |
|||
* Example: |
|||
* if (!sintmap_empty(&sint_intmap)) |
|||
* abort(); |
|||
*/ |
|||
#define sintmap_empty(smap) intmap_empty_(sintmap_unwrap_(smap)) |
|||
|
|||
static inline bool intmap_empty_(const struct intmap *map) |
|||
{ |
|||
return map->v == NULL && map->u.n == NULL; |
|||
} |
|||
|
|||
/**
|
|||
* uintmap_get - get a value from an unsigned integer map |
|||
* @umap: the typed intmap to search. |
|||
* @index: the unsigned index to search for. |
|||
* |
|||
* Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT). |
|||
* |
|||
* Example: |
|||
* int *val = uintmap_get(&uint_intmap, 100); |
|||
* if (val) |
|||
* printf("100 => %i\n", *val); |
|||
*/ |
|||
#define uintmap_get(umap, index) \ |
|||
tcon_cast((umap), uintmap_canary, \ |
|||
intmap_get_(uintmap_unwrap_(umap), (index))) |
|||
|
|||
/**
|
|||
* sintmap_get - get a value from a signed integer map |
|||
* @smap: the typed intmap to search. |
|||
* @index: the signed index to search for. |
|||
* |
|||
* Returns the value, or NULL if it isn't in the map (and sets errno = ENOENT). |
|||
* |
|||
* Example: |
|||
* int *val2 = sintmap_get(&sint_intmap, -100); |
|||
* if (val2) |
|||
* printf("-100 => %i\n", *val2); |
|||
*/ |
|||
#define sintmap_get(smap, index) \ |
|||
tcon_cast((smap), sintmap_canary, \ |
|||
intmap_get_(sintmap_unwrap_(smap), SINTMAP_OFF(index))) |
|||
|
|||
void *intmap_get_(const struct intmap *map, intmap_index_t index); |
|||
|
|||
/**
|
|||
* uintmap_add - place a member in an unsigned integer map. |
|||
* @umap: the typed intmap to add to. |
|||
* @index: the unsigned index to place in the map. |
|||
* @value: the (non-NULL) value. |
|||
* |
|||
* This returns false if we run out of memory (errno = ENOMEM), or |
|||
* (more normally) if that index already appears in the map (EEXIST). |
|||
* |
|||
* Note that the value is not copied, just the pointer. |
|||
* |
|||
* Example: |
|||
* val = malloc(sizeof *val); |
|||
* *val = 17; |
|||
* if (!uintmap_add(&uint_intmap, 100, val)) |
|||
* printf("100 was already in the map\n"); |
|||
*/ |
|||
#define uintmap_add(umap, index, value) \ |
|||
intmap_add_(uintmap_unwrap_(tcon_check((umap), uintmap_canary, \ |
|||
(value))), \ |
|||
(index), (void *)(value)) |
|||
|
|||
/**
|
|||
* sintmap_add - place a member in a signed integer map. |
|||
* @smap: the typed intmap to add to. |
|||
* @index: the signed index to place in the map. |
|||
* @value: the (non-NULL) value. |
|||
* |
|||
* This returns false if we run out of memory (errno = ENOMEM), or |
|||
* (more normally) if that index already appears in the map (EEXIST). |
|||
* |
|||
* Note that the value is not copied, just the pointer. |
|||
* |
|||
* Example: |
|||
* val = malloc(sizeof *val); |
|||
* *val = 17; |
|||
* if (!sintmap_add(&sint_intmap, -100, val)) |
|||
* printf("-100 was already in the map\n"); |
|||
*/ |
|||
#define sintmap_add(smap, index, value) \ |
|||
intmap_add_(sintmap_unwrap_(tcon_check((smap), sintmap_canary, \ |
|||
(value))), \ |
|||
SINTMAP_OFF(index), (void *)(value)) |
|||
|
|||
bool intmap_add_(struct intmap *map, intmap_index_t member, const void *value); |
|||
|
|||
/**
|
|||
* uintmap_del - remove a member from an unsigned integer map. |
|||
* @umap: the typed intmap to delete from. |
|||
* @index: the unsigned index to remove from the map. |
|||
* |
|||
* This returns the value, or NULL if there was no value at that |
|||
* index. |
|||
* |
|||
* Example: |
|||
* if (uintmap_del(&uint_intmap, 100) == NULL) |
|||
* printf("100 was not in the map?\n"); |
|||
*/ |
|||
#define uintmap_del(umap, index) \ |
|||
tcon_cast((umap), uintmap_canary, \ |
|||
intmap_del_(uintmap_unwrap_(umap), (index))) |
|||
|
|||
/**
|
|||
* sintmap_del - remove a member from a signed integer map. |
|||
* @smap: the typed intmap to delete from. |
|||
* @index: the signed index to remove from the map. |
|||
* |
|||
* This returns the value, or NULL if there was no value at that |
|||
* index. |
|||
* |
|||
* Example: |
|||
* if (sintmap_del(&sint_intmap, -100) == NULL) |
|||
* printf("-100 was not in the map?\n"); |
|||
*/ |
|||
#define sintmap_del(smap, index) \ |
|||
tcon_cast((smap), sintmap_canary, \ |
|||
intmap_del_(sintmap_unwrap_(smap), SINTMAP_OFF(index))) |
|||
|
|||
void *intmap_del_(struct intmap *map, intmap_index_t index); |
|||
|
|||
/**
|
|||
* uintmap_clear - remove every member from an unsigned integer map. |
|||
* @umap: the typed intmap to clear. |
|||
* |
|||
* The map will be empty after this. |
|||
* |
|||
* Example: |
|||
* uintmap_clear(&uint_intmap); |
|||
*/ |
|||
#define uintmap_clear(umap) intmap_clear_(uintmap_unwrap_(umap)) |
|||
|
|||
/**
|
|||
* sintmap_clear - remove every member from a signed integer map. |
|||
* @smap: the typed intmap to clear. |
|||
* |
|||
* The map will be empty after this. |
|||
* |
|||
* Example: |
|||
* sintmap_clear(&sint_intmap); |
|||
*/ |
|||
#define sintmap_clear(smap) intmap_clear_(sintmap_unwrap_(smap)) |
|||
|
|||
void intmap_clear_(struct intmap *map); |
|||
|
|||
/**
|
|||
* uintmap_first - get first value in an unsigned intmap |
|||
* @umap: the typed intmap to iterate through. |
|||
* @indexp: a pointer to store the index. |
|||
* |
|||
* Returns NULL if the map is empty, otherwise populates *@indexp and |
|||
* returns the lowest entry. |
|||
*/ |
|||
#define uintmap_first(umap, indexp) \ |
|||
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 value in a signed intmap |
|||
* @smap: the typed intmap to iterate through. |
|||
* @indexp: a pointer to store the index. |
|||
* |
|||
* Returns NULL if the map is empty, otherwise populates *@indexp and |
|||
* returns the lowest entry. |
|||
*/ |
|||
#define sintmap_first(smap, indexp) \ |
|||
tcon_cast((smap), sintmap_canary, \ |
|||
sintmap_first_(sintmap_unwrap_(smap), (indexp))) |
|||
|
|||
/**
|
|||
* uintmap_after - get the closest following index in an unsigned intmap |
|||
* @umap: the typed intmap to iterate through. |
|||
* @indexp: the preceeding index (may not exist) |
|||
* |
|||
* Returns NULL if the there is no entry > @indexp, otherwise |
|||
* populates *@indexp and returns the lowest entry > @indexp. |
|||
*/ |
|||
#define uintmap_after(umap, indexp) \ |
|||
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 |
|||
* @smap: the typed intmap to iterate through. |
|||
* @indexp: the preceeding index (may not exist) |
|||
* |
|||
* Returns NULL if the there is no entry > @indexp, otherwise |
|||
* populates *@indexp and returns the lowest entry > @indexp. |
|||
*/ |
|||
#define sintmap_after(smap, indexp) \ |
|||
tcon_cast((smap), sintmap_canary, \ |
|||
sintmap_after_(sintmap_unwrap_(smap), (indexp))) |
|||
|
|||
/* TODO: We could implement intmap_prefix. */ |
|||
|
|||
/* These make sure it really is a uintmap/sintmap */ |
|||
#define uintmap_unwrap_(u) (tcon_unwrap(u) + 0*tcon_sizeof((u), uintmap_canary)) |
|||
#define sintmap_unwrap_(s) (tcon_unwrap(s) + 0*tcon_sizeof((s), sintmap_canary)) |
|||
|
|||
/* We have to offset indices if they're signed, so ordering works. */ |
|||
#define SINTMAP_OFFSET ((intmap_index_t)1 << (sizeof(intmap_index_t)*8-1)) |
|||
#define SINTMAP_OFF(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 */ |
@ -0,0 +1,93 @@ |
|||
#define intmap_index_t uint8_t |
|||
#define sintmap_index_t int8_t |
|||
|
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <stdio.h> |
|||
|
|||
#define NUM 100 |
|||
|
|||
typedef UINTMAP(uint8_t *) umap; |
|||
typedef SINTMAP(int8_t *) smap; |
|||
|
|||
static bool check_umap(const umap *map) |
|||
{ |
|||
/* This is a larger type than unsigned, and allows negative */ |
|||
int64_t prev; |
|||
intmap_index_t i; |
|||
uint8_t *v; |
|||
|
|||
/* Must be in order, must contain value. */ |
|||
prev = -1; |
|||
for (v = uintmap_first(map, &i); v; v = uintmap_after(map, &i)) { |
|||
if (i <= prev) |
|||
return false; |
|||
if (*v != i) |
|||
return false; |
|||
prev = i; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
static bool check_smap(const smap *map) |
|||
{ |
|||
/* This is a larger type than int, and allows negative */ |
|||
int64_t prev; |
|||
sintmap_index_t i; |
|||
int8_t *v; |
|||
|
|||
/* Must be in order, must contain value. */ |
|||
prev = -0x80000001ULL; |
|||
for (v = sintmap_first(map, &i); v; v = sintmap_after(map, &i)) { |
|||
if (i <= prev) |
|||
return false; |
|||
if (*v != i) |
|||
return false; |
|||
prev = i; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
umap umap; |
|||
smap smap; |
|||
int i; |
|||
uint8_t urandoms[NUM]; |
|||
int8_t srandoms[NUM]; |
|||
|
|||
plan_tests(6 * NUM + 2); |
|||
uintmap_init(&umap); |
|||
sintmap_init(&smap); |
|||
|
|||
for (i = 0; i < NUM; i++) { |
|||
urandoms[i] = random(); |
|||
srandoms[i] = random(); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
/* In case we have duplicates. */ |
|||
while (!uintmap_add(&umap, urandoms[i], urandoms+i)) |
|||
urandoms[i] = random(); |
|||
ok1(check_umap(&umap)); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
ok1(uintmap_del(&umap, urandoms[i]) == urandoms+i); |
|||
ok1(check_umap(&umap)); |
|||
} |
|||
ok1(uintmap_empty(&umap)); |
|||
|
|||
for (i = 0; i < NUM; i++) { |
|||
/* In case we have duplicates. */ |
|||
while (!sintmap_add(&smap, srandoms[i], srandoms+i)) |
|||
srandoms[i] = random(); |
|||
ok1(check_smap(&smap)); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
ok1(sintmap_del(&smap, srandoms[i]) == srandoms+i); |
|||
ok1(check_smap(&smap)); |
|||
} |
|||
ok1(sintmap_empty(&smap)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,89 @@ |
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <stdio.h> |
|||
|
|||
#define NUM 1000 |
|||
|
|||
typedef UINTMAP(unsigned int *) umap; |
|||
typedef SINTMAP(int *) smap; |
|||
|
|||
static bool check_umap(const umap *map) |
|||
{ |
|||
/* This is a larger type than unsigned, and allows negative */ |
|||
int64_t prev; |
|||
uint64_t i; |
|||
unsigned int *v; |
|||
|
|||
/* Must be in order, must contain value. */ |
|||
prev = -1; |
|||
for (v = uintmap_first(map, &i); v; v = uintmap_after(map, &i)) { |
|||
if ((int64_t)i <= prev) |
|||
return false; |
|||
if (*v != i) |
|||
return false; |
|||
prev = i; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
static bool check_smap(const smap *map) |
|||
{ |
|||
/* This is a larger type than int, and allows negative */ |
|||
int64_t prev, i; |
|||
int *v; |
|||
|
|||
/* Must be in order, must contain value. */ |
|||
prev = -0x80000001ULL; |
|||
for (v = sintmap_first(map, &i); v; v = sintmap_after(map, &i)) { |
|||
if (i <= prev) |
|||
return false; |
|||
if (*v != i) |
|||
return false; |
|||
prev = i; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
umap umap; |
|||
smap smap; |
|||
int i; |
|||
unsigned int urandoms[NUM]; |
|||
int srandoms[NUM]; |
|||
|
|||
plan_tests(6 * NUM + 2); |
|||
uintmap_init(&umap); |
|||
sintmap_init(&smap); |
|||
|
|||
for (i = 0; i < NUM; i++) { |
|||
urandoms[i] = random(); |
|||
srandoms[i] = random(); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
/* In case we have duplicates. */ |
|||
while (!uintmap_add(&umap, urandoms[i], urandoms+i)) |
|||
urandoms[i] = random(); |
|||
ok1(check_umap(&umap)); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
ok1(uintmap_del(&umap, urandoms[i]) == urandoms+i); |
|||
ok1(check_umap(&umap)); |
|||
} |
|||
ok1(uintmap_empty(&umap)); |
|||
|
|||
for (i = 0; i < NUM; i++) { |
|||
/* In case we have duplicates. */ |
|||
while (!sintmap_add(&smap, srandoms[i], srandoms+i)) |
|||
srandoms[i] = random(); |
|||
ok1(check_smap(&smap)); |
|||
} |
|||
for (i = 0; i < NUM; i++) { |
|||
ok1(sintmap_del(&smap, srandoms[i]) == srandoms+i); |
|||
ok1(check_smap(&smap)); |
|||
} |
|||
ok1(sintmap_empty(&smap)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,61 @@ |
|||
#include <ccan/intmap/intmap.h> |
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
SINTMAP(const char *) map; |
|||
const char *first = "first", *second = "second"; |
|||
int64_t s; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(35); |
|||
|
|||
sintmap_init(&map); |
|||
/* Test boundaries. */ |
|||
ok1(!sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL)); |
|||
ok1(!sintmap_get(&map, -0x8000000000000000LL)); |
|||
ok1(sintmap_first(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
s = 0x7FFFFFFFFFFFFFFFLL; |
|||
ok1(sintmap_after(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
s = -0x8000000000000000LL; |
|||
ok1(sintmap_after(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
s = 0x7FFFFFFFFFFFFFFELL; |
|||
ok1(sintmap_after(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first)); |
|||
ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first); |
|||
ok1(sintmap_first(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL); |
|||
ok1(errno == 0); |
|||
ok1(sintmap_add(&map, -0x8000000000000000LL, second)); |
|||
ok1(sintmap_get(&map, 0x7FFFFFFFFFFFFFFFLL) == first); |
|||
ok1(sintmap_get(&map, -0x8000000000000000LL) == second); |
|||
ok1(sintmap_first(&map, &s) == second && s == -0x8000000000000000LL); |
|||
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL); |
|||
ok1(errno == 0); |
|||
s = 0x7FFFFFFFFFFFFFFELL; |
|||
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL); |
|||
ok1(errno == 0); |
|||
s = -0x7FFFFFFFFFFFFFFFLL; |
|||
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL); |
|||
ok1(errno == 0); |
|||
ok1(sintmap_after(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first); |
|||
s = -0x8000000000000000LL; |
|||
ok1(sintmap_after(&map, &s) == NULL); |
|||
ok1(errno == ENOENT); |
|||
ok1(sintmap_add(&map, 0x7FFFFFFFFFFFFFFFLL, first)); |
|||
ok1(sintmap_del(&map, 0x8000000000000000LL) == second); |
|||
s = -0x8000000000000000LL; |
|||
ok1(sintmap_after(&map, &s) == first && s == 0x7FFFFFFFFFFFFFFFLL); |
|||
ok1(errno == 0); |
|||
ok1(sintmap_del(&map, 0x7FFFFFFFFFFFFFFFLL) == first); |
|||
ok1(sintmap_empty(&map)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,55 @@ |
|||
#include <ccan/intmap/intmap.h> |
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
UINTMAP(char *) map; |
|||
const char val[] = "there"; |
|||
const char none[] = ""; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(28); |
|||
|
|||
uintmap_init(&map); |
|||
|
|||
ok1(!uintmap_get(&map, 1)); |
|||
ok1(errno == ENOENT); |
|||
ok1(!uintmap_get(&map, 0)); |
|||
ok1(errno == ENOENT); |
|||
ok1(!uintmap_del(&map, 1)); |
|||
ok1(errno == ENOENT); |
|||
ok1(!uintmap_del(&map, 0)); |
|||
ok1(errno == ENOENT); |
|||
|
|||
ok1(uintmap_add(&map, 1, val)); |
|||
ok1(uintmap_get(&map, 1) == val); |
|||
ok1(!uintmap_get(&map, 0)); |
|||
ok1(errno == ENOENT); |
|||
|
|||
/* Add a duplicate should fail. */ |
|||
ok1(!uintmap_add(&map, 1, val)); |
|||
ok1(errno == EEXIST); |
|||
|
|||
/* Delete should succeed. */ |
|||
ok1(uintmap_del(&map, 1) == val); |
|||
ok1(!uintmap_get(&map, 1)); |
|||
ok1(errno == ENOENT); |
|||
ok1(!uintmap_get(&map, 0)); |
|||
ok1(errno == ENOENT); |
|||
|
|||
/* Both at once... */ |
|||
ok1(uintmap_add(&map, 0, none)); |
|||
ok1(uintmap_add(&map, 1, val)); |
|||
ok1(uintmap_get(&map, 1) == val); |
|||
ok1(uintmap_get(&map, 0) == none); |
|||
ok1(!uintmap_del(&map, 2)); |
|||
ok1(uintmap_del(&map, 0) == none); |
|||
ok1(uintmap_get(&map, 1) == val); |
|||
ok1(uintmap_del(&map, 1) == val); |
|||
|
|||
ok1(uintmap_empty(&map)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
Loading…
Reference in new issue