Commit 3a34aa1a authored by Rusty Russell's avatar Rusty Russell

jmap: use ccan/tcon and always be typesafe.

This handles both pointer and integer types using ccan/tcon.
parent 805ea067
...@@ -9,38 +9,46 @@ ...@@ -9,38 +9,46 @@
* integers or pointers as an index, Judy arrays provide an efficient * integers or pointers as an index, Judy arrays provide an efficient
* map to integers or pointers. * map to integers or pointers.
* *
* jmap.h simply contains wrappers for a size_t-indexed size_t values, and * You define a struct for your particular index and value types using
* jmap_type.h contain a wrapper macro for size_t->pointer maps and pointer * the JMAP_MEMBERS macro, then use the jmap routines to manipulate
* ->pointer maps. * the mapping.
*
* Note: if you use an integer type for the index or value types and
* your compiler doesn't support "typeof", you will get warnings about
* mixing pointers and integers.
* *
* Example: * Example:
* // Silly example of associating data with arguments by pointer and int. * // Silly example of associating data with arguments by pointer and int.
* #include <string.h> * #include <string.h>
* #include <stdio.h> * #include <stdio.h>
* #include <ccan/jmap/jmap_type.h> * #include <ccan/jmap/jmap.h>
* *
* struct opt_detail { * struct opt_detail {
* bool is_long; * bool is_long;
* unsigned int length; // == 1 if !is_long. * unsigned int length; // == 1 if !is_long.
* }; * };
* *
* // Define jmap_arg_<op> and jmap_arg, for int -> argv. * // Define map type for int -> argv.
* JMAP_DEFINE_UINTIDX_TYPE(char, arg); * struct arg_map {
* // Define jmap_opt_<op> and jmap_opt, for argv -> struct opt_detail *. * JMAP_MEMBERS(int, char *);
* JMAP_DEFINE_PTRIDX_TYPE(char, struct opt_detail, opt); * };
* // Define map type for argv -> struct opt_detail *.
* struct opt_map {
* JMAP_MEMBERS(char *, struct opt_detail *);
* };
* *
* int main(int argc, char *argv[]) * int main(int argc, char *argv[])
* { * {
* int i; * int i;
* // This map is equivalent to the argv[] array. Silly example. * // This map is equivalent to the argv[] array. Silly example.
* struct jmap_arg *arg = jmap_arg_new(); * struct arg_map *arg = jmap_new(struct arg_map);
* struct jmap_opt *opt = jmap_opt_new(); * struct opt_map *opt = jmap_new(struct opt_map);
* struct opt_detail *d; * struct opt_detail *d;
* *
* // Note: this is not correct for real parsing! * // Note: this is not correct for real parsing!
* for (i = 0; i < argc; i++) { * for (i = 1; i < argc; i++) {
* jmap_arg_add(arg, i, argv[i]); * jmap_add(arg, i, argv[i]);
* if (i < 1 || argv[i][0] != '-') * if (argv[i][0] != '-')
* continue; * continue;
* d = malloc(sizeof(*d)); * d = malloc(sizeof(*d));
* if (argv[i][1] == '-') { * if (argv[i][1] == '-') {
...@@ -52,26 +60,29 @@ ...@@ -52,26 +60,29 @@
* d->is_long = false; * d->is_long = false;
* d->length = 1; * d->length = 1;
* } * }
* jmap_opt_add(opt, argv[i], d); * jmap_add(opt, argv[i], d);
* } * }
* *
* printf("Found %lu options:\n", jmap_opt_count(opt)); * printf("Found %lu options:\n", jmap_count(opt));
* for (i = jmap_arg_first(arg,-1); i!=-1; i = jmap_arg_next(arg,i,-1)) { * for (i = jmap_first(arg); i; i = jmap_next(arg,i)) {
* char *a = jmap_arg_get(arg, i); * char *a = jmap_get(arg, i);
* d = jmap_opt_get(opt, a); * d = jmap_get(opt, a);
* printf(" Arg %i ('%s') is a %s of %u chars\n", * printf(" Arg %i ('%s') is a %s of %u chars\n",
* i, a, * i, a,
* d == NULL ? "normal argument" * d == NULL ? "normal arg"
* : d->is_long ? "long option" * : d->is_long ? "long opt"
* : "short option", * : "short opt",
* d == NULL ? strlen(a) : d->length); * d == NULL ? strlen(a) : d->length);
* // We no longer need it, so free it here. * // We no longer need it, so free it here.
* free(d); * free(d);
* } * }
* jmap_opt_free(opt); * jmap_free(opt);
* jmap_arg_free(arg); * jmap_free(arg);
* return 0; * return 0;
* } * }
* // Given "--help" output contains "Arg 1 ('--help') is a long opt of 4 chars"
* // Given "-h" output contains "Arg 1 ('-h') is a short opt of 1 chars"
* // Given "foo" output contains "Arg 1 ('foo') is a normal arg of 3 chars"
* *
* License: LGPL (v2.1 or any later version) * License: LGPL (v2.1 or any later version)
* Author: Rusty Russell <rusty@rustcorp.com.au> * Author: Rusty Russell <rusty@rustcorp.com.au>
...@@ -84,6 +95,7 @@ int main(int argc, char *argv[]) ...@@ -84,6 +95,7 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "depends") == 0) { if (strcmp(argv[1], "depends") == 0) {
printf("ccan/build_assert\n"); printf("ccan/build_assert\n");
printf("ccan/compiler\n"); printf("ccan/compiler\n");
printf("ccan/tcon\n");
printf("Judy\n"); printf("Judy\n");
return 0; return 0;
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
struct jmap *jmap_new(void) struct jmap *jmap_new_(size_t size)
{ {
struct jmap *map; struct jmap *map;
...@@ -13,7 +13,8 @@ struct jmap *jmap_new(void) ...@@ -13,7 +13,8 @@ struct jmap *jmap_new(void)
/* We also put pointers into Judy, in jmap_types.h */ /* We also put pointers into Judy, in jmap_types.h */
BUILD_ASSERT(sizeof(Word_t) >= sizeof(void *)); BUILD_ASSERT(sizeof(Word_t) >= sizeof(void *));
map = malloc(sizeof(*map)); assert(size >= sizeof(*map));
map = malloc(size);
if (map) { if (map) {
map->judy = NULL; map->judy = NULL;
memset(&map->err, 0, sizeof(map->err)); memset(&map->err, 0, sizeof(map->err));
...@@ -26,7 +27,7 @@ struct jmap *jmap_new(void) ...@@ -26,7 +27,7 @@ struct jmap *jmap_new(void)
return map; return map;
} }
const char *jmap_error_(struct jmap *map) const char *jmap_error_str_(struct jmap *map)
{ {
char *str; char *str;
free((char *)map->errstr); free((char *)map->errstr);
...@@ -40,7 +41,7 @@ const char *jmap_error_(struct jmap *map) ...@@ -40,7 +41,7 @@ const char *jmap_error_(struct jmap *map)
return str; return str;
} }
void jmap_free(const struct jmap *map) void jmap_free_(const struct jmap *map)
{ {
free((char *)map->errstr); free((char *)map->errstr);
JudyLFreeArray((PPvoid_t)&map->judy, PJE0); JudyLFreeArray((PPvoid_t)&map->judy, PJE0);
......
/* Licensed under LGPLv2.1+ - see LICENSE file for details */ /* Licensed under LGPLv2.1+ - see LICENSE file for details */
#ifndef CCAN_JMAP_H #ifndef CCAN_JMAP_H
#define CCAN_JMAP_H #define CCAN_JMAP_H
#include <ccan/compiler/compiler.h>
#include <ccan/tcon/tcon.h>
#include <stddef.h> #include <stddef.h>
#include <Judy.h> #include <Judy.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <ccan/compiler/compiler.h>
#include <assert.h> #include <assert.h>
#ifdef CCAN_JMAP_DEBUG #ifdef CCAN_JMAP_DEBUG
#include <stdio.h> #include <stdio.h>
#endif #endif
/** /**
* jmap_new - create a new, empty jmap. * struct map - private definition of a 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: * It's exposed here so you can put it in your structures and so we can
* jmap_free(map); * supply inline functions.
*/ */
void jmap_free(const struct jmap *map);
/* This is exposed in the header so we can inline. Treat it as private! */
struct jmap { struct jmap {
Pvoid_t judy; Pvoid_t judy;
JError_t err; JError_t err;
...@@ -45,47 +29,46 @@ struct jmap { ...@@ -45,47 +29,46 @@ struct jmap {
unsigned long acc_index; unsigned long acc_index;
const char *funcname; const char *funcname;
}; };
const char *COLD jmap_error_(struct jmap *map);
/* Debugging checks. */ /**
static inline void jmap_debug_add_access(const struct jmap *map, * JMAP_MEMBERS - declare members for a type-specific jmap.
unsigned long index, * @itype: index type for this map, or void * for any pointer.
unsigned long *val, * @ctype: contents type for this map, or void * for any pointer.
const char *funcname) *
{ * Example:
#ifdef CCAN_JMAP_DEBUG * struct jmap_long_to_charp {
if (!map->acc_value) { * JMAP_MEMBERS(long, char *);
((struct jmap *)map)->acc_value = val; * };
((struct jmap *)map)->acc_index = index; */
((struct jmap *)map)->funcname = funcname; #define JMAP_MEMBERS(itype, ctype) \
} struct jmap raw; \
#endif TCON(itype icanary; ctype ccanary)
if (val)
assert(++((struct jmap *)map)->num_accesses);
}
static inline void jmap_debug_del_access(struct jmap *map, unsigned long **val) /**
{ * jmap_new - create a new, empty jmap.
assert(--map->num_accesses >= 0); *
#ifdef CCAN_JMAP_DEBUG * See Also:
if (map->acc_value == *val) * JMAP_MEMBERS()
map->acc_value = NULL; *
#endif * Example:
/* Set it to some invalid value. Not NULL, they might rely on that! */ * struct jmap_long_to_charp {
assert(memset(val, 0x42, sizeof(*val))); * JMAP_MEMBERS(long, char *);
} * };
*
* struct jmap_long_to_charp *map = jmap_new(struct jmap_long_to_charp);
* if (!map)
* errx(1, "Failed to allocate jmap");
*/
#define jmap_new(type) ((type *)jmap_new_(sizeof(type)))
static inline void jmap_debug_access(struct jmap *map) /**
{ * jmap_free - destroy a jmap.
#ifdef CCAN_JMAP_DEBUG * @map: the map returned from jmap_new.
if (map->num_accesses && map->acc_value) *
fprintf(stderr, * Example:
"jmap: still got index %lu, val %lu (%p) from %s\n", * jmap_free(map);
map->acc_index, *map->acc_value, map->acc_value, */
map->funcname); #define jmap_free(map) jmap_free_(&(map)->raw)
#endif
assert(!map->num_accesses);
}
/** /**
* jmap_error - test for an error in the a previous jmap_ operation. * jmap_error - test for an error in the a previous jmap_ operation.
...@@ -99,21 +82,48 @@ static inline void jmap_debug_access(struct jmap *map) ...@@ -99,21 +82,48 @@ static inline void jmap_debug_access(struct jmap *map)
* interface misuse. * interface misuse.
* *
* Example: * Example:
* struct jmap *map = jmap_new();
* const char *errstr; * const char *errstr;
* *
* if (!map)
* err(1, "allocating jmap");
* errstr = jmap_error(map); * errstr = jmap_error(map);
* if (errstr) * if (errstr)
* errx(1, "Woah, error on newly created map?! %s", errstr); * errx(1, "Woah, error on newly created map?! %s", errstr);
*/ */
static inline const char *jmap_error(struct jmap *map) #define jmap_error(map) jmap_error_(&(map)->raw)
{
if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX) /**
return NULL; * jmap_rawi - unwrap the typed map and check the index type
return jmap_error_(map); * @map: the typed jmap
} * @expr: the expression to check the index type against (not evaluated)
*
* This macro usually causes the compiler to emit a warning if the
* variable is of an unexpected type. It is used internally where we
* need to access the raw underlying jmap.
*/
#define jmap_rawi(map, expr) (&tcon_check((map), icanary, (expr))->raw)
/**
* jmap_rawc - unwrap the typed map and check the contents type
* @map: the typed jmap
* @expr: the expression to check the content type against (not evaluated)
*
* This macro usually causes the compiler to emit a warning if the
* variable is of an unexpected type. It is used internally where we
* need to access the raw underlying jmap.
*/
#define jmap_rawc(map, expr) (&tcon_check((map), ccanary, (expr))->raw)
/**
* jmap_rawci - unwrap the typed map and check the index and contents types
* @map: the typed jmap
* @iexpr: the expression to check the index type against (not evaluated)
* @cexpr: the expression to check the contents type against (not evaluated)
*
* This macro usually causes the compiler to emit a warning if the
* variable is of an unexpected type. It is used internally where we
* need to access the raw underlying jmap.
*/
#define jmap_rawci(map, iexpr, cexpr) \
(&tcon_check(tcon_check((map), ccanary, (cexpr)), icanary, (iexpr))->raw)
/** /**
* jmap_add - add or replace a value for a given index in the map. * jmap_add - add or replace a value for a given index in the map.
...@@ -125,20 +135,12 @@ static inline const char *jmap_error(struct jmap *map) ...@@ -125,20 +135,12 @@ static inline const char *jmap_error(struct jmap *map)
* Returns false on error (out of memory). * Returns false on error (out of memory).
* *
* Example: * Example:
* if (!jmap_add(map, 0, 1)) * if (!jmap_add(map, 0, "hello"))
* err(1, "jmap_add failed!"); * err(1, "jmap_add failed!");
*/ */
static inline bool jmap_add(struct jmap *map, #define jmap_add(map, index, value) \
unsigned long index, unsigned long value) jmap_add_(jmap_rawci((map), (index), (value)), \
{ (unsigned long)(index), (unsigned long)value)
unsigned long *val;
jmap_debug_access(map);
val = (unsigned long *)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. * jmap_set - change a value for an existing index in the map.
...@@ -150,21 +152,12 @@ static inline bool jmap_add(struct jmap *map, ...@@ -150,21 +152,12 @@ static inline bool jmap_add(struct jmap *map,
* otherwise returns false and does nothing. * otherwise returns false and does nothing.
* *
* Example: * Example:
* if (!jmap_set(map, 0, 2)) * if (!jmap_set(map, 0, "goodbye"))
* err(1, "jmap_set: index 0 not found"); * err(1, "jmap_set: index 0 not found");
*/ */
static inline bool jmap_set(const struct jmap *map, #define jmap_set(map, index, value) \
unsigned long index, unsigned long value) jmap_set_(jmap_rawci((map), (index), (value)), \
{ (unsigned long)(index), (unsigned long)value)
unsigned long *val;
val = (unsigned long *)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. * jmap_del - remove an index from the map.
...@@ -175,11 +168,8 @@ static inline bool jmap_set(const struct jmap *map, ...@@ -175,11 +168,8 @@ static inline bool jmap_set(const struct jmap *map,
* if (!jmap_del(map, 0)) * if (!jmap_del(map, 0))
* err(1, "jmap_del failed!"); * err(1, "jmap_del failed!");
*/ */
static inline bool jmap_del(struct jmap *map, unsigned long index) #define jmap_del(map, index) \
{ jmap_del_(jmap_rawi((map), (index)), (unsigned long)(index))
jmap_debug_access(map);
return JudyLDel(&map->judy, index, &map->err) == 1;
}
/** /**
* jmap_test - test if a given index is defined. * jmap_test - test if a given index is defined.
...@@ -187,38 +177,40 @@ static inline bool jmap_del(struct jmap *map, unsigned long index) ...@@ -187,38 +177,40 @@ static inline bool jmap_del(struct jmap *map, unsigned long index)
* @index: the index to find * @index: the index to find
* *
* Example: * Example:
* jmap_add(map, 0, 1); * jmap_add(map, 1, "hello");
* assert(jmap_test(map, 0)); * assert(jmap_test(map, 1));
*/ */
static inline bool jmap_test(const struct jmap *map, unsigned long index) #define jmap_test(map, index) \
{ jmap_test_(jmap_rawi((map), (index)), (unsigned long)(index))
return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
}
/** /**
* jmap_get - get a value for a given index. * jmap_get - get a value for a given index.
* @map: map from jmap_new * @map: map from jmap_new
* @index: the index to find * @index: the index to find
* @invalid: the value to return if the index isn't found. *
* Returns 0 if !jmap_test(map, index).
* *
* Example: * Example:
* jmap_add(map, 0, 1); * const char *str = "hello";
* assert(jmap_get(map, 0, -1) == 1); * jmap_add(map, 2, str);
* assert(jmap_get(map, 0) == str);
* *
* See Also: * See Also:
* jmap_getval() * jmap_getval()
*/ */
static inline unsigned long jmap_get(const struct jmap *map, #define jmap_get(map, index) \
unsigned long index, tcon_cast((map), ccanary, \
unsigned long invalid) jmap_get_(jmap_rawi((map), (index)), (unsigned long)(index)))
{
unsigned long *val; /**
val = (unsigned long *)JudyLGet(map->judy, index, * jmap_count - get population of the map.
(JError_t *)&map->err); * @map: map from jmap_new
if (!val || val == PJERR) *
return invalid; * Example:
return *val; * assert(jmap_count(map) < 1000);
} */
#define jmap_count(map) \
jmap_popcount_(&(map)->raw, 0, -1UL)
/** /**
* jmap_popcount - get population of (some part of) the map. * jmap_popcount - get population of (some part of) the map.
...@@ -229,12 +221,9 @@ static inline unsigned long jmap_get(const struct jmap *map, ...@@ -229,12 +221,9 @@ static inline unsigned long jmap_get(const struct jmap *map,
* Example: * Example:
* assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000)); * assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
*/ */
static inline unsigned long jmap_popcount(const struct jmap *map, #define jmap_popcount(map, start, end_incl) \
unsigned long start, jmap_popcount_(jmap_rawi((map), (start) ? (start) : (end_incl)), \
unsigned long end_incl) (unsigned long)(start), (unsigned long)(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. * jmap_nth - return the index of the nth value in the map.
...@@ -259,109 +248,74 @@ static inline unsigned long jmap_popcount(const struct jmap *map, ...@@ -259,109 +248,74 @@ static inline unsigned long jmap_popcount(const struct jmap *map,
* See Also: * See Also:
* jmap_nthval(); * jmap_nthval();
*/ */
static inline unsigned long jmap_nth(const struct jmap *map, #define jmap_nth(map, n, invalid) \
unsigned long n, unsigned long invalid) tcon_cast((map), icanary, \
{ jmap_nth_(jmap_rawi((map), (invalid)), \
unsigned long index; (n), (unsigned long)(invalid)))
if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
index = invalid;
return index;
}
/** /**
* jmap_first - return the first index in the map. * jmap_first - return the first index in the map (must not contain 0).
* @map: map from jmap_new * @map: map from jmap_new
* @invalid: return value if jmap is empty.
* *
* This is equivalent to jmap_nth(map, 0, invalid). * This is equivalent to jmap_nth(map, 0, 0).
* *
* Example: * Example:
* assert(!jmap_test(map, 0)); * assert(!jmap_test(map, 0));
* printf("Map indices (increasing order):"); * printf("Map indices (increasing order):");
* for (i = jmap_first(map, 0); i; i = jmap_next(map, i, 0)) * for (i = jmap_first(map); i; i = jmap_next(map, i))
* printf(" %lu", i); * printf(" %lu", i);
* printf("\n"); * printf("\n");
* *
* See Also: * See Also:
* jmap_firstval() * jmap_firstval()
*/ */
static inline unsigned long jmap_first(const struct jmap *map, #define jmap_first(map) \
unsigned long invalid) tcon_cast((map), icanary, jmap_first_(&(map)->raw))
{
unsigned long 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. * jmap_next - return the next index in the map.
* @map: map from jmap_new * @map: map from jmap_new
* @prev: previous index * @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. * This is usually used to find an adjacent index after jmap_first.
* See Also: * See Also:
* jmap_nextval() * jmap_nextval()
*/ */
static inline unsigned long jmap_next(const struct jmap *map, #define jmap_next(map, prev) \
unsigned long prev, tcon_cast((map), icanary, jmap_next_(jmap_rawi((map), (prev)), \
unsigned long invalid) (unsigned long)(prev)))
{
if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/** /**
* jmap_last - return the last index in the map. * jmap_last - return the last index in the map.
* @map: map from jmap_new * @map: map from jmap_new
* @invalid: return value if map is empty. *
* Returns 0 if map is empty.
* *
* Example: * Example:
* assert(!jmap_test(map, 0)); * assert(!jmap_test(map, 0));
* printf("Map indices (increasing order):"); * printf("Map indices (increasing order):");
* for (i = jmap_last(map, 0); i; i = jmap_prev(map, i, 0)) * for (i = jmap_last(map); i; i = jmap_prev(map, i))
* printf(" %lu", i); * printf(" %lu", i);
* printf("\n"); * printf("\n");
* See Also: * See Also:
* jmap_lastval() * jmap_lastval()
*/ */
static inline unsigned long jmap_last(const struct jmap *map, #define jmap_last(map) \
unsigned long invalid) tcon_cast((map), icanary, jmap_last_(&(map)->raw))
{
unsigned long 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. * jmap_prev - return the previous index in the map (must not contain 0)
* @map: map from jmap_new * @map: map from jmap_new
* @prev: previous index * @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. * This is usually used to find an prior adjacent index after jmap_last.
* Returns 0 if no previous indices in map.
*
* See Also: * See Also:
* jmap_prevval() * jmap_prevval()
*/ */
static inline unsigned long jmap_prev(const struct jmap *map, #define jmap_prev(map, prev) \
unsigned long prev, tcon_cast((map), icanary, jmap_prev_(jmap_rawi((map), (prev)), (prev)))
unsigned long invalid)
{
if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
prev = invalid;
else
assert(prev != invalid);
return prev;
}
/** /**
* jmap_getval - access a value in-place for a given index. * jmap_getval - access a value in-place for a given index.
...@@ -377,28 +331,24 @@ static inline unsigned long jmap_prev(const struct jmap *map, ...@@ -377,28 +331,24 @@ static inline unsigned long jmap_prev(const struct jmap *map,
* have called jmap_putval(). * have called jmap_putval().
* *
* Example: * Example:
* unsigned long *p; * char **p;
* jmap_add(map, 0, 1); * jmap_add(map, 0, "hello");
* p = jmap_getval(map, 0); * p = jmap_getval(map, 0);
* if (!p) * if (!p)
* errx(1, "Could not find 0 in map!"); * errx(1, "Could not find 0 in map!");
* if (*p != 1) * if (strcmp(*p, "hello") != 0)
* errx(1, "Value in map was not 0?!"); * errx(1, "Value in map was not correct?!");
* *p = 7; * *p = (char *)"goodbye";
* jmap_putval(map, &p); * jmap_putval(map, &p);
* // Accessing p now would probably crash. * // Accessing p now would probably crash.
* *
* See Also: * See Also:
* jmap_putval(), jmap_firstval() * jmap_putval(), jmap_firstval()
*/ */
static inline unsigned long *jmap_getval(struct jmap *map, unsigned long index) #define jmap_getval(map, index) \
{ tcon_cast_ptr((map), ccanary, \
unsigned long *val; jmap_getval_(jmap_rawi((map), (index)), \
val = (unsigned long *)JudyLGet(map->judy, index, (unsigned long)(index)))
(JError_t *)&map->err);
jmap_debug_add_access(map, index, val, "jmap_getval");
return val;
}
/** /**
* jmap_putval - revoke access to a value. * jmap_putval - revoke access to a value.
...@@ -415,43 +365,36 @@ static inline unsigned long *jmap_getval(struct jmap *map, unsigned long index) ...@@ -415,43 +365,36 @@ static inline unsigned long *jmap_getval(struct jmap *map, unsigned long index)
* jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(), * jmap_getval(), jmap_nthval(), jmap_firstval(), jmap_nextval(),
* jmap_lastval(), jmap_prevval(). * jmap_lastval(), jmap_prevval().
*/ */
static inline void jmap_putval(struct jmap *map, unsigned long **p) #define jmap_putval(map, p) \
{ jmap_putval_(jmap_rawc((map), **(p)), (p))
jmap_debug_del_access(map, p);
}
/** /**
* jmap_nthval - access the value of the nth value in the map. * jmap_nthval - access the value of the nth value in the map.
* @map: map from jmap_new * @map: map from jmap_new
* @n: which index we are interested in (0-based) * @n: which index we are interested in (0-based)
* @index: set to the nth index in the map.
* *
* This returns a pointer to the value at the nth index in the map, * 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. * 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. * You must use jmap_putval() on the pointer once you are done with it.
* *
* Example: * Example:
* unsigned long *val; * char **val;
* *
* // We know 0 isn't in map. * // We know 0 isn't in map.
* assert(!jmap_test(map, 0)); * assert(!jmap_test(map, 0));
* for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) { * for (i = 0; (val = jmap_nthval(map, i, &index)) != NULL; i++) {
* assert(jmap_popcount(map, 0, index) == i); * assert(jmap_popcount(map, 0, index) == i);
* printf("Index %lu = %lu, value = %lu\n", i, index, *val); * printf("Index %lu = %lu, value = %s\n", i, index, *val);
* jmap_putval(map, &val); * jmap_putval(map, &val);
* } * }
* *
* See Also: * See Also:
* jmap_nth(); * jmap_nth();
*/ */
static inline unsigned long *jmap_nthval(const struct jmap *map, #define jmap_nthval(map, n, index) \
unsigned long n, unsigned long *index) tcon_cast_ptr((map), ccanary, \
{ jmap_nthval_(jmap_rawi((map), *(index)), (n), (index)))
unsigned long *val;
val = (unsigned long *)JudyLByCount(map->judy, n+1, 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. * jmap_firstval - access the first value in the map.
...@@ -462,7 +405,7 @@ static inline unsigned long *jmap_nthval(const struct jmap *map, ...@@ -462,7 +405,7 @@ static inline unsigned long *jmap_nthval(const struct jmap *map,
* the first value, which you must call jmap_putval() on! * the first value, which you must call jmap_putval() on!
* *
* Example: * Example:
* // Add one to every value. * // Add one to every value (ie. make it point into second char of string)
* for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) { * for (val = jmap_firstval(map, &i); val; val = jmap_nextval(map, &i)) {
* (*val)++; * (*val)++;
* jmap_putval(map, &val); * jmap_putval(map, &val);
...@@ -472,16 +415,10 @@ static inline unsigned long *jmap_nthval(const struct jmap *map, ...@@ -472,16 +415,10 @@ static inline unsigned long *jmap_nthval(const struct jmap *map,
* See Also: * See Also:
* jmap_first, jmap_nextval() * jmap_first, jmap_nextval()
*/ */
static inline unsigned long *jmap_firstval(const struct jmap *map, #define jmap_firstval(map, index) \
unsigned long *index) tcon_cast_ptr((map), ccanary, \
{ jmap_firstval_(jmap_rawi((map), *(index)), \
unsigned long *val; (unsigned long *)(index)))
*index = 0;
val = (unsigned long *)JudyLFirst(map->judy, 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. * jmap_nextval - access the next value in the map.
...@@ -494,15 +431,11 @@ static inline unsigned long *jmap_firstval(const struct jmap *map, ...@@ -494,15 +431,11 @@ static inline unsigned long *jmap_firstval(const struct jmap *map,
* See Also: * See Also:
* jmap_firstval(), jmap_putval() * jmap_firstval(), jmap_putval()
*/ */
static inline unsigned long *jmap_nextval(const struct jmap *map, #define jmap_nextval(map, index) \
unsigned long *index) tcon_cast_ptr((map), ccanary, \
{ jmap_nextval_(jmap_rawi((map), *(index)), \
unsigned long *val; (unsigned long *)(index)))
val = (unsigned long *)JudyLNext(map->judy, 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. * jmap_lastval - access the last value in the map.
...@@ -512,16 +445,11 @@ static inline unsigned long *jmap_nextval(const struct jmap *map, ...@@ -512,16 +445,11 @@ static inline unsigned long *jmap_nextval(const struct jmap *map,
* See Also: * See Also:
* jmap_last(), jmap_putval() * jmap_last(), jmap_putval()
*/ */
static inline unsigned long *jmap_lastval(const struct jmap *map, #define jmap_lastval(map, index) \
unsigned long *index) tcon_cast_ptr((map), ccanary, \
{ jmap_lastval_(jmap_rawi((map), *(index)), \
unsigned long *val; (unsigned long *)(index)))
*index = -1;
val = (unsigned long *)JudyLLast(map->judy, 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. * jmap_prevval - access the previous value in the map.
...@@ -534,7 +462,206 @@ static inline unsigned long *jmap_lastval(const struct jmap *map, ...@@ -534,7 +462,206 @@ static inline unsigned long *jmap_lastval(const struct jmap *map,
* See Also: * See Also:
* jmap_lastval(), jmap_putval() * jmap_lastval(), jmap_putval()
*/ */
static inline unsigned long *jmap_prevval(const struct jmap *map, #define jmap_prevval(map, index) \
tcon_cast_ptr((map), ccanary, \
jmap_prevval_(jmap_rawi((map), *(index)), \
(unsigned long *)(index)))
/* Debugging checks. */
static inline void jmap_debug_add_access(const struct jmap *map,
unsigned long index,
unsigned long *val,
const char *funcname)
{
#ifdef CCAN_JMAP_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, unsigned long **val)
{
assert(--map->num_accesses >= 0);
#ifdef CCAN_JMAP_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(memset(val, 0x42, sizeof(void *)));
}
static inline void jmap_debug_access(struct jmap *map)
{
#ifdef CCAN_JMAP_DEBUG
if (map->num_accesses && map->acc_value)
fprintf(stderr,
"jmap: still got index %lu, val %lu (%p) from %s\n",
map->acc_index, *map->acc_value, map->acc_value,
map->funcname);
#endif
assert(!map->num_accesses);
}
/* Private functions */
struct jmap *jmap_new_(size_t size);
void jmap_free_(const struct jmap *map);
const char *COLD jmap_error_str_(struct jmap *map);
static inline const char *jmap_error_(struct jmap *map)
{
if (JU_ERRNO(&map->err) <= JU_ERRNO_NFMAX)
return NULL;
return jmap_error_str_(map);
}
static inline bool jmap_add_(struct jmap *map,
unsigned long index, unsigned long value)
{
unsigned long *val;
jmap_debug_access(map);
val = (unsigned long *)JudyLIns(&map->judy, index, &map->err);
if (val == PJERR)
return false;
*val = value;
return true;
}
static inline bool jmap_set_(const struct jmap *map,
unsigned long index, unsigned long value)
{
unsigned long *val;
val = (unsigned long *)JudyLGet(map->judy, index,
(JError_t *)&map->err);
if (val && val != PJERR) {
*val = value;
return true;
}
return false;
}
static inline bool jmap_del_(struct jmap *map, unsigned long index)
{
jmap_debug_access(map);
return JudyLDel(&map->judy, index, &map->err) == 1;
}
static inline bool jmap_test_(const struct jmap *map, unsigned long index)
{
return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
}
static inline unsigned long jmap_get_(const struct jmap *map,
unsigned long index)
{
unsigned long *val;
val = (unsigned long *)JudyLGet(map->judy, index,
(JError_t *)&map->err);
if (!val || val == PJERR)
return 0;
return *val;
}
static inline unsigned long jmap_popcount_(const struct jmap *map,
unsigned long start,
unsigned long end_incl)
{
return JudyLCount(map->judy, start, end_incl, (JError_t *)&map->err);
}
static inline unsigned long jmap_nth_(const struct jmap *map,
unsigned long n, unsigned long invalid)
{
unsigned long index;
if (!JudyLByCount(map->judy, n+1, &index, (JError_t *)&map->err))
index = invalid;
return index;
}
static inline unsigned long jmap_first_(const struct jmap *map)
{
unsigned long index = 0;
if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
index = 0;
else
assert(index != 0);
return index;
}
static inline unsigned long jmap_next_(const struct jmap *map,
unsigned long prev)
{
if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
prev = 0;
else
assert(prev != 0);
return prev;
}
static inline unsigned long jmap_last_(const struct jmap *map)
{
unsigned long index = -1;
if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
index = 0;
else
assert(index != 0);
return index;
}
static inline unsigned long jmap_prev_(const struct jmap *map,
unsigned long prev)
{
if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
prev = 0;
else
assert(prev != 0);
return prev;
}
static inline void *jmap_getval_(struct jmap *map, unsigned long index)
{
unsigned long *val;
val = (unsigned long *)JudyLGet(map->judy, index,
(JError_t *)&map->err);
jmap_debug_add_access(map, index, val, "jmap_getval");
return val;
}
static inline void jmap_putval_(struct jmap *map, void *p)
{
jmap_debug_del_access(map, p);
}
static inline unsigned long *jmap_nthval_(const struct jmap *map, unsigned long n,
unsigned long *index)
{
unsigned long *val;
val = (unsigned long *)JudyLByCount(map->judy, n+1, index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_nthval");
return val;
}
static inline unsigned long *jmap_firstval_(const struct jmap *map,
unsigned long *index)
{
unsigned long *val;
*index = 0;
val = (unsigned long *)JudyLFirst(map->judy, index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_firstval");
return val;
}
static inline unsigned long *jmap_nextval_(const struct jmap *map,
unsigned long *index)
{
unsigned long *val;
val = (unsigned long *)JudyLNext(map->judy, index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_nextval");
return val;
}
static inline unsigned long *jmap_lastval_(const struct jmap *map,
unsigned long *index)
{
unsigned long *val;
*index = -1;
val = (unsigned long *)JudyLLast(map->judy, index,
(JError_t *)&map->err);
jmap_debug_add_access(map, *index, val, "jmap_lastval");
return val;
}
static inline unsigned long *jmap_prevval_(const struct jmap *map,
unsigned long *index) unsigned long *index)
{ {
unsigned long *val; unsigned long *val;
......
/* Licensed under LGPLv2.1+ - see LICENSE file for details */
#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:
*
* // Creating, errors and freeing.
* 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);
*
* // Add, set, delete, test and get.
* bool jmap_@name_add(struct jmap_@name *map,
* unsigned long idx, const type *value);
* bool jmap_@name_set(const struct jmap_@name *map,
* unsigned long idx, const type *value);
* bool jmap_@name_del(struct jmap_@name *map, unsigned long idx);
* bool jmap_@name_test(const struct jmap_@name *map, unsigned long idx);
* type *jmap_@name_get(const struct jmap_@name *map, unsigned long idx);
*
* // Counting and iteration.
* unsigned long jmap_@name_popcount(const struct jmap_@name *map,
* unsigned long start,
* unsigned long end_incl);
* unsigned long jmap_@name_nth(const struct jmap_@name *map,
* unsigned long n, unsigned long invalid);
* unsigned long jmap_@name_first(const struct jmap_@name *map,
* unsigned long invalid);
* unsigned long jmap_@name_next(const struct jmap_@name *map,
* unsigned long prev,
* unsigned long invalid);
* unsigned long jmap_@name_last(const struct jmap_@name *map,
* unsigned long invalid);
* unsigned long jmap_@name_prev(const struct jmap_@name *map,
* unsigned long prev,
* unsigned long invalid);
*
* // Get pointers to values to use.
* type **jmap_@name_getval(const struct jmap_@name *map,
* unsigned long idx);
* void jmap_@name_putval(struct jmap_@name *map, type ***p);
* type **jmap_@name_nthval(struct jmap_@name *map,
* unsigned long n, unsigned long *idx);
* type **jmap_@name_firstval(const struct jmap_@name *map,
* unsigned long *idx);
* type **jmap_@name_nextval(const struct jmap_@name *map,
* unsigned long *idx);
* type **jmap_@name_lastval(const struct jmap_@name *map,
* unsigned long *idx);
* type **jmap_@name_prevval(const struct jmap_@name *map,
* unsigned long *idx);
*/
#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, \
unsigned long idx, const type *value) \
{ \
return jmap_add((struct jmap *)map, idx, (unsigned long)value); \
} \
static inline bool jmap_##name##_set(const struct jmap_##name *map, \
unsigned long idx, const type *value) \
{ \
return jmap_set((const struct jmap *)map, idx, (unsigned long)value); \
} \
static inline bool jmap_##name##_del(struct jmap_##name *map, \
unsigned long idx) \
{ \
return jmap_del((struct jmap *)map, idx); \
} \
static inline bool jmap_##name##_test(const struct jmap_##name *map, \
unsigned long idx) \
{ \
return jmap_test((const struct jmap *)map, (unsigned long)idx); \
} \
static inline type *jmap_##name##_get(const struct jmap_##name *map, \
unsigned long idx) \
{ \
return (type *)jmap_get((const struct jmap *)map, idx, 0); \
} \
static inline unsigned long \
jmap_##name##_popcount(const struct jmap_##name *map, \
unsigned long start, unsigned long end_incl) \
{ \
return jmap_popcount((const struct jmap *)map, start, end_incl); \
} \
static inline unsigned long jmap_##name##_nth(const struct jmap_##name *map, \
unsigned long n, \
unsigned long invalid) \
{ \
return jmap_nth((const struct jmap *)map, n, invalid); \
} \
static inline unsigned long \
jmap_##name##_first(const struct jmap_##name *map, \
unsigned long invalid) \
{ \
return jmap_first((const struct jmap *)map, invalid); \
} \
static inline unsigned long \
jmap_##name##_next(const struct jmap_##name *map, \
unsigned long prev, unsigned long invalid) \
{ \
return jmap_next((const struct jmap *)map, prev, invalid); \
} \
static inline unsigned long \
jmap_##name##_last(const struct jmap_##name *map, \
unsigned long invalid) \
{ \
return jmap_last((const struct jmap *)map, invalid); \
} \
static inline unsigned long \
jmap_##name##_prev(const struct jmap_##name *map, \
unsigned long prev, unsigned long invalid) \
{ \
return jmap_prev((const struct jmap *)map, prev, invalid); \
} \
static inline type **jmap_##name##_getval(const struct jmap_##name *map, \
unsigned long idx) \
{ \
return (type **)jmap_getval((struct jmap *)map, idx); \
} \
static inline void jmap_##name##_putval(struct jmap_##name *map, \
type ***p) \
{ \
return jmap_putval((struct jmap *)map, (unsigned long **)p); \
} \
static inline type **jmap_##name##_nthval(struct jmap_##name *map, \
unsigned long n, \
unsigned long *idx) \
{ \
return (type **)jmap_nthval((struct jmap *)map, n, idx); \
} \
static inline type **jmap_##name##_firstval(const struct jmap_##name *map, \
unsigned long *idx) \
{ \
return (type **)jmap_firstval((const struct jmap *)map, idx); \
} \
static inline type **jmap_##name##_nextval(const struct jmap_##name *map, \
unsigned long *idx) \
{ \
return (type **)jmap_nextval((const struct jmap *)map, idx); \
} \
static inline type **jmap_##name##_lastval(const struct jmap_##name *map, \
unsigned long *idx) \
{ \
return (type **)jmap_lastval((const struct jmap *)map, idx); \
} \
static inline type **jmap_##name##_prevval(const struct jmap_##name *map, \
unsigned long *idx) \
{ \
return (type **)jmap_prevval((const struct jmap *)map, idx); \
}
/**
* JMAP_DEFINE_PTRIDX_TYPE - create a map of jmap ops for ptr->ptr map
* @itype: a type whose pointers will idx 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-idxed Judy map of pointers. It is
* assumed that a NULL pointer is never an idx in the map, as
* various functions return NULL for "invalid idx". Similarly,
* jmap_@name_get will return NULL if an idx isn't valid, so NULL indices
* are not recommended (though you can tell using jmap_@name_test).
*
* Since the ordering is by idx 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 *idx, const type *value);
* bool jmap_@name_set(const struct jmap_@name *map,
* const itype *idx, const type *value);
* bool jmap_@name_del(struct jmap_@name *map, const itype *idx);
* bool jmap_@name_test(const struct jmap_@name *map, const itype *idx);
*
* type *jmap_@name_get(const struct jmap_@name *map, const itype *idx);
* 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 *idx);
* void jmap_@name_putval(struct jmap_@name *map, type ***p);
* type **jmap_@name_firstval(const struct jmap_@name *map,
* const itype **idx);
* type **jmap_@name_nextval(const struct jmap_@name *map,
* const itype **idx);
*/
#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 *idx, const type *value) \
{ \
return jmap_add((struct jmap *)map, (unsigned long)idx, \
(unsigned long)value); \
} \
static inline bool jmap_##name##_set(const struct jmap_##name *map, \
const itype *idx, const type *value) \
{ \
return jmap_set((const struct jmap *)map, (unsigned long)idx, \
(unsigned long)value); \
} \
static inline bool jmap_##name##_del(struct jmap_##name *map, \
const itype *idx) \
{ \
return jmap_del((struct jmap *)map, (unsigned long)idx); \
} \
static inline bool jmap_##name##_test(const struct jmap_##name *map, \
const itype *idx) \
{ \
return jmap_test((const struct jmap *)map, (unsigned long)idx); \
} \
static inline type *jmap_##name##_get(const struct jmap_##name *map, \
const itype *idx) \
{ \
return (type *)jmap_get((const struct jmap *)map, \
(unsigned long)idx, 0); \
} \
static inline unsigned long \
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, \
(unsigned long)prev, 0); \
} \
static inline type **jmap_##name##_getval(const struct jmap_##name *map, \
const itype *idx) \
{ \
return (type **)jmap_getval((struct jmap *)map, \
(unsigned long)idx); \
} \
static inline void jmap_##name##_putval(struct jmap_##name *map, \
type ***p) \
{ \
return jmap_putval((struct jmap *)map, (unsigned long **)p); \
} \
static inline type **jmap_##name##_firstval(const struct jmap_##name *map, \
itype **idx) \
{ \
unsigned long i; \
type **ret; \
ret = (type **)jmap_firstval((const struct jmap *)map, &i); \
*idx = (void *)i; \
return ret; \
} \
static inline type **jmap_##name##_nextval(const struct jmap_##name *map, \
itype **idx) \
{ \
return (type **)jmap_nextval((const struct jmap *)map, \
(unsigned long *)idx); \
}
#endif /* CCAN_JMAP_TYPE_H */
...@@ -5,15 +5,19 @@ ...@@ -5,15 +5,19 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
struct map {
JMAP_MEMBERS(unsigned long, unsigned long);
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct jmap *map; struct map *map;
unsigned long *value; unsigned long *value;
int status; int status;
plan_tests(9); plan_tests(9);
map = jmap_new(); map = jmap_new(struct map);
ok1(jmap_error(map) == NULL); ok1(jmap_error(map) == NULL);
ok1(jmap_add(map, 0, 1)); ok1(jmap_add(map, 0, 1));
......
#include <ccan/tap/tap.h>
#include <ccan/jmap/jmap.c>
struct idx;
struct map {
JMAP_MEMBERS(struct idx *, int);
};
#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 map *map;
struct idx *idx[NUM+1], *index;
unsigned int i;
int *intp;
plan_tests(25 + NUM*2 + 6);
for (i = 0; i < NUM+1; i++)
idx[i] = malloc(20);
qsort(idx, NUM, sizeof(idx[0]), cmp_ptr);
map = jmap_new(struct map);
ok1(jmap_error(map) == NULL);
ok1(jmap_test(map, idx[NUM]) == false);
ok1(jmap_get(map, idx[NUM]) == 0);
ok1(jmap_count(map) == 0);
ok1(jmap_first(map) == 0);
ok1(jmap_del(map, idx[0]) == false);
/* Set only works on existing cases. */
ok1(jmap_set(map, idx[0], 0) == false);
ok1(jmap_add(map, idx[0], 1) == true);
ok1(jmap_get(map, idx[0]) == 1);
ok1(jmap_set(map, idx[0], -1) == true);
ok1(jmap_get(map, idx[0]) == -1);
ok1(jmap_test(map, idx[0]) == true);
ok1(jmap_count(map) == 1);
ok1(jmap_first(map) == idx[0]);
ok1(jmap_next(map, idx[0]) == NULL);
ok1(jmap_del(map, idx[0]) == true);
ok1(jmap_test(map, idx[0]) == false);
ok1(jmap_count(map) == 0);
for (i = 0; i < NUM; i++)
jmap_add(map, idx[i], i+1);
ok1(jmap_count(map) == NUM);
ok1(jmap_first(map) == idx[0]);
ok1(jmap_next(map, idx[0]) == idx[1]);
ok1(jmap_next(map, idx[NUM-1]) == NULL);
ok1(jmap_get(map, idx[0]) == 1);
ok1(jmap_get(map, idx[NUM-1]) == NUM);
ok1(jmap_get(map, (void *)((char *)idx[NUM-1] + 1)) == 0);
/* Reverse values in map. */
for (i = 0; i < NUM; i++) {
intp = jmap_getval(map, idx[i]);
ok1(*intp == i+1);
*intp = NUM-i;
jmap_putval(map, &intp);
}
for (i = 0; i < NUM; i++)
ok1(jmap_get(map, idx[i]) == NUM-i);
intp = jmap_firstval(map, &index);
ok1(index == idx[0]);
ok1(*intp == NUM);
jmap_putval(map, &intp);
intp = jmap_nextval(map, &index);
ok1(index == idx[1]);
ok1(*intp == NUM-1);
jmap_putval(map, &intp);
index = idx[NUM-1];
intp = jmap_nextval(map, &index);
ok1(intp == NULL);
ok1(jmap_error(map) == NULL);
jmap_free(map);
for (i = 0; i < NUM+1; i++)
free(idx[i]);
return exit_status();
}
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
#include <ccan/jmap/jmap_type.h>
#include <ccan/jmap/jmap.c> #include <ccan/jmap/jmap.c>
struct foo; struct foo;
struct idx; struct idx;
JMAP_DEFINE_PTRIDX_TYPE(struct idx, struct foo, foo); struct jmap_foo {
JMAP_MEMBERS(struct idx *, struct foo *);
};
#define NUM 100 #define NUM 100
...@@ -32,70 +33,70 @@ int main(int argc, char *argv[]) ...@@ -32,70 +33,70 @@ int main(int argc, char *argv[])
for (i = 0; i < NUM+1; i++) for (i = 0; i < NUM+1; i++)
idx[i] = (void *)((char *)foo[i] + 1); idx[i] = (void *)((char *)foo[i] + 1);
map = jmap_foo_new(); map = jmap_new(struct jmap_foo);
ok1(jmap_foo_error(map) == NULL); ok1(jmap_error(map) == NULL);
ok1(jmap_foo_test(map, idx[NUM]) == false); ok1(jmap_test(map, idx[NUM]) == false);
ok1(jmap_foo_get(map, idx[NUM]) == (struct foo *)NULL); ok1(jmap_get(map, idx[NUM]) == (struct foo *)NULL);
ok1(jmap_foo_count(map) == 0); ok1(jmap_count(map) == 0);
ok1(jmap_foo_first(map) == (struct idx *)NULL); ok1(jmap_first(map) == (struct idx *)NULL);
ok1(jmap_foo_del(map, idx[0]) == false); ok1(jmap_del(map, idx[0]) == false);
/* Set only works on existing cases. */ /* Set only works on existing cases. */
ok1(jmap_foo_set(map, idx[0], foo[0]) == false); ok1(jmap_set(map, idx[0], foo[0]) == false);
ok1(jmap_foo_add(map, idx[0], foo[1]) == true); ok1(jmap_add(map, idx[0], foo[1]) == true);
ok1(jmap_foo_get(map, idx[0]) == foo[1]); ok1(jmap_get(map, idx[0]) == foo[1]);
ok1(jmap_foo_set(map, idx[0], foo[0]) == true); ok1(jmap_set(map, idx[0], foo[0]) == true);
ok1(jmap_foo_get(map, idx[0]) == foo[0]); ok1(jmap_get(map, idx[0]) == foo[0]);
ok1(jmap_foo_test(map, idx[0]) == true); ok1(jmap_test(map, idx[0]) == true);
ok1(jmap_foo_count(map) == 1); ok1(jmap_count(map) == 1);
ok1(jmap_foo_first(map) == idx[0]); ok1(jmap_first(map) == idx[0]);
ok1(jmap_foo_next(map, idx[0]) == NULL); ok1(jmap_next(map, idx[0]) == NULL);
ok1(jmap_foo_del(map, idx[0]) == true); ok1(jmap_del(map, idx[0]) == true);
ok1(jmap_foo_test(map, idx[0]) == false); ok1(jmap_test(map, idx[0]) == false);
ok1(jmap_foo_count(map) == 0); ok1(jmap_count(map) == 0);
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
jmap_foo_add(map, idx[i], foo[i]); jmap_add(map, idx[i], foo[i]);
ok1(jmap_foo_count(map) == NUM); ok1(jmap_count(map) == NUM);
ok1(jmap_foo_first(map) == idx[0]); ok1(jmap_first(map) == idx[0]);
ok1(jmap_foo_next(map, idx[0]) == idx[1]); ok1(jmap_next(map, idx[0]) == idx[1]);
ok1(jmap_foo_next(map, idx[NUM-1]) == NULL); ok1(jmap_next(map, idx[NUM-1]) == NULL);
ok1(jmap_foo_get(map, idx[0]) == foo[0]); ok1(jmap_get(map, idx[0]) == foo[0]);
ok1(jmap_foo_get(map, idx[NUM-1]) == foo[NUM-1]); ok1(jmap_get(map, idx[NUM-1]) == foo[NUM-1]);
ok1(jmap_foo_get(map, (void *)((char *)idx[NUM-1] + 1)) == NULL); ok1(jmap_get(map, (void *)((char *)idx[NUM-1] + 1)) == NULL);
/* Reverse values in map. */ /* Reverse values in map. */
for (i = 0; i < NUM; i++) { for (i = 0; i < NUM; i++) {
foop = jmap_foo_getval(map, idx[i]); foop = jmap_getval(map, idx[i]);
ok1(*foop == foo[i]); ok1(*foop == foo[i]);
*foop = foo[NUM-1-i]; *foop = foo[NUM-1-i];
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
} }
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
ok1(jmap_foo_get(map, idx[i]) == foo[NUM-1-i]); ok1(jmap_get(map, idx[i]) == foo[NUM-1-i]);
foop = jmap_foo_firstval(map, &index); foop = jmap_firstval(map, &index);
ok1(index == idx[0]); ok1(index == idx[0]);
ok1(*foop == foo[NUM-1]); ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_nextval(map, &index); foop = jmap_nextval(map, &index);
ok1(index == idx[1]); ok1(index == idx[1]);
ok1(*foop == foo[NUM-2]); ok1(*foop == foo[NUM-2]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
index = idx[NUM-1]; index = idx[NUM-1];
foop = jmap_foo_nextval(map, &index); foop = jmap_nextval(map, &index);
ok1(foop == NULL); ok1(foop == NULL);
ok1(jmap_foo_error(map) == NULL); ok1(jmap_error(map) == NULL);
jmap_foo_free(map); jmap_free(map);
for (i = 0; i < NUM+1; i++) for (i = 0; i < NUM+1; i++)
free(foo[i]); free(foo[i]);
......
#include <ccan/tap/tap.h> #include <ccan/tap/tap.h>
#include <ccan/jmap/jmap_type.h>
#include <ccan/jmap/jmap.c> #include <ccan/jmap/jmap.c>
struct foo; struct foo;
JMAP_DEFINE_UINTIDX_TYPE(struct foo, foo); struct jmap_foo {
JMAP_MEMBERS(unsigned long, struct foo *);
};
#define NUM 100 #define NUM 100
...@@ -14,117 +15,120 @@ int main(int argc, char *argv[]) ...@@ -14,117 +15,120 @@ int main(int argc, char *argv[])
struct foo *foo[NUM], **foop; struct foo *foo[NUM], **foop;
unsigned long i; unsigned long i;
plan_tests(37 + NUM*2 + 19); plan_tests(40 + NUM*2 + 19);
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
foo[i] = malloc(20); foo[i] = malloc(20);
map = jmap_foo_new(); map = jmap_new(struct jmap_foo);
ok1(jmap_foo_error(map) == NULL); ok1(jmap_error(map) == NULL);
ok1(jmap_foo_test(map, 0) == false); ok1(jmap_test(map, 0) == false);
ok1(jmap_foo_get(map, 0) == (struct foo *)NULL); ok1(jmap_get(map, 0) == (struct foo *)NULL);
ok1(jmap_foo_popcount(map, 0, -1) == 0); ok1(jmap_popcount(map, 0, -1) == 0);
ok1(jmap_foo_first(map, 0) == 0); ok1(jmap_first(map) == 0);
ok1(jmap_foo_last(map, 0) == 0); ok1(jmap_last(map) == 0);
ok1(jmap_foo_del(map, 0) == false); ok1(jmap_del(map, 0) == false);
/* Set only works on existing cases. */ /* Set only works on existing cases. */
ok1(jmap_foo_set(map, 0, foo[0]) == false); ok1(jmap_set(map, 1, foo[0]) == false);
ok1(jmap_foo_add(map, 0, foo[1]) == true); ok1(jmap_add(map, 1, foo[1]) == true);
ok1(jmap_foo_get(map, 0) == foo[1]); ok1(jmap_get(map, 1) == foo[1]);
ok1(jmap_foo_set(map, 0, foo[0]) == true); ok1(jmap_set(map, 1, foo[0]) == true);
ok1(jmap_foo_get(map, 0) == foo[0]); ok1(jmap_get(map, 1) == foo[0]);
ok1(jmap_foo_test(map, 0) == true); ok1(jmap_test(map, 1) == true);
ok1(jmap_foo_popcount(map, 0, -1) == 1); ok1(jmap_popcount(map, 0, -1) == 1);
ok1(jmap_foo_first(map, -1) == 0); ok1(jmap_first(map) == 1);
ok1(jmap_foo_last(map, -1) == 0); ok1(jmap_last(map) == 1);
ok1(jmap_foo_next(map, 0, -1) == (size_t)-1); ok1(jmap_next(map, 0) == 1);
ok1(jmap_foo_prev(map, 0, -1) == (size_t)-1); ok1(jmap_next(map, 1) == 0);
ok1(jmap_prev(map, 2) == 1);
ok1(jmap_foo_del(map, 0) == true); ok1(jmap_prev(map, 1) == 0);
ok1(jmap_foo_test(map, 0) == false);
ok1(jmap_foo_popcount(map, 0, -1) == 0); ok1(jmap_del(map, 1) == true);
ok1(jmap_test(map, 1) == false);
ok1(jmap_popcount(map, 0, -1) == 0);
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
jmap_foo_add(map, i, foo[i]); jmap_add(map, i+1, foo[i]);
ok1(jmap_foo_popcount(map, 0, -1) == NUM); ok1(jmap_count(map) == NUM);
ok1(jmap_foo_popcount(map, 0, NUM-1) == NUM); ok1(jmap_popcount(map, 0, -1) == NUM);
ok1(jmap_foo_popcount(map, 0, NUM/2-1) == NUM/2); ok1(jmap_popcount(map, 1, NUM) == NUM);
ok1(jmap_foo_popcount(map, NUM/2, NUM) == NUM - NUM/2); ok1(jmap_popcount(map, 1, NUM/2) == NUM/2);
ok1(jmap_popcount(map, NUM/2+1, NUM) == NUM - NUM/2);
ok1(jmap_foo_nth(map, 0, -1) == 0);
ok1(jmap_foo_nth(map, NUM-1, -1) == NUM-1); ok1(jmap_nth(map, 0, -1) == 1);
ok1(jmap_foo_nth(map, NUM, -1) == (size_t)-1); ok1(jmap_nth(map, NUM-1, -1) == NUM);
ok1(jmap_foo_first(map, -1) == 0); ok1(jmap_nth(map, NUM, -1) == (size_t)-1);
ok1(jmap_foo_last(map, -1) == NUM-1); ok1(jmap_first(map) == 1);
ok1(jmap_foo_next(map, 0, -1) == 1); ok1(jmap_last(map) == NUM);
ok1(jmap_foo_next(map, NUM-1, -1) == (size_t)-1); ok1(jmap_next(map, 1) == 2);
ok1(jmap_foo_prev(map, 1, -1) == 0); ok1(jmap_next(map, NUM) == 0);
ok1(jmap_foo_prev(map, 0, -1) == (size_t)-1); ok1(jmap_prev(map, 2) == 1);
ok1(jmap_prev(map, 1) == 0);
ok1(jmap_foo_get(map, 0) == foo[0]);
ok1(jmap_foo_get(map, NUM-1) == foo[NUM-1]); ok1(jmap_get(map, 1) == foo[0]);
ok1(jmap_foo_get(map, NUM) == NULL); ok1(jmap_get(map, NUM) == foo[NUM-1]);
ok1(jmap_get(map, NUM+1) == NULL);
/* Reverse values in map. */ /* Reverse values in map. */
for (i = 0; i < NUM; i++) { for (i = 0; i < NUM; i++) {
foop = jmap_foo_getval(map, i); foop = jmap_getval(map, i+1);
ok1(*foop == foo[i]); ok1(*foop == foo[i]);
*foop = foo[NUM-1-i]; *foop = foo[NUM-1-i];
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
} }
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
ok1(jmap_foo_get(map, i) == foo[NUM-1-i]); ok1(jmap_get(map, i+1) == foo[NUM-1-i]);
foop = jmap_foo_nthval(map, 0, &i); foop = jmap_nthval(map, 0, &i);
ok1(i == 0); ok1(i == 1);
ok1(*foop == foo[NUM-1]); ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_nthval(map, NUM-1, &i); foop = jmap_nthval(map, NUM-1, &i);
ok1(i == NUM-1); ok1(i == NUM);
ok1(*foop == foo[0]); ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_firstval(map, &i); foop = jmap_firstval(map, &i);
ok1(i == 0); ok1(i == 1);
ok1(*foop == foo[NUM-1]); ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_nextval(map, &i); foop = jmap_nextval(map, &i);
ok1(i == 1); ok1(i == 2);
ok1(*foop == foo[NUM-2]); ok1(*foop == foo[NUM-2]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_prevval(map, &i); foop = jmap_prevval(map, &i);
ok1(i == 0); ok1(i == 1);
ok1(*foop == foo[NUM-1]); ok1(*foop == foo[NUM-1]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_prevval(map, &i); foop = jmap_prevval(map, &i);
ok1(foop == NULL); ok1(foop == NULL);
foop = jmap_foo_lastval(map, &i); foop = jmap_lastval(map, &i);
ok1(i == NUM-1); ok1(i == NUM);
ok1(*foop == foo[0]); ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_prevval(map, &i); foop = jmap_prevval(map, &i);
ok1(i == NUM-2); ok1(i == NUM-1);
ok1(*foop == foo[1]); ok1(*foop == foo[1]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_nextval(map, &i); foop = jmap_nextval(map, &i);
ok1(i == NUM-1); ok1(i == NUM);
ok1(*foop == foo[0]); ok1(*foop == foo[0]);
jmap_foo_putval(map, &foop); jmap_putval(map, &foop);
foop = jmap_foo_nextval(map, &i); foop = jmap_nextval(map, &i);
ok1(foop == NULL); ok1(foop == NULL);
ok1(jmap_foo_error(map) == NULL); ok1(jmap_error(map) == NULL);
jmap_foo_free(map); jmap_free(map);
for (i = 0; i < NUM; i++) for (i = 0; i < NUM; i++)
free(foo[i]); free(foo[i]);
......
...@@ -2,111 +2,113 @@ ...@@ -2,111 +2,113 @@
#define CCAN_JMAP_DEBUG #define CCAN_JMAP_DEBUG
#include <ccan/jmap/jmap.c> #include <ccan/jmap/jmap.c>
struct map {
JMAP_MEMBERS(unsigned long, unsigned long);
};
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct jmap *map; struct map *map;
unsigned long i, *value; unsigned long i, *value;
const char *err; const char *err;
plan_tests(53); plan_tests(51);
map = jmap_new(); map = jmap_new(struct map);
ok1(jmap_error(map) == NULL); ok1(jmap_error(map) == NULL);
ok1(jmap_test(map, 0) == false); ok1(jmap_test(map, 0) == false);
ok1(jmap_del(map, 0) == false); ok1(jmap_del(map, 0) == false);
ok1(jmap_add(map, 0, 1) == true); ok1(jmap_add(map, 0, 1) == true);
ok1(jmap_test(map, 0) == true); ok1(jmap_test(map, 0) == true);
ok1(jmap_get(map, 0, -1) == 1); ok1(jmap_get(map, 0) == 1);
ok1(jmap_get(map, 1, -1) == (size_t)-1); ok1(jmap_get(map, 1) == 0);
ok1(jmap_del(map, 0) == true); ok1(jmap_del(map, 0) == true);
ok1(jmap_popcount(map, 0, -1) == 0); ok1(jmap_popcount(map, 0, -1) == 0);
ok1(jmap_nth(map, 0, 0) == 0); ok1(jmap_nth(map, 0, 0) == 0);
ok1(jmap_nth(map, 0, -1) == (size_t)-1); ok1(jmap_nth(map, 0, -1) == (size_t)-1);
ok1(jmap_first(map, 0) == 0); ok1(jmap_first(map) == 0);
ok1(jmap_first(map, -1) == (size_t)-1); ok1(jmap_last(map) == 0);
ok1(jmap_last(map, 0) == 0);
ok1(jmap_last(map, -1) == (size_t)-1);
ok1(jmap_getval(map, 0) == NULL); ok1(jmap_getval(map, 0) == NULL);
/* Map a million indices, 16 apart. */ /* Map a million indices, 16 apart. */
for (i = 0; i < 1000000; i++) for (i = 0; i < 1000000; i++)
jmap_add(map, i << 4, (i << 5) + 1); jmap_add(map, (i << 4) + 1, (i << 5) + 1);
/* This only take 6.3MB on my 32-bit system. */ /* This only take 6.3MB on my 32-bit system. */
diag("%u bytes memory used\n", (unsigned)JudyLMemUsed(map->judy)); diag("%u bytes memory used\n", (unsigned)JudyLMemUsed(map->raw.judy));
ok1(jmap_get(map, 0, -1) == 1); ok1(jmap_get(map, 1) == 1);
ok1(jmap_get(map, 999999 << 4, -1) == (999999 << 5) + 1); ok1(jmap_get(map, (999999 << 4) + 1) == (999999 << 5) + 1);
ok1(jmap_popcount(map, 0, -1) == 1000000); ok1(jmap_popcount(map, 0, -1) == 1000000);
ok1(jmap_nth(map, 0, -1) == 0); ok1(jmap_nth(map, 0, -1) == 1);
ok1(jmap_nth(map, 999999, -1) == 999999 << 4); ok1(jmap_nth(map, 999999, -1) == (999999 << 4) + 1);
ok1(jmap_nth(map, 1000000, -1) == (size_t)-1); ok1(jmap_nth(map, 1000000, -1) == (size_t)-1);
ok1(jmap_first(map, -1) == 0); ok1(jmap_first(map) == 1);
ok1(jmap_last(map, -1) == 999999 << 4); ok1(jmap_last(map) == (999999 << 4) + 1);
ok1(jmap_next(map, 0, -1) == 1 << 4); ok1(jmap_next(map, 1) == (1 << 4) + 1);
ok1(jmap_next(map, 999999 << 4, -1) == (size_t)-1); ok1(jmap_next(map, (999999 << 4) + 1) == 0);
ok1(jmap_prev(map, 1, -1) == 0); ok1(jmap_prev(map, 2) == 1);
ok1(jmap_prev(map, 0, -1) == (size_t)-1); ok1(jmap_prev(map, 0) == 0);
ok1(jmap_error(map) == NULL); ok1(jmap_error(map) == NULL);
/* Accessors. */ /* Accessors. */
value = jmap_getval(map, 0); value = jmap_getval(map, 1);
ok1(value && *value == 1); ok1(value && *value == 1);
*value = 2; *value = 2;
ok1(jmap_get(map, 0, -1) == 2); ok1(jmap_get(map, 1) == 2);
jmap_putval(map, &value); jmap_putval(map, &value);
ok1(jmap_get(map, 0, -1) == 2); ok1(jmap_get(map, 1) == 2);
ok1(jmap_set(map, 0, 1)); ok1(jmap_set(map, 1, 1));
value = jmap_getval(map, 999999 << 4); value = jmap_getval(map, (999999 << 4) + 1);
ok1(value && *value == (999999 << 5) + 1); ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value); jmap_putval(map, &value);
value = jmap_nthval(map, 0, &i); value = jmap_nthval(map, 0, &i);
ok1(i == 0); ok1(i == 1);
ok1(value && *value == 1); ok1(value && *value == 1);
jmap_putval(map, &value); jmap_putval(map, &value);
value = jmap_nthval(map, 999999, &i); value = jmap_nthval(map, 999999, &i);
ok1(i == 999999 << 4); ok1(i == (999999 << 4) + 1);
ok1(value && *value == (999999 << 5) + 1); ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value); jmap_putval(map, &value);
ok1(jmap_nthval(map, 1000000, &i) == NULL); ok1(jmap_nthval(map, 1000000, &i) == NULL);
value = jmap_firstval(map, &i); value = jmap_firstval(map, &i);
ok1(i == 0); ok1(i == 1);
ok1(value && *value == 1); ok1(value && *value == 1);
jmap_putval(map, &value); jmap_putval(map, &value);
ok1(jmap_prevval(map, &i) == NULL); ok1(jmap_prevval(map, &i) == NULL);
i = 0; i = 1;
value = jmap_nextval(map, &i); value = jmap_nextval(map, &i);
ok1(i == 1 << 4); ok1(i == (1 << 4) + 1);
ok1(value && *value == (1 << 5) + 1); ok1(value && *value == (1 << 5) + 1);
jmap_putval(map, &value); jmap_putval(map, &value);
value = jmap_lastval(map, &i); value = jmap_lastval(map, &i);
ok1(i == 999999 << 4); ok1(i == (999999 << 4) + 1);
ok1(value && *value == (999999 << 5) + 1); ok1(value && *value == (999999 << 5) + 1);
jmap_putval(map, &value); jmap_putval(map, &value);
ok1(jmap_nextval(map, &i) == NULL); ok1(jmap_nextval(map, &i) == NULL);
i = 999999 << 4; i = (999999 << 4) + 1;
value = jmap_prevval(map, &i); value = jmap_prevval(map, &i);
ok1(i == 999998 << 4); ok1(i == (999998 << 4) + 1);
ok1(value && *value == (999998 << 5) + 1); ok1(value && *value == (999998 << 5) + 1);
jmap_putval(map, &value); jmap_putval(map, &value);
/* Test error handling */ /* Test error handling */
JU_ERRNO(&map->err) = 100; JU_ERRNO(&map->raw.err) = 100;
JU_ERRID(&map->err) = 991; JU_ERRID(&map->raw.err) = 991;
err = jmap_error(map); err = jmap_error(map);
ok1(err); ok1(err);
ok1(strstr(err, "100")); ok1(strstr(err, "100"));
ok1(strstr(err, "991")); ok1(strstr(err, "991"));
ok1(err == map->errstr); ok1(err == map->raw.errstr);
jmap_free(map); jmap_free(map);
return exit_status(); return exit_status();
......
...@@ -74,8 +74,10 @@ ...@@ -74,8 +74,10 @@
*/ */
#if HAVE_TYPEOF #if HAVE_TYPEOF
#define tcon_cast(x, canary, expr) ((__typeof__((x)->_tcon[0].canary))(expr)) #define tcon_cast(x, canary, expr) ((__typeof__((x)->_tcon[0].canary))(expr))
#define tcon_cast_ptr(x, canary, expr) ((__typeof__(&(x)->_tcon[0].canary))(expr))
#else #else
#define tcon_cast(x, canary, expr) ((void *)(expr)) #define tcon_cast(x, canary, expr) ((void *)(expr))
#define tcon_cast_ptr(x, canary, expr) ((void *)(expr))
#endif #endif
#endif /* CCAN_TCON_H */ #endif /* CCAN_TCON_H */
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