mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-07 16:14:26 +01:00
ccan: Added ccan/intmap
This commit is contained in:
committed by
Rusty Russell
parent
999472d99a
commit
05cf3160d4
4
Makefile
4
Makefile
@@ -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 \
|
||||
@@ -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 \
|
||||
@@ -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
|
||||
|
||||
1
ccan/ccan/intmap/LICENSE
Symbolic link
1
ccan/ccan/intmap/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
34
ccan/ccan/intmap/_info
Normal file
34
ccan/ccan/intmap/_info
Normal file
@@ -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;
|
||||
}
|
||||
214
ccan/ccan/intmap/intmap.c
Normal file
214
ccan/ccan/intmap/intmap.c
Normal file
@@ -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);
|
||||
}
|
||||
342
ccan/ccan/intmap/intmap.h
Normal file
342
ccan/ccan/intmap/intmap.h
Normal file
@@ -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 */
|
||||
93
ccan/ccan/intmap/test/run-order-smallsize.c
Normal file
93
ccan/ccan/intmap/test/run-order-smallsize.c
Normal file
@@ -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();
|
||||
}
|
||||
89
ccan/ccan/intmap/test/run-order.c
Normal file
89
ccan/ccan/intmap/test/run-order.c
Normal file
@@ -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();
|
||||
}
|
||||
61
ccan/ccan/intmap/test/run-signed-int.c
Normal file
61
ccan/ccan/intmap/test/run-signed-int.c
Normal file
@@ -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();
|
||||
}
|
||||
55
ccan/ccan/intmap/test/run.c
Normal file
55
ccan/ccan/intmap/test/run.c
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user