Commit 2965496c authored by Rusty Russell's avatar Rusty Russell

Merge branch 'judy'

parents 35177fd5 4116b284
#include <stdio.h>
#include <string.h>
#include "config.h"
/**
* jbitset - variable-length bitset (based on libJudy)
*
* This provides a convenient wrapper for using Judy bitsets; using
* integers or pointers as an index, Judy arrays provide an efficient
* bit array or bit map of variable size.
*
* jbitset.h simply contains wrappers for a size_t-indexed bitset, and
* jbitset_type.h contain a wrapper macro for pointer bitsets.
*
* Example:
* // Simple analysis of one-byte mallocs.
* #include <stdlib.h>
* #include <stdio.h>
* #include <err.h>
* #include <ccan/jbitset/jbitset_type.h>
*
* // Define jbit_char_<op> and jbitset_char, for char * bitset.
* JBIT_DEFINE_TYPE(char, char);
*
* int main(int argc, char *argv[])
* {
* unsigned int i, runs, reuse;
* size_t mindist = -1;
* struct jbitset_char *set = jbit_char_new();
* char *p, *prev;
*
* runs = (argc == 1 ? 1000 : atoi(argv[1]));
* if (!runs)
* errx(1, "Invalid number of allocations '%s'", argv[1]);
*
* for (i = 0; i < runs; i++)
* if (!jbit_char_set(set, malloc(1)))
* errx(1, "same pointer allocated twice!");
*
* // Calculate minimum distance
* prev = jbit_char_first(set)+1;
* for (p = jbit_char_first(set); p; prev = p, p = jbit_char_next(set,p))
* if (p - prev < mindist)
* mindist = p - prev;
*
* // Free them all, see how many we reallocate.
* for (p = jbit_char_first(set); p; p = jbit_char_next(set, p))
* free(p);
* for (reuse = 0, i = 0; i < runs; i++)
* reuse += jbit_char_test(set, malloc(1));
*
* printf("Allocation density (bytes): %zu\n"
* "Minimum inter-pointer distance: %zu\n"
* "Reuse rate: %.0f%%\n",
* (jbit_char_last(set) - jbit_char_first(set)) / runs,
* mindist,
* 100.0 * reuse / runs);
* return 0;
* }
*
* License: LGPL (2 or any later version)
* Author: Rusty Russell <rusty@rustcorp.com.au>
*/
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/build_assert\n");
printf("ccan/compiler\n");
printf("Judy\n");
return 0;
}
if (strcmp(argv[1], "libs") == 0) {
printf("Judy\n");
return 0;
}
return 1;
}
#include <ccan/jbitset/jbitset.h>
#include <ccan/build_assert/build_assert.h>
#include <stdlib.h>
#include <string.h>
struct jbitset *jbit_new(void)
{
struct jbitset *set;
/* Judy uses Word_t, we use size_t. */
BUILD_ASSERT(sizeof(size_t) == sizeof(Word_t));
set = malloc(sizeof(*set));
if (set) {
set->judy = NULL;
memset(&set->err, 0, sizeof(set->err));
set->errstr = NULL;
}
return set;
}
const char *jbit_error_(struct jbitset *set)
{
char *str;
free((char *)set->errstr);
set->errstr = str = malloc(100);
if (!set->errstr)
return "out of memory";
sprintf(str,
"JU_ERRNO_* == %d, ID == %d\n",
JU_ERRNO(&set->err), JU_ERRID(&set->err));
return str;
}
void jbit_free(const struct jbitset *set)
{
free((char *)set->errstr);
Judy1FreeArray((PPvoid_t)&set->judy, PJE0);
free((void *)set);
}
#ifndef CCAN_JBITSET_H
#define CCAN_JBITSET_H
#include <Judy.h>
#include <stdbool.h>
#include <ccan/compiler/compiler.h>
#include <assert.h>
/**
* jbit_new - create a new, empty jbitset.
*
* See Also:
* JBIT_DEFINE_TYPE()
*
* Example:
* struct jbitset *set = jbit_new();
* if (!set)
* errx(1, "Failed to allocate jbitset");
*/
struct jbitset *jbit_new(void);
/**
* jbit_free - destroy a jbitset.
* @set: the set returned from jbit_new.
*
* Example:
* jbit_free(set);
*/
void jbit_free(const struct jbitset *set);
/* This is exposed in the header so we can inline. Treat it as private! */
struct jbitset {
void *judy;
JError_t err;
const char *errstr;
};
const char *COLD_ATTRIBUTE jbit_error_(struct jbitset *set);
/**
* jbit_error - test for an error in the a previous jbit_ operation.
* @set: the set to test.
*
* Under normal circumstances, return NULL to indicate no error has occurred.
* Otherwise, it will return a string containing the error. This string
* can only be freed by jbit_free() on the set.
*
* Other than out-of-memory, errors are caused by memory corruption or
* interface misuse.
*
* Example:
* struct jbitset *set = jbit_new();
* const char *errstr;
*
* if (!set)
* err(1, "allocating jbitset");
* errstr = jbit_error(set);
* if (errstr)
* errx(1, "Woah, error on newly created set?! %s", errstr);
*/
static inline const char *jbit_error(struct jbitset *set)
{
if (JU_ERRNO(&set->err) <= JU_ERRNO_NFMAX)
return NULL;
return jbit_error_(set);
}
/**
* jbit_test - test a bit in the bitset.
* @set: bitset from jbit_new
* @index: the index to test
*
* Returns true if jbit_set() has been done on this index, false otherwise.
*
* Example:
* assert(!jbit_test(set, 0));
*/
static inline bool jbit_test(const struct jbitset *set, size_t index)
{
return Judy1Test(set->judy, index, (JError_t *)&set->err);
}
/**
* jbit_set - set a bit in the bitset.
* @set: bitset from jbit_new
* @index: the index to set
*
* Returns false if it was already set (ie. nothing changed)
*
* Example:
* if (jbit_set(set, 0))
* err(1, "Bit 0 was already set?!");
*/
static inline bool jbit_set(struct jbitset *set, size_t index)
{
return Judy1Set(&set->judy, index, &set->err);
}
/**
* jbit_clear - clear a bit in the bitset.
* @set: bitset from jbit_new
* @index: the index to set
*
* Returns the old bit value (ie. false if nothing changed).
*
* Example:
* if (jbit_clear(set, 0))
* err(1, "Bit 0 was already clear?!");
*/
static inline bool jbit_clear(struct jbitset *set, size_t index)
{
return Judy1Unset(&set->judy, index, &set->err);
}
/**
* jbit_popcount - get population of (some part of) bitset.
* @set: bitset from jbit_new
* @start: first index to count
* @end_incl: last index to count (use -1 for end).
*
* Example:
* assert(jbit_popcount(set, 0, 1000) <= jbit_popcount(set, 0, 2000));
*/
static inline size_t jbit_popcount(const struct jbitset *set,
size_t start, size_t end_incl)
{
return Judy1Count(set->judy, start, end_incl, (JError_t *)&set->err);
}
/**
* jbit_nth - return the index of the nth bit which is set.
* @set: bitset from jbit_new
* @n: which bit we are interested in (0-based)
* @invalid: what to return if n >= set population
*
* This normally returns the nth bit in the set, and often there is a
* convenient known-invalid value (ie. something which is never in the
* set). Otherwise, and a wrapper function like this can be used:
*
* static bool jbit_nth_index(struct jbitset *set, size_t n, size_t *idx)
* {
* // Zero might be valid, if it's first in set.
* if (n == 0 && jbit_test(set, 0)) {
* *idx = 0;
* return true;
* }
* *idx = jbit_nth(set, n, 0);
* return (*idx != 0);
* }
*
* Example:
* size_t i, val;
*
* // We know 0 isn't in set.
* assert(!jbit_test(set, 0));
* for (i = 0; (val = jbit_nth(set, i, 0)) != 0; i++) {
* assert(jbit_popcount(set, 0, val) == i);
* printf("Value %zu = %zu\n", i, val);
* }
*/
static inline size_t jbit_nth(const struct jbitset *set,
size_t n, size_t invalid)
{
Word_t index;
if (!Judy1ByCount(set->judy, n+1, &index, (JError_t *)&set->err))
index = invalid;
return index;
}
/**
* jbit_first - return the first bit which is set.
* @set: bitset from jbit_new
* @invalid: return value if no bits are set at all.
*
* This is equivalent to jbit_nth(set, 0, invalid).
*
* Example:
* assert(!jbit_test(set, 0));
* printf("Set contents (increasing order):");
* for (i = jbit_first(set, 0); i; i = jbit_next(set, i, 0))
* printf(" %zu", i);
* printf("\n");
*/
static inline size_t jbit_first(const struct jbitset *set, size_t invalid)
{
Word_t index = 0;
if (!Judy1First(set->judy, &index, (JError_t *)&set->err))
index = invalid;
else
assert(index != invalid);
return index;
}
/**
* jbit_next - return the next bit which is set.
* @set: bitset from jbit_new
* @prev: previous index
* @invalid: return value if no bits are set at all.
*
* This is usually used to find an adjacent bit which is set, after
* jbit_first.
*/
static inline size_t jbit_next(const struct jbitset *set, size_t prev,
size_t invalid)
{
if (!Judy1Next(set->judy, (Word_t *)&prev, (JError_t *)&set->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/**
* jbit_last - return the last bit which is set.
* @set: bitset from jbit_new
* @invalid: return value if no bits are set at all.
*
* Example:
* assert(!jbit_test(set, 0));
* printf("Set contents (decreasing order):");
* for (i = jbit_last(set, 0); i; i = jbit_prev(set, i, 0))
* printf(" %zu", i);
* printf("\n");
*/
static inline size_t jbit_last(const struct jbitset *set, size_t invalid)
{
Word_t index = -1;
if (!Judy1Last(set->judy, &index, (JError_t *)&set->err))
index = invalid;
else
assert(index != invalid);
return index;
}
/**
* jbit_prev - return the previous bit which is set.
* @set: bitset from jbit_new
* @prev: previous index
* @invalid: return value if no bits are set at all.
*
* This is usually used to find an adjacent bit which is set, after
* jbit_last.
*/
static inline size_t jbit_prev(const struct jbitset *set, size_t prev,
size_t invalid)
{
if (!Judy1Prev(set->judy, (Word_t *)&prev, (JError_t *)&set->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/**
* jbit_first_clear - return the first bit which is unset.
* @set: bitset from jbit_new
* @invalid: return value if no bits are clear at all.
*
* This allows for iterating the inverse of the bitmap.
*/
static inline size_t jbit_first_clear(const struct jbitset *set,
size_t invalid)
{
Word_t index = 0;
if (!Judy1FirstEmpty(set->judy, &index, (JError_t *)&set->err))
index = invalid;
else
assert(index != invalid);
return index;
}
static inline size_t jbit_next_clear(const struct jbitset *set, size_t prev,
size_t invalid)
{
if (!Judy1NextEmpty(set->judy, (Word_t *)&prev, (JError_t *)&set->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
static inline size_t jbit_last_clear(const struct jbitset *set, size_t invalid)
{
Word_t index = -1;
if (!Judy1LastEmpty(set->judy, &index, (JError_t *)&set->err))
index = invalid;
else
assert(index != invalid);
return index;
}
static inline size_t jbit_prev_clear(const struct jbitset *set, size_t prev,
size_t invalid)
{
if (!Judy1PrevEmpty(set->judy, (Word_t *)&prev, (JError_t *)&set->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
#endif /* CCAN_JBITSET_H */
#ifndef CCAN_JBITSET_TYPE_H
#define CCAN_JBITSET_TYPE_H
#include <ccan/jbitset/jbitset.h>
/**
* JBIT_DEFINE_TYPE - create a set of jbit ops for a given pointer type
* @type: a type whose pointers will go into the bitset.
* @name: a name for all the functions to define (of form jbit_<name>_*)
*
* This macro defines a set of inline functions for typesafe and convenient
* usage of a Judy bitset for pointers. It is assumed that a NULL pointer
* is never set in the bitset.
*
* Example:
* JBIT_DEFINE_TYPE(char, char);
* JBIT_DEFINE_TYPE(struct foo, foo);
*
* static struct jbitset_char *jc;
* struct jbitset_foo *jf;
*
* static void add_to_bitsets(const char *p, const struct foo *f)
* {
* // Note, this adds the pointer, not the string!
* jbit_char_set(jc, p);
* jbit_foo_set(jf, f);
* }
*/
#define JBIT_DEFINE_TYPE(type, name) \
struct jbitset_##name; \
static inline struct jbitset_##name *jbit_##name##_new(void) \
{ \
return (struct jbitset_##name *)jbit_new(); \
} \
static inline void jbit_##name##_free(const struct jbitset_##name *set) \
{ \
jbit_free((const struct jbitset *)set); \
} \
static inline const char *jbit_##name##_error(struct jbitset_##name *set) \
{ \
return jbit_error((struct jbitset *)set); \
} \
static inline bool jbit_##name##_test(const struct jbitset_##name *set, \
const type *index) \
{ \
return jbit_test((const struct jbitset *)set, (size_t)index); \
} \
static inline bool jbit_##name##_set(struct jbitset_##name *set, \
const type *index) \
{ \
return jbit_set((struct jbitset *)set, (size_t)index); \
} \
static inline bool jbit_##name##_clear(struct jbitset_##name *set, \
const type *index) \
{ \
return jbit_clear((struct jbitset *)set, (size_t)index); \
} \
static inline size_t jbit_##name##_count(struct jbitset_##name *set) \
{ \
return jbit_popcount((const struct jbitset *)set, 0, -1); \
} \
static inline type *jbit_##name##_nth(const struct jbitset_##name *set, \
size_t n) \
{ \
return (type *)jbit_nth((const struct jbitset *)set, n, 0); \
} \
static inline type *jbit_##name##_first(const struct jbitset_##name *set) \
{ \
return (type *)jbit_first((const struct jbitset *)set, 0); \
} \
static inline type *jbit_##name##_next(struct jbitset_##name *set, \
const type *prev) \
{ \
return (type *)jbit_next((const struct jbitset *)set, (size_t)prev, 0); \
} \
static inline type *jbit_##name##_last(struct jbitset_##name *set) \
{ \
return (type *)jbit_last((const struct jbitset *)set, 0); \
} \
static inline type *jbit_##name##_prev(struct jbitset_##name *set, \
const type *prev) \
{ \
return (type *)jbit_prev((const struct jbitset *)set, (size_t)prev, 0); \
}
#endif /* CCAN_JBITSET_TYPE_H */
#include <ccan/tap/tap.h>
#include <ccan/jbitset/jbitset_type.h>
#include <ccan/jbitset/jbitset.c>
struct foo;
JBIT_DEFINE_TYPE(struct foo, foo);
static int cmp_ptr(const void *a, const void *b)
{
return *(char **)a - *(char **)b;
}
#define NUM 100
int main(int argc, char *argv[])
{
struct jbitset_foo *set;
struct foo *foo[NUM];
unsigned int i;
plan_tests(20);
for (i = 0; i < NUM; i++)
foo[i] = malloc(20);
set = jbit_foo_new();
ok1(jbit_foo_error(set) == NULL);
ok1(jbit_foo_set(set, foo[0]) == true);
ok1(jbit_foo_set(set, foo[0]) == false);
ok1(jbit_foo_clear(set, foo[0]) == true);
ok1(jbit_foo_clear(set, foo[0]) == false);
ok1(jbit_foo_count(set) == 0);
ok1(jbit_foo_nth(set, 0) == (struct foo *)NULL);
ok1(jbit_foo_first(set) == (struct foo *)NULL);
ok1(jbit_foo_last(set) == (struct foo *)NULL);
for (i = 0; i < NUM; i++)
jbit_foo_set(set, foo[i]);
qsort(foo, NUM, sizeof(foo[0]), cmp_ptr);
ok1(jbit_foo_count(set) == NUM);
ok1(jbit_foo_nth(set, 0) == foo[0]);
ok1(jbit_foo_nth(set, NUM-1) == foo[NUM-1]);
ok1(jbit_foo_nth(set, NUM) == (struct foo *)NULL);
ok1(jbit_foo_first(set) == foo[0]);
ok1(jbit_foo_last(set) == foo[NUM-1]);
ok1(jbit_foo_next(set, foo[0]) == foo[1]);
ok1(jbit_foo_next(set, foo[NUM-1]) == (struct foo *)NULL);
ok1(jbit_foo_prev(set, foo[1]) == foo[0]);
ok1(jbit_foo_prev(set, foo[0]) == (struct foo *)NULL);
ok1(jbit_foo_error(set) == NULL);
jbit_foo_free(set);
return exit_status();
}
#include <ccan/tap/tap.h>
#include <ccan/jbitset/jbitset.c>
int main(int argc, char *argv[])
{
struct jbitset *set;
size_t i;
const char *err;
plan_tests(36);
set = jbit_new();
ok1(jbit_error(set) == NULL);
ok1(jbit_set(set, 0) == true);
ok1(jbit_set(set, 0) == false);
ok1(jbit_clear(set, 0) == true);
ok1(jbit_clear(set, 0) == false);
ok1(jbit_popcount(set, 0, -1) == 0);
ok1(jbit_nth(set, 0, 0) == 0);
ok1(jbit_nth(set, 0, -1) == (size_t)-1);
ok1(jbit_first(set, 0) == 0);
ok1(jbit_first(set, -1) == (size_t)-1);
ok1(jbit_last(set, 0) == 0);
ok1(jbit_last(set, -1) == (size_t)-1);
ok1(jbit_first_clear(set, -1) == 0);
ok1(jbit_first_clear(set, -2) == 0);
ok1(jbit_last_clear(set, 0) == (size_t)-1);
ok1(jbit_prev_clear(set, 1, -1) == 0);
ok1(jbit_next_clear(set, 0, -1) == 1);
ok1(jbit_next_clear(set, -1, -1) == -1);
/* Set a million bits, 16 bits apart. */
for (i = 0; i < 1000000; i++)
jbit_set(set, i << 4);
/* This only take 1.7MB on my 32-bit system. */
diag("%u bytes memory used\n", (unsigned)Judy1MemUsed(set->judy));
ok1(jbit_popcount(set, 0, -1) == 1000000);
ok1(jbit_nth(set, 0, -1) == 0);
ok1(jbit_nth(set, 999999, -1) == 999999 << 4);
ok1(jbit_nth(set, 1000000, -1) == (size_t)-1);
ok1(jbit_first(set, -1) == 0);
ok1(jbit_last(set, -1) == 999999 << 4);
ok1(jbit_first_clear(set, -1) == 1);
ok1(jbit_last_clear(set, 0) == (size_t)-1);
ok1(jbit_prev_clear(set, 1, -1) == (size_t)-1);
ok1(jbit_next(set, 0, -1) == 1 << 4);
ok1(jbit_next(set, 999999 << 4, -1) == (size_t)-1);
ok1(jbit_prev(set, 1, -1) == 0);
ok1(jbit_prev(set, 0, -1) == (size_t)-1);
ok1(jbit_error(set) == NULL);
/* Test error handling */
JU_ERRNO(&set->err) = 100;
JU_ERRID(&set->err) = 991;
err = jbit_error(set);
ok1(err);
ok1(strstr(err, "100"));
ok1(strstr(err, "991"));
ok1(err == set->errstr);
jbit_free(set);
return exit_status();
}
#include <stdio.h>
#include <string.h>
#include "config.h"
/**
* jmap - map from indices to values (based on libJudy)
*
* This provides a convenient wrapper for using JudyL arrays; using
* integers or pointers as an index, Judy arrays provide an efficient
* map to integers or pointers.
*
* jmap.h simply contains wrappers for a size_t-indexed size_t values, and
* jmap_type.h contain a wrapper macro for size_t->pointer maps and pointer
* ->pointer maps.
*
* Example:
* // Silly example of associating data with arguments by pointer and int.
* #include <string.h>
* #include <stdio.h>
* #include <ccan/jmap/jmap_type.h>
*
* struct opt_detail {
* bool is_long;
* unsigned int length; // == 1 if !is_long.
* };
*
* // Define jmap_arg_<op> and jmap_arg, for int -> argv.
* JMAP_DEFINE_UINTIDX_TYPE(char, arg);
* // Define jmap_opt_<op> and jmap_opt, for argv -> struct opt_detail *.
* JMAP_DEFINE_PTRIDX_TYPE(char, struct opt_detail, opt);
*
* int main(int argc, char *argv[])
* {
* int i;
* // This map is equivalent to the argv[] array. Silly example.
* struct jmap_arg *arg = jmap_arg_new();
* struct jmap_opt *opt = jmap_opt_new();
* struct opt_detail *d;
*
* // Note: this is not correct for real parsing!
* for (i = 0; i < argc; i++) {
* jmap_arg_add(arg, i, argv[i]);
* if (i < 1 || argv[i][0] != '-')
* continue;
* d = malloc(sizeof(*d));
* if (argv[i][1] == '-') {
* // --<stuff>
* d->is_long = true;
* d->length = strlen(argv[i]+2);
* } else {
* // -<opt1>
* d->is_long = false;
* d->length = 1;
* }
* jmap_opt_add(opt, argv[i], d);
* }
*
* printf("Found %u options:\n", jmap_opt_count(opt));
* for (i = jmap_arg_first(arg,-1); i!=-1; i = jmap_arg_next(arg,i,-1)) {
* char *a = jmap_arg_get(arg, i);
* d = jmap_opt_get(opt, a);
* printf(" Arg %i ('%s') is a %s of %u chars\n",
* i, a,
* d == NULL ? "normal argument"
* : d->is_long ? "long option"
* : "short option",
* d == NULL ? strlen(a) : d->length);
* // We no longer need it, so free it here.
* free(d);
* }
* jmap_opt_free(opt);
* jmap_arg_free(arg);
* return 0;
* }
*
* License: LGPL (2 or any later version)
* Author: Rusty Russell <rusty@rustcorp.com.au>
*/
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/build_assert\n");
printf("ccan/compiler\n");
printf("Judy\n");
return 0;
}
if (strcmp(argv[1], "libs") == 0) {
printf("Judy\n");
return 0;
}
return 1;
}
#include <ccan/jmap/jmap.h>
#include <ccan/build_assert/build_assert.h>
#include <stdlib.h>
#include <string.h>
struct jmap *jmap_new(void)
{
struct jmap *map;
/* Judy uses Word_t, we use size_t. */
BUILD_ASSERT(sizeof(size_t) == sizeof(Word_t));
map = malloc(sizeof(*map));
if (map) {
map->judy = NULL;
memset(&map->err, 0, sizeof(map->err));
map->errstr = NULL;
map->num_accesses = 0;
map->acc_value = NULL;
map->acc_index = 0;
map->funcname = NULL;
}
return map;
}
const char *jmap_error_(struct jmap *map)
{
char *str;
free((char *)map->errstr);
map->errstr = str = malloc(100);
if (!map->errstr)
return "out of memory";
sprintf(str,
"JU_ERRNO_* == %d, ID == %d\n",
JU_ERRNO(&map->err), JU_ERRID(&map->err));
return str;
}
void jmap_free(const struct jmap *map)
{
free((char *)map->errstr);
Judy1FreeArray((PPvoid_t)&map->judy, PJE0);
free((void *)map);
}
#ifndef CCAN_JMAP_H
#define CCAN_JMAP_H
#include <Judy.h>
#include <stdbool.h>
#include <ccan/compiler/compiler.h>
#include <assert.h>
#ifdef DEBUG
#include <stdio.h>
#endif
/**
* jmap_new - create a new, empty jmap.
*
* See Also:
* JMAP_DEFINE_TYPE()
*
* Example:
* struct jmap *map = jmap_new();
* if (!map)
* errx(1, "Failed to allocate jmap");
*/
struct jmap *jmap_new(void);
/**
* jmap_free - destroy a jmap.
* @map: the map returned from jmap_new.
*
* Example:
* jmap_free(map);
*/
void jmap_free(const struct jmap *map);
/* This is exposed in the header so we can inline. Treat it as private! */
struct jmap {
Pvoid_t judy;
JError_t err;
const char *errstr;
/* Used if !NDEBUG */
int num_accesses;
/* Used if DEBUG */
size_t *acc_value;
size_t acc_index;
const char *funcname;
};
const char *COLD_ATTRIBUTE jmap_error_(struct jmap *map);
/* Debugging checks. */
static inline void jmap_debug_add_access(const struct jmap *map,
size_t index, size_t *val,
const char *funcname)
{
#ifdef DEBUG
if (!map->acc_value) {
((struct jmap *)map)->acc_value = val;
((struct jmap *)map)->acc_index = index;
((struct jmap *)map)->funcname = funcname;
}
#endif
if (val)
assert(++((struct jmap *)map)->num_accesses);
}
static inline void jmap_debug_del_access(struct jmap *map, size_t **val)
{
assert(--map->num_accesses >= 0);
#ifdef DEBUG
if (map->acc_value == *val)
map->acc_value = NULL;
#endif
/* Set it to some invalid value. Not NULL, they might rely on that! */
assert((*val = (void *)jmap_new) != NULL);
}
static inline void jmap_debug_access(struct jmap *map)
{
#ifdef DEBUG
if (map->num_accesses && map->acc_value)
fprintf(stderr,
"jmap: still got index %zu, val %zu (%p) from %s\n",
map->acc_index, *map->acc_value, map->acc_value,
map->funcname);
#endif
assert(!map->num_accesses);
}
/**
* jmap_error - test for an error in the a previous jmap_ operation.
* @map: the map to test.
*
* Under normal circumstances, return NULL to indicate no error has occurred.
* Otherwise, it will return a string containing the error. This string
* can only be freed by jmap_free() on the map.
*
* Other than out-of-memory, errors are caused by memory corruption or
* interface misuse.
*
* Example:
* struct jmap *map = jmap_new();
* const char *errstr;
*
* if (!map)
* err(1, "allocating jmap");
* errstr = jmap_error(map);
* if (errstr)
* errx(1, "Woah, error on newly created map?! %s", errstr);
*/
static inline const char *jmap_error(struct jmap *map)
{
if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX)
return NULL;
return jmap_error_(map);
}
/**
* jmap_add - add or replace a value for a given index in the map.
* @map: map from jmap_new
* @index: the index to map
* @value: the value to associate with the index
*
* Adds index into the map; replaces value if it's already there.
* Returns false on error (out of memory).
*
* Example:
* if (!jmap_add(map, 0, 1))
* err(1, "jmap_add failed!");
*/
static inline bool jmap_add(struct jmap *map, size_t index, size_t value)
{
Word_t *val;
jmap_debug_access(map);
val = (void *)JudyLIns(&map->judy, index, &map->err);
if (val == PJERR)
return false;
*val = value;
return true;
}
/**
* jmap_set - change a value for an existing index in the map.
* @map: map from jmap_new
* @index: the index to map
* @value: the value to associate with the index
*
* This sets the value of an index if it already exists, and return true,
* otherwise returns false and does nothing.
*
* Example:
* if (!jmap_set(map, 0, 2))
* err(1, "jmap_set: index 0 not found");
*/
static inline bool jmap_set(const struct jmap *map, size_t index, size_t value)
{
Word_t *val;
val = (void *)JudyLGet(map->judy, index, (JError_t *)&map->err);
if (val && val != PJERR) {
*val = value;
return true;
}
return false;
}
/**
* jmap_del - remove an index from the map.
* @map: map from jmap_new
* @index: the index to map
*
* Example:
* if (!jmap_del(map, 0))
* err(1, "jmap_del failed!");
*/
static inline bool jmap_del(struct jmap *map, size_t index)
{
jmap_debug_access(map);
return JudyLDel(&map->judy, index, &map->err) == 1;
}
/**
* jmap_test - test if a given index is defined.
* @map: map from jmap_new
* @index: the index to find
*
* Example:
* jmap_add(map, 0, 1);
* assert(jmap_test(map, 0));
*/
static inline bool jmap_test(const struct jmap *map, size_t index)
{
return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
}
/**
* jmap_get - get a value for a given index.
* @map: map from jmap_new
* @index: the index to find
* @invalid: the value to return if the index isn't found.
*
* Example:
* jmap_add(map, 0, 1);
* assert(jmap_get(map, 0, -1) == 1);
*
* See Also:
* jmap_getval()
*/
static inline size_t jmap_get(const struct jmap *map, size_t index,
size_t invalid)
{
Word_t *val;
val = (void *)JudyLGet(map->judy, index, (JError_t *)&map->err);
if (!val || val == PJERR)
return invalid;
return *val;
}
/**
* jmap_popcount - get population of (some part of) the map.
* @map: map from jmap_new
* @start: first index to count
* @end_incl: last index to count (use -1 for end).
*
* Example:
* assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
*/
static inline size_t jmap_popcount(const struct jmap *map,
size_t start, size_t end_incl)
{
return JudyLCount(map->judy, start, end_incl, (JError_t *)&map->err);
}
/**
* jmap_nth - return the index of the nth value in the map.
* @map: map from jmap_new
* @n: which index we are interested in (0-based)
* @invalid: what to return if n >= map population
*
* This normally returns the nth index in the map, and often there is a
* convenient known-invalid value (ie. something which is never in the
* map). Otherwise you can use jmap_nthval().
*
* Example:
* size_t i, index;
*
* // We know 0 isn't in map.
* assert(!jmap_test(map, 0));
* for (i = 0; (index = jmap_nth(map, i, 0)) != 0; i++) {
* assert(jmap_popcount(map, 0, index) == i);
* printf("Index %zu = %zu\n", i, index);
* }
*
* See Also:
* jmap_nthval();
*/
static inline size_t jmap_nth(const struct jmap *map,
size_t n, size_t invalid)
{
Word_t index;
if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
index = invalid;
return index;
}
/**
* jmap_first - return the first index in the map.
* @map: map from jmap_new
* @invalid: return value if jmap is empty.
*
* This is equivalent to jmap_nth(map, 0, invalid).
*
* Example:
* assert(!jmap_test(map, 0));
* printf("Map indices (increasing order):");
* for (i = jmap_first(map, 0); i; i = jmap_next(map, i, 0))
* printf(" %zu", i);
* printf("\n");
*
* See Also:
* jmap_firstval()
*/
static inline size_t jmap_first(const struct jmap *map, size_t invalid)
{
Word_t index = 0;
if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
index = invalid;
else
assert(index != invalid);
return index;
}
/**
* jmap_next - return the next index in the map.
* @map: map from jmap_new
* @prev: previous index
* @invalid: return value if there prev was final index in map.
*
* This is usually used to find an adjacent index after jmap_first.
* See Also:
* jmap_nextval()
*/
static inline size_t jmap_next(const struct jmap *map, size_t prev,
size_t invalid)
{
if (!JudyLNext(map->judy, (Word_t *)&prev, (JError_t *)&map->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/**
* jmap_last - return the last index in the map.
* @map: map from jmap_new
* @invalid: return value if map is empty.
*
* Example:
* assert(!jmap_test(map, 0));
* printf("Map indices (increasing order):");
* for (i = jmap_last(map, 0); i; i = jmap_prev(map, i, 0))
* printf(" %zu", i);
* printf("\n");
* See Also:
* jmap_lastval()
*/
static inline size_t jmap_last(const struct jmap *map, size_t invalid)
{
Word_t index = -1;
if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
index = invalid;
else
assert(index != invalid);
return index;
}
/**
* jmap_prev - return the previous index in the map.
* @map: map from jmap_new
* @prev: previous index
* @invalid: return value if no previous indices are in the map.
*
* This is usually used to find an prior adjacent index after jmap_last.
* See Also:
* jmap_prevval()
*/
static inline size_t jmap_prev(const struct jmap *map, size_t prev,
size_t invalid)
{
if (!JudyLPrev(map->judy, (Word_t *)&prev, (JError_t *)&map->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/**
* jmap_getval - access a value in-place for a given index.
* @map: map from jmap_new
* @index: the index to find
*
* Returns a pointer into the map, or NULL if the index isn't in the
* map. Like the other val functions (jmap_nthval, jmap_firstval
* etc), this pointer cannot be used after a jmap_add or jmap_del
* call, and you must call jmap_putval() once you are finished.
*
* Unless you define NDEBUG, jmap_add and kmap_del will check that you
* have called jmap_putval().
*
* Example:
* size_t *p;
* jmap_add(map, 0, 1);
* p = jmap_getval(map, 0);
* if (!p)
* errx(1, "Could not find 0 in map!");
* if (*p != 1)
* errx(1, "Value in map was not 0?!");
* *p = 7;
* jmap_putval(map, &p);
* // Accessing p now would probably crash.
*
* See Also:
* jmap_putval(), jmap_firstval()
*/
static inline size_t *jmap_getval(struct jmap *map, size_t index)
{
size_t *val;
val = (void *)JudyLGet(map->judy, index, (JError_t *)&map->err);
jmap_debug_add_access(map, index, val, "jmap_getval");
return val;
}
/**
* jmap_putval - revoke access to a value.
* @map: map from jmap_new
* @p: the pointer to a pointer to the value
*
* @p is a pointer to the (successful) value retuned from one of the
* jmap_*val functions (listed below). After this, it will be invalid.
*
* Unless NDEBUG is defined, this will actually alter the value of p
* to point to garbage to help avoid accidental use.
*
* See Also:
* jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(),
* jmap_lastval(), jmap_prevval().
*/
static inline void jmap_putval(struct jmap *map, size_t **p)
{
jmap_debug_del_access(map, p);
}
/**
* jmap_nthval - access the value of the nth value in the map.
* @map: map from jmap_new
* @n: which index we are interested in (0-based)
*
* This returns a pointer to the value at the nth index in the map,
* or NULL if there are n is greater than the population of the map.
* You must use jmap_putval() on the pointer once you are done with it.
*
* Example:
* size_t *val;
*
* // We know 0 isn't in map.
* assert(!jmap_test(map, 0));
* for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) {
* assert(jmap_popcount(map, 0, index) == i);
* printf("Index %zu = %zu, value = %zu\n", i, index, *val);
* jmap_putval(map, &val);
* }
*
* See Also:
* jmap_nth();
*/
static inline size_t *jmap_nthval(const struct jmap *map,
size_t n, size_t *index)
{
size_t *val;
val = (size_t *)JudyLByCount(map->judy, n+1, (Word_t *)index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_nthval");
return val;
}
/**
* jmap_firstval - access the first value in the map.
* @map: map from jmap_new
* @index: set to the first index in the map.
*
* Returns NULL if the map is empty; otherwise this returns a pointer to
* the first value, which you must call jmap_putval() on!
*
* Example:
* // Add one to every value.
* for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) {
* (*val)++;
* jmap_putval(map, &val);
* }
* printf("\n");
*
* See Also:
* jmap_first, jmap_nextval()
*/
static inline size_t *jmap_firstval(const struct jmap *map, size_t *index)
{
size_t *val;
*index = 0;
val = (size_t *)JudyLFirst(map->judy, (Word_t *)index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_firstval");
return val;
}
/**
* jmap_nextval - access the next value in the map.
* @map: map from jmap_new
* @index: previous index, updated with the new index.
*
* This returns a pointer to a value (which you must call jmap_putval on)
* or NULL. This usually used to find an adjacent value after jmap_firstval.
*
* See Also:
* jmap_firstval(), jmap_putval()
*/
static inline size_t *jmap_nextval(const struct jmap *map, size_t *index)
{
size_t *val;
val = (size_t *)JudyLNext(map->judy, (Word_t *)index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_nextval");
return val;
}
/**
* jmap_lastval - access the last value in the map.
* @map: map from jmap_new
* @index: set to the last index in the map.
*
* See Also:
* jmap_last(), jmap_putval()
*/
static inline size_t *jmap_lastval(const struct jmap *map, size_t *index)
{
size_t *val;
*index = -1;
val = (size_t *)JudyLLast(map->judy, (Word_t *)index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_lastval");
return val;
}
/**
* jmap_prevval - access the previous value in the map.
* @map: map from jmap_new
* @index: previous index, updated with the new index.
*
* This returns a pointer to a value (which you must call jmap_putval on)
* or NULL. This usually used to find an adjacent value after jmap_lastval.
*
* See Also:
* jmap_lastval(), jmap_putval()
*/
static inline size_t *jmap_prevval(const struct jmap *map, size_t *index)
{
size_t *val;
val = (size_t *)JudyLPrev(map->judy, (Word_t *)index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_prevval");
return val;
}
#endif /* CCAN_JMAP_H */
#ifndef CCAN_JMAP_TYPE_H
#define CCAN_JMAP_TYPE_H
#include <ccan/jmap/jmap.h>
/**
* JMAP_DEFINE_UINTIDX_TYPE - create a set of jmap ops for integer->ptr map
* @type: a type whose pointers will be values in the map.
* @name: a name for all the functions to define (of form jmap_<name>_*)
*
* It's easiest if NULL values aren't placed in the map: jmap_@name_get will
* return NULL if an index isn't valid.
*
* The following wrapper functions are defined; each one is the same as
* the jmap.h generic equivalent except where noted:
*
* struct jmap_@name *jmap_@name_new(void);
* void jmap_@name_free(const struct jmap_@name *map);
* const char *jmap_@name_error(struct jmap_@name *map);
*
* bool jmap_@name_add(const struct jmap_@name *map,
* size_t index, const type *value);
* bool jmap_@name_set(const struct jmap_@name *map,
* size_t index, const type *value);
* bool jmap_@name_del(struct jmap_@name *map, size_t index);
* bool jmap_@name_test(const struct jmap_@name *map, size_t index);
*
* type *jmap_@name_get(const struct jmap_@name *map, size_t index);
* size_t jmap_@name_popcount(const struct jmap_@name *map,
* size_t start, size_t end_incl);
* size_t jmap_@name_nth(const struct jmap_@name *map,
* size_t n, size_t invalid);
* size_t jmap_@name_first(const struct jmap_@name *map,
* size_t invalid);
* size_t jmap_@name_next(const struct jmap_@name *map,
* size_t prev, size_t invalid);
* size_t jmap_@name_last(const struct jmap_@name *map,
* size_t invalid);
* size_t jmap_@name_prev(const struct jmap_@name *map,
* size_t prev, size_t invalid);
*
* type **jmap_@name_getval(const struct jmap_@name *map, size_t index);
* void jmap_@name_putval(struct jmap_@name *map, type ***p);
* type **jmap_@name_nthval(struct jmap_@name *map,
* size_t n, size_t *index);
* type **jmap_@name_firstval(const struct jmap_@name *map,
* size_t *index);
* type **jmap_@name_nextval(const struct jmap_@name *map, size_t *index);
* type **jmap_@name_lastval(const struct jmap_@name *map, size_t *index);
* type **jmap_@name_prevval(const struct jmap_@name *map, size_t *index);
*/
#define JMAP_DEFINE_UINTIDX_TYPE(type, name) \
struct jmap_##name; \
static inline struct jmap_##name *jmap_##name##_new(void) \
{ \
return (struct jmap_##name *)jmap_new(); \
} \
static inline void jmap_##name##_free(const struct jmap_##name *map) \
{ \
jmap_free((const struct jmap *)map); \
} \
static inline const char *jmap_##name##_error(struct jmap_##name *map) \
{ \
return jmap_error((struct jmap *)map); \
} \
static inline bool jmap_##name##_add(struct jmap_##name *map, \
size_t index, const type *value) \
{ \
return jmap_add((struct jmap *)map, index, (size_t)value); \
} \
static inline bool jmap_##name##_set(const struct jmap_##name *map, \
size_t index, const type *value) \
{ \
return jmap_set((const struct jmap *)map, index, (size_t)value); \
} \
static inline bool jmap_##name##_del(struct jmap_##name *map, size_t index) \
{ \
return jmap_del((struct jmap *)map, index); \
} \
static inline bool jmap_##name##_test(const struct jmap_##name *map, \
size_t index) \
{ \
return jmap_test((const struct jmap *)map, (size_t)index); \
} \
static inline type *jmap_##name##_get(const struct jmap_##name *map, \
size_t index) \
{ \
return (type *)jmap_get((const struct jmap *)map, index, 0); \
} \
static inline size_t jmap_##name##_popcount(const struct jmap_##name *map, \
size_t start, size_t end_incl) \
{ \
return jmap_popcount((const struct jmap *)map, start, end_incl); \
} \
static inline size_t jmap_##name##_nth(const struct jmap_##name *map, \
size_t n, size_t invalid) \
{ \
return jmap_nth((const struct jmap *)map, n, invalid); \
} \
static inline size_t jmap_##name##_first(const struct jmap_##name *map, \
size_t invalid) \
{ \
return jmap_first((const struct jmap *)map, invalid); \
} \
static inline size_t jmap_##name##_next(const struct jmap_##name *map, \
size_t prev, size_t invalid) \
{ \
return jmap_next((const struct jmap *)map, prev, invalid); \
} \
static inline size_t jmap_##name##_last(const struct jmap_##name *map, \
size_t invalid) \
{ \
return jmap_last((const struct jmap *)map, invalid); \
} \
static inline size_t jmap_##name##_prev(const struct jmap_##name *map, \
size_t prev, size_t invalid) \
{ \
return jmap_prev((const struct jmap *)map, prev, invalid); \
} \
static inline type **jmap_##name##_getval(const struct jmap_##name *map, \
size_t index) \
{ \
return (type **)jmap_getval((struct jmap *)map, index); \
} \
static inline void jmap_##name##_putval(struct jmap_##name *map, \
type ***p) \
{ \
return jmap_putval((struct jmap *)map, (size_t **)p); \
} \
static inline type **jmap_##name##_nthval(struct jmap_##name *map, \
size_t n, size_t *index) \
{ \
return (type **)jmap_nthval((struct jmap *)map, n, index); \
} \
static inline type **jmap_##name##_firstval(const struct jmap_##name *map, \
size_t *index) \
{ \
return (type **)jmap_firstval((const struct jmap *)map, index); \
} \
static inline type **jmap_##name##_nextval(const struct jmap_##name *map, \
size_t *index) \
{ \
return (type **)jmap_nextval((const struct jmap *)map, index); \
} \
static inline type **jmap_##name##_lastval(const struct jmap_##name *map, \
size_t *index) \
{ \
return (type **)jmap_lastval((const struct jmap *)map, index); \
} \
static inline type **jmap_##name##_prevval(const struct jmap_##name *map, \
size_t *index) \
{ \
return (type **)jmap_prevval((const struct jmap *)map, index); \
}
/**
* JMAP_DEFINE_PTRIDX_TYPE - create a map of jmap ops for ptr->ptr map
* @itype: a type whose pointers will index into the map.
* @type: a type whose pointers will be values in the map.
* @name: a name for all the functions to define (of form jmap_<name>_*)
*
* This macro defines a map of inline functions for typesafe and
* convenient usage of a pointer-indexed Judy map of pointers. It is
* assumed that a NULL pointer is never an index in the map, as
* various functions return NULL for "invalid index". Similarly,
* jmap_@name_get will return NULL if an index isn't valid, so NULL indices
* are not recommended (though you can tell using jmap_@name_test).
*
* Since the ordering is by index pointer value, it's generally quite useless.
* Thus we don't define order-specific functions, except first/next for
* traversal.
*
* The following wrapper functions are defined; each one is the same as
* the jmap.h generic equivalent:
*
* struct jmap_@name *jmap_@name_new(void);
* void jmap_@name_free(const struct jmap_@name *map);
* const char *jmap_@name_error(struct jmap_@name *map);
*
* bool jmap_@name_add(const struct jmap_@name *map,
* const itype *index, const type *value);
* bool jmap_@name_set(const struct jmap_@name *map,
* const itype *index, const type *value);
* bool jmap_@name_del(struct jmap_@name *map, const itype *index);
* bool jmap_@name_test(const struct jmap_@name *map, const itype *index);
*
* type *jmap_@name_get(const struct jmap_@name *map, const itype *index);
* itype *jmap_@name_count(const struct jmap_@name *map);
* itype *jmap_@name_first(const struct jmap_@name *map);
* itype *jmap_@name_next(const struct jmap_@name *map,
* const itype *prev);
*
* type **jmap_@name_getval(const struct jmap_@name *map,
* const itype *index);
* void jmap_@name_putval(struct jmap_@name *map, type ***p);
* type **jmap_@name_firstval(const struct jmap_@name *map,
* const itype **index);
* type **jmap_@name_nextval(const struct jmap_@name *map,
* const itype **index);
*/
#define JMAP_DEFINE_PTRIDX_TYPE(itype, type, name) \
struct jmap_##name; \
static inline struct jmap_##name *jmap_##name##_new(void) \
{ \
return (struct jmap_##name *)jmap_new(); \
} \
static inline void jmap_##name##_free(const struct jmap_##name *map) \
{ \
jmap_free((const struct jmap *)map); \
} \
static inline const char *jmap_##name##_error(struct jmap_##name *map) \
{ \
return jmap_error((struct jmap *)map); \
} \
static inline bool jmap_##name##_add(struct jmap_##name *map, \
const itype *index, const type *value) \
{ \
return jmap_add((struct jmap *)map, (size_t)index, \
(size_t)value); \
} \
static inline bool jmap_##name##_set(const struct jmap_##name *map, \
const itype *index, const type *value) \
{ \
return jmap_set((const struct jmap *)map, (size_t)index, \
(size_t)value); \
} \
static inline bool jmap_##name##_del(struct jmap_##name *map, \
const itype *index) \
{ \
return jmap_del((struct jmap *)map, (size_t)index); \
} \
static inline bool jmap_##name##_test(const struct jmap_##name *map, \
const itype *index) \
{ \
return jmap_test((const struct jmap *)map, (size_t)index); \
} \
static inline type *jmap_##name##_get(const struct jmap_##name *map, \
const itype *index) \
{ \
return (type *)jmap_get((const struct jmap *)map, (size_t)index, 0); \
} \
static inline size_t jmap_##name##_count(const struct jmap_##name *map) \
{ \
return jmap_popcount((const struct jmap *)map, 0, -1); \
} \
static inline itype *jmap_##name##_first(const struct jmap_##name *map) \
{ \
return (itype *)jmap_first((const struct jmap *)map, 0); \
} \
static inline itype *jmap_##name##_next(const struct jmap_##name *map, \
const itype *prev) \
{ \
return (itype *)jmap_next((const struct jmap *)map, (size_t)prev, 0); \
} \
static inline type **jmap_##name##_getval(const struct jmap_##name *map, \
const itype *index) \
{ \
return (type **)jmap_getval((struct jmap *)map, (size_t)index); \
} \
static inline void jmap_##name##_putval(struct jmap_##name *map, \
type ***p) \
{ \
return jmap_putval((struct jmap *)map, (size_t **)p); \
} \
static inline type **jmap_##name##_firstval(const struct jmap_##name *map, \
itype **index) \
{ \
return (type **)jmap_firstval((const struct jmap *)map, \
(size_t *)index); \
} \
static inline type **jmap_##name##_nextval(const struct jmap_##name *map, \
itype **index) \
{ \
return (type **)jmap_nextval((const struct jmap *)map, \
(size_t *)index); \
}
#endif /* CCAN_JMAP_TYPE_H */
/* Test our access counting failures. */
#include <ccan/jmap/jmap.c>
#include <ccan/tap/tap.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
struct jmap *map;
size_t *value;
int status;
plan_tests(9);
map = jmap_new();
ok1(jmap_error(map) == NULL);
ok1(jmap_add(map, 0, 1));
/* add while holding value. */
value = jmap_getval(map, 0);
ok1(value);
if (!fork()) {
jmap_add(map, 1, 2);
exit(0);
} else {
wait(&status);
ok1(WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT);
}
jmap_putval(map, &value);
/* del while holding value. */
value = jmap_getval(map, 0);
ok1(value);
if (!fork()) {
jmap_del(map, 0);
exit(0);
} else {
wait(&status);
ok1(WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT);
}
jmap_putval(map, &value);
ok1(jmap_add(map, 0, 1));
/* set while holding value ok. */
value = jmap_getval(map, 0);
ok1(value);
if (!fork()) {
jmap_set(map, 0, 2);
exit(0);
} else {
wait(&status);
ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
jmap_putval(map, &value);
/* FIXME: test jmap_nthval, jmap_firstval etc. */
jmap_free(map);
return exit_status();
}
#include <ccan/tap/tap.h>
#include <ccan/jmap/jmap_type.h>
#include <ccan/jmap/jmap.c>
struct foo;
struct idx;
JMAP_DEFINE_PTRIDX_TYPE(struct idx, struct foo, foo);
#define NUM 100
static int cmp_ptr(const void *a, const void *b)
{
return *(char **)a - *(char **)b;
}
int main(int argc, char *argv[])
{
struct jmap_foo *map;
struct foo *foo[NUM], **foop;
struct idx *idx[NUM], *index;
unsigned int i;
plan_tests(25 + NUM*2 + 6);
for (i = 0; i < NUM; i++)
foo[i] = malloc(20);
qsort(foo, NUM, sizeof(foo[0]), cmp_ptr);
/* idx[i] == foo[i] + 1, for easy checking */
for (i = 0; i < NUM; i++)
idx[i] = (void *)((char *)foo[i] + 1);
map = jmap_foo_new();
ok1(jmap_foo_error(map) == NULL);
ok1(jmap_foo_test(map, idx[i]) == false);
ok1(jmap_foo_get(map, idx[i]) == (struct foo *)NULL);
ok1(jmap_foo_count(map) == 0);
ok1(jmap_foo_first(map) == (struct idx *)NULL);
ok1(jmap_foo_del(map, idx[0]) == false);
/* Set only works on existing cases. */
ok1(jmap_foo_set(map, idx[0], foo[0]) == false);
ok1(jmap_foo_add(map, idx[0], foo[1]) == true);
ok1(jmap_foo_get(map, idx[0]) == foo[1]);
ok1(jmap_foo_set(map, idx[0], foo[0]) == true);
ok1(jmap_foo_get(map, idx[0]) == foo[0]);
ok1(jmap_foo_test(map, idx[0]) == true);
ok1(jmap_foo_count(map) == 1);
ok1(jmap_foo_first(map) == idx[0]);
ok1(jmap_foo_next(map, idx[0]) == NULL);
ok1(jmap_foo_del(map, idx[0]) == true);
ok1(jmap_foo_test(map, idx[0]) == false);
ok1(jmap_foo_count(map) == 0);
for (i = 0; i < NUM; i++)
jmap_foo_add(map, idx[i], foo[i]);
ok1(jmap_foo_count(map) == NUM);
ok1(jmap_foo_first(map) == idx[0]);
ok1(jmap_foo_next(map, idx[0]) == idx[1]);
ok1(jmap_foo_next(map, idx[NUM-1]) == NULL);
ok1(jmap_foo_get(map, idx[0]) == foo[0]);
ok1(jmap_foo_get(map, idx[NUM-1]) == foo[NUM-1]);
ok1(jmap_foo_get(map, (void *)((char *)idx[NUM-1] + 1)) == NULL);
/* Reverse values in map. */
for (i = 0; i < NUM; i++) {
foop = jmap_foo_getval(map, idx[i]);
ok1(*foop == foo[i]);
*foop = foo[NUM-1-i];
jmap_foo_putval(map, &foop);
}
for (i = 0; i < NUM; i++)
ok1(jmap_foo_get(map, idx[i]) == foo[NUM-1-i]);
foop = jmap_foo_firstval(map, &index);
ok1(index == idx[0]);
ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_nextval(map, &index);
ok1(index == idx[1]);
ok1(*foop == foo[NUM-2]);
jmap_foo_putval(map, &foop);
index = idx[NUM-1];
foop = jmap_foo_nextval(map, &index);
ok1(foop == NULL);
ok1(jmap_foo_error(map) == NULL);
jmap_foo_free(map);
return exit_status();
}
#include <ccan/tap/tap.h>
#include <ccan/jmap/jmap_type.h>
#include <ccan/jmap/jmap.c>
struct foo;
JMAP_DEFINE_UINTIDX_TYPE(struct foo, foo);
#define NUM 100
int main(int argc, char *argv[])
{
struct jmap_foo *map;
struct foo *foo[NUM], **foop;
unsigned int i;
plan_tests(37 + NUM*2 + 19);
for (i = 0; i < NUM; i++)
foo[i] = malloc(20);
map = jmap_foo_new();
ok1(jmap_foo_error(map) == NULL);
ok1(jmap_foo_test(map, 0) == false);
ok1(jmap_foo_get(map, 0) == (struct foo *)NULL);
ok1(jmap_foo_popcount(map, 0, -1) == 0);
ok1(jmap_foo_first(map, 0) == 0);
ok1(jmap_foo_last(map, 0) == 0);
ok1(jmap_foo_del(map, 0) == false);
/* Set only works on existing cases. */
ok1(jmap_foo_set(map, 0, foo[0]) == false);
ok1(jmap_foo_add(map, 0, foo[1]) == true);
ok1(jmap_foo_get(map, 0) == foo[1]);
ok1(jmap_foo_set(map, 0, foo[0]) == true);
ok1(jmap_foo_get(map, 0) == foo[0]);
ok1(jmap_foo_test(map, 0) == true);
ok1(jmap_foo_popcount(map, 0, -1) == 1);
ok1(jmap_foo_first(map, -1) == 0);
ok1(jmap_foo_last(map, -1) == 0);
ok1(jmap_foo_next(map, 0, -1) == (size_t)-1);
ok1(jmap_foo_prev(map, 0, -1) == (size_t)-1);
ok1(jmap_foo_del(map, 0) == true);
ok1(jmap_foo_test(map, 0) == false);
ok1(jmap_foo_popcount(map, 0, -1) == 0);
for (i = 0; i < NUM; i++)
jmap_foo_add(map, i, foo[i]);
ok1(jmap_foo_popcount(map, 0, -1) == NUM);
ok1(jmap_foo_popcount(map, 0, NUM-1) == NUM);
ok1(jmap_foo_popcount(map, 0, NUM/2-1) == NUM/2);
ok1(jmap_foo_popcount(map, NUM/2, NUM) == NUM - NUM/2);
ok1(jmap_foo_nth(map, 0, -1) == 0);
ok1(jmap_foo_nth(map, NUM-1, -1) == NUM-1);
ok1(jmap_foo_nth(map, NUM, -1) == (size_t)-1);
ok1(jmap_foo_first(map, -1) == 0);
ok1(jmap_foo_last(map, -1) == NUM-1);
ok1(jmap_foo_next(map, 0, -1) == 1);
ok1(jmap_foo_next(map, NUM-1, -1) == (size_t)-1);
ok1(jmap_foo_prev(map, 1, -1) == 0);
ok1(jmap_foo_prev(map, 0, -1) == (size_t)-1);
ok1(jmap_foo_get(map, 0) == foo[0]);
ok1(jmap_foo_get(map, NUM-1) == foo[NUM-1]);
ok1(jmap_foo_get(map, NUM) == NULL);
/* Reverse values in map. */
for (i = 0; i < NUM; i++) {
foop = jmap_foo_getval(map, i);
ok1(*foop == foo[i]);
*foop = foo[NUM-1-i];
jmap_foo_putval(map, &foop);
}
for (i = 0; i < NUM; i++)
ok1(jmap_foo_get(map, i) == foo[NUM-1-i]);
foop = jmap_foo_nthval(map, 0, &i);
ok1(i == 0);
ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_nthval(map, NUM-1, &i);
ok1(i == NUM-1);
ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_firstval(map, &i);
ok1(i == 0);
ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_nextval(map, &i);
ok1(i == 1);
ok1(*foop == foo[NUM-2]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_prevval(map, &i);
ok1(i == 0);
ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_prevval(map, &i);
ok1(foop == NULL);
foop = jmap_foo_lastval(map, &i);
ok1(i == NUM-1);
ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_prevval(map, &i);
ok1(i == NUM-2);
ok1(*foop == foo[1]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_nextval(map, &i);
ok1(i == NUM-1);
ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop);
foop = jmap_foo_nextval(map, &i);
ok1(foop == NULL);
ok1(jmap_foo_error(map) == NULL);
jmap_foo_free(map);
return exit_status();
}
#include <ccan/tap/tap.h>
#define DEBUG
#include <ccan/jmap/jmap.c>
int main(int argc, char *argv[])
{
struct jmap *map;
size_t i, *value;
const char *err;
plan_tests(53);
map = jmap_new();
ok1(jmap_error(map) == NULL);
ok1(jmap_test(map, 0) == false);
ok1(jmap_del(map, 0) == false);
ok1(jmap_add(map, 0, 1) == true);
ok1(jmap_test(map, 0) == true);
ok1(jmap_get(map, 0, -1) == 1);
ok1(jmap_get(map, 1, -1) == (size_t)-1);
ok1(jmap_del(map, 0) == true);
ok1(jmap_popcount(map, 0, -1) == 0);
ok1(jmap_nth(map, 0, 0) == 0);
ok1(jmap_nth(map, 0, -1) == (size_t)-1);
ok1(jmap_first(map, 0) == 0);
ok1(jmap_first(map, -1) == (size_t)-1);
ok1(jmap_last(map, 0) == 0);
ok1(jmap_last(map, -1) == (size_t)-1);
ok1(jmap_getval(map, 0) == NULL);
/* Map a million indices, 16 apart. */
for (i = 0; i < 1000000; i++)
jmap_add(map, i << 4, (i << 5) + 1);
/* This only take 6.3MB on my 32-bit system. */
diag("%u bytes memory used\n", (unsigned)JudyLMemUsed(map->judy));
ok1(jmap_get(map, 0, -1) == 1);
ok1(jmap_get(map, 999999 << 4, -1) == (999999 << 5) + 1);
ok1(jmap_popcount(map, 0, -1) == 1000000);
ok1(jmap_nth(map, 0, -1) == 0);
ok1(jmap_nth(map, 999999, -1) == 999999 << 4);
ok1(jmap_nth(map, 1000000, -1) == (size_t)-1);
ok1(jmap_first(map, -1) == 0);
ok1(jmap_last(map, -1) == 999999 << 4);
ok1(jmap_next(map, 0, -1) == 1 << 4);
ok1(jmap_next(map, 999999 << 4, -1) == (size_t)-1);
ok1(jmap_prev(map, 1, -1) == 0);
ok1(jmap_prev(map, 0, -1) == (size_t)-1);
ok1(jmap_error(map) == NULL);
/* Accessors. */
value = jmap_getval(map, 0);
ok1(value && *value == 1);
*value = 2;
ok1(jmap_get(map, 0, -1) == 2);
jmap_putval(map, &value);
ok1(jmap_get(map, 0, -1) == 2);
ok1(jmap_set(map, 0, 1));
value = jmap_getval(map, 999999 << 4);
ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value);
value = jmap_nthval(map, 0, &i);
ok1(i == 0);
ok1(value && *value == 1);
jmap_putval(map, &value);
value = jmap_nthval(map, 999999, &i);
ok1(i == 999999 << 4);
ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value);
ok1(jmap_nthval(map, 1000000, &i) == NULL);
value = jmap_firstval(map, &i);
ok1(i == 0);
ok1(value && *value == 1);
jmap_putval(map, &value);
ok1(jmap_prevval(map, &i) == NULL);
i = 0;
value = jmap_nextval(map, &i);
ok1(i == 1 << 4);
ok1(value && *value == (1 << 5) + 1);
jmap_putval(map, &value);
value = jmap_lastval(map, &i);
ok1(i == 999999 << 4);
ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value);
ok1(jmap_nextval(map, &i) == NULL);
i = 999999 << 4;
value = jmap_prevval(map, &i);
ok1(i == 999998 << 4);
ok1(value && *value == (999998 << 5) + 1);
jmap_putval(map, &value);
/* Test error handling */
JU_ERRNO(&map->err) = 100;
JU_ERRID(&map->err) = 991;
err = jmap_error(map);
ok1(err);
ok1(strstr(err, "100"));
ok1(strstr(err, "991"));
ok1(err == map->errstr);
jmap_free(map);
return exit_status();
}
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