From 3a34aa1a0c71b0be86511a8aa83af9935351dad1 Mon Sep 17 00:00:00 2001
From: Rusty Russell <rusty@rustcorp.com.au>
Date: Fri, 23 Sep 2011 12:00:49 +0930
Subject: [PATCH] jmap: use ccan/tcon and always be typesafe.

This handles both pointer and integer types using ccan/tcon.
---
 ccan/jmap/_info                   |  60 +--
 ccan/jmap/jmap.c                  |   9 +-
 ccan/jmap/jmap.h                  | 607 ++++++++++++++++++------------
 ccan/jmap/jmap_type.h             | 303 ---------------
 ccan/jmap/test/run-access-count.c |   8 +-
 ccan/jmap/test/run-ptridx-int.c   |  99 +++++
 ccan/jmap/test/run-ptridx-type.c  |  79 ++--
 ccan/jmap/test/run-uintidx-type.c | 160 ++++----
 ccan/jmap/test/run.c              |  76 ++--
 ccan/tcon/tcon.h                  |   2 +
 10 files changed, 676 insertions(+), 727 deletions(-)
 delete mode 100644 ccan/jmap/jmap_type.h
 create mode 100644 ccan/jmap/test/run-ptridx-int.c

diff --git a/ccan/jmap/_info b/ccan/jmap/_info
index cad473bf..0047dc05 100644
--- a/ccan/jmap/_info
+++ b/ccan/jmap/_info
@@ -9,38 +9,46 @@
  * 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.
+ * You define a struct for your particular index and value types using
+ * the JMAP_MEMBERS macro, then use the jmap routines to manipulate
+ * 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:
  * // Silly example of associating data with arguments by pointer and int.
  * #include <string.h>
  * #include <stdio.h>
- * #include <ccan/jmap/jmap_type.h>
+ * #include <ccan/jmap/jmap.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);
+ * // Define map type for int -> argv.
+ * struct arg_map {
+ *	JMAP_MEMBERS(int, char *);
+ * };
+ * // Define map type for argv -> struct opt_detail *.
+ * struct opt_map {
+ *	JMAP_MEMBERS(char *, struct opt_detail *);
+ * };
  * 
  * 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 arg_map *arg = jmap_new(struct arg_map);
+ * 	struct opt_map *opt = jmap_new(struct opt_map);
  * 	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] != '-')
+ * 	for (i = 1; i < argc; i++) {
+ * 		jmap_add(arg, i, argv[i]);
+ * 		if (argv[i][0] != '-')
  * 			continue;
  * 		d = malloc(sizeof(*d));
  * 		if (argv[i][1] == '-') {
@@ -52,27 +60,30 @@
  * 			d->is_long = false;
  * 			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));
- * 	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("Found %lu options:\n", jmap_count(opt));
+ * 	for (i = jmap_first(arg); i; i = jmap_next(arg,i)) {
+ * 		char *a = jmap_get(arg, i);
+ * 		d = jmap_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 ? "normal arg"
+ * 		       : d->is_long ? "long opt"
+ * 		       : "short opt",
  * 		       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);
+ * 	jmap_free(opt);
+ * 	jmap_free(arg);
  * 	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)
  * Author: Rusty Russell <rusty@rustcorp.com.au>
  */
@@ -84,6 +95,7 @@ int main(int argc, char *argv[])
 	if (strcmp(argv[1], "depends") == 0) {
 		printf("ccan/build_assert\n");
 		printf("ccan/compiler\n");
+		printf("ccan/tcon\n");
 		printf("Judy\n");
 		return 0;
 	}
diff --git a/ccan/jmap/jmap.c b/ccan/jmap/jmap.c
index 78b7ba21..8982a715 100644
--- a/ccan/jmap/jmap.c
+++ b/ccan/jmap/jmap.c
@@ -4,7 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-struct jmap *jmap_new(void)
+struct jmap *jmap_new_(size_t size)
 {
 	struct jmap *map;
 
@@ -13,7 +13,8 @@ struct jmap *jmap_new(void)
 	/* We also put pointers into Judy, in jmap_types.h */
 	BUILD_ASSERT(sizeof(Word_t) >= sizeof(void *));
 
-	map = malloc(sizeof(*map));
+	assert(size >= sizeof(*map));
+	map = malloc(size);
 	if (map) {
 		map->judy = NULL;
 		memset(&map->err, 0, sizeof(map->err));
@@ -26,7 +27,7 @@ struct jmap *jmap_new(void)
 	return map;
 }
 
-const char *jmap_error_(struct jmap *map)
+const char *jmap_error_str_(struct jmap *map)
 {
 	char *str;
 	free((char *)map->errstr);
@@ -40,7 +41,7 @@ const char *jmap_error_(struct jmap *map)
 	return str;
 }
 
-void jmap_free(const struct jmap *map)
+void jmap_free_(const struct jmap *map)
 {
 	free((char *)map->errstr);
 	JudyLFreeArray((PPvoid_t)&map->judy, PJE0);
diff --git a/ccan/jmap/jmap.h b/ccan/jmap/jmap.h
index 26a8d339..e30a6ece 100644
--- a/ccan/jmap/jmap.h
+++ b/ccan/jmap/jmap.h
@@ -1,39 +1,23 @@
 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
 #ifndef CCAN_JMAP_H
 #define CCAN_JMAP_H
+#include <ccan/compiler/compiler.h>
+#include <ccan/tcon/tcon.h>
 #include <stddef.h>
 #include <Judy.h>
 #include <stdbool.h>
 #include <string.h>
-#include <ccan/compiler/compiler.h>
 #include <assert.h>
 #ifdef CCAN_JMAP_DEBUG
 #include <stdio.h>
 #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");
+ * It's exposed here so you can put it in your structures and so we can
+ * supply inline functions.
  */
-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;
@@ -45,47 +29,46 @@ struct jmap {
 	unsigned long acc_index;
 	const char *funcname;
 };
-const char *COLD jmap_error_(struct jmap *map);
 
-/* 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);
-}
+/**
+ * JMAP_MEMBERS - declare members for a type-specific jmap.
+ * @itype: index type for this map, or void * for any pointer.
+ * @ctype: contents type for this map, or void * for any pointer.
+ *
+ * Example:
+ *	struct jmap_long_to_charp {
+ *		JMAP_MEMBERS(long, char *);
+ *	};
+ */
+#define JMAP_MEMBERS(itype, ctype)		\
+	struct jmap raw;			\
+	TCON(itype icanary; ctype ccanary)
 
-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(*val)));
-}
+/**
+ * jmap_new - create a new, empty jmap.
+ *
+ * See Also:
+ *	JMAP_MEMBERS()
+ *
+ * Example:
+ *	struct jmap_long_to_charp {
+ *		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)
-{
-#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);
-}
+/**
+ * jmap_free - destroy a jmap.
+ * @map: the map returned from jmap_new.
+ *
+ * Example:
+ *	jmap_free(map);
+ */
+#define jmap_free(map) jmap_free_(&(map)->raw)
 
 /**
  * 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)
  * 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);
-}
+#define jmap_error(map) jmap_error_(&(map)->raw)
+
+/**
+ * jmap_rawi - unwrap the typed map and check the index type
+ * @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.
@@ -125,20 +135,12 @@ static inline const char *jmap_error(struct jmap *map)
  * Returns false on error (out of memory).
  *
  * Example:
- *	if (!jmap_add(map, 0, 1))
+ *	if (!jmap_add(map, 0, "hello"))
  *		err(1, "jmap_add failed!");
  */
-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;
-}
+#define jmap_add(map, index, value)				\
+	jmap_add_(jmap_rawci((map), (index), (value)),		\
+		  (unsigned long)(index), (unsigned long)value)
 
 /**
  * jmap_set - change a value for an existing index in the map.
@@ -150,21 +152,12 @@ static inline bool jmap_add(struct jmap *map,
  * otherwise returns false and does nothing.
  *
  * Example:
- *	if (!jmap_set(map, 0, 2))
+ *	if (!jmap_set(map, 0, "goodbye"))
  *		err(1, "jmap_set: index 0 not found");
  */
-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;
-}
+#define jmap_set(map, index, value)				\
+	jmap_set_(jmap_rawci((map), (index), (value)),		\
+		  (unsigned long)(index), (unsigned long)value)
 
 /**
  * jmap_del - remove an index from the map.
@@ -175,11 +168,8 @@ static inline bool jmap_set(const struct jmap *map,
  *	if (!jmap_del(map, 0))
  *		err(1, "jmap_del failed!");
  */
-static inline bool jmap_del(struct jmap *map, unsigned long index)
-{
-	jmap_debug_access(map);
-	return JudyLDel(&map->judy, index, &map->err) == 1;
-}
+#define jmap_del(map, index)						\
+	jmap_del_(jmap_rawi((map), (index)), (unsigned long)(index))
 
 /**
  * jmap_test - test if a given index is defined.
@@ -187,38 +177,40 @@ static inline bool jmap_del(struct jmap *map, unsigned long index)
  * @index: the index to find
  *
  * Example:
- *	jmap_add(map, 0, 1);
- *	assert(jmap_test(map, 0));
+ *	jmap_add(map, 1, "hello");
+ *	assert(jmap_test(map, 1));
  */
-static inline bool jmap_test(const struct jmap *map, unsigned long index)
-{
-	return JudyLGet(map->judy, index, (JError_t *)&map->err) != NULL;
-}
+#define jmap_test(map, index)				\
+	jmap_test_(jmap_rawi((map), (index)), (unsigned long)(index))
 
 /**
  * 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.
+ *
+ * Returns 0 if !jmap_test(map, index).
  *
  * Example:
- *	jmap_add(map, 0, 1);
- *	assert(jmap_get(map, 0, -1) == 1);
+ *	const char *str = "hello";
+ *	jmap_add(map, 2, str);
+ *	assert(jmap_get(map, 0) == str);
  *
  * See Also:
  *	jmap_getval()
  */
-static inline unsigned long jmap_get(const struct jmap *map,
-				     unsigned long index,
-				     unsigned long invalid)
-{
-	unsigned long *val;
-	val = (unsigned long *)JudyLGet(map->judy, index,
-					(JError_t *)&map->err);
-	if (!val || val == PJERR)
-		return invalid;
-	return *val;
-}
+#define jmap_get(map, index)						\
+	tcon_cast((map), ccanary,					\
+		  jmap_get_(jmap_rawi((map), (index)), (unsigned long)(index)))
+
+/**
+ * jmap_count - get population of the map.
+ * @map: map from jmap_new
+ *
+ * Example:
+ *	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.
@@ -229,12 +221,9 @@ static inline unsigned long jmap_get(const struct jmap *map,
  * Example:
  *	assert(jmap_popcount(map, 0, 1000) <= jmap_popcount(map, 0, 2000));
  */
-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);
-}
+#define jmap_popcount(map, start, end_incl)				\
+	jmap_popcount_(jmap_rawi((map), (start) ? (start) : (end_incl)), \
+		       (unsigned long)(start), (unsigned long)(end_incl))
 
 /**
  * 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,
  * See Also:
  *	jmap_nthval();
  */
-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;
-}
+#define jmap_nth(map, n, invalid)					\
+	tcon_cast((map), icanary,					\
+		  jmap_nth_(jmap_rawi((map), (invalid)),			\
+			    (n), (unsigned long)(invalid)))
 
 /**
- * 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
- * @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:
  *	assert(!jmap_test(map, 0));
  *	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("\n");
  *
  * See Also:
  *	jmap_firstval()
  */
-static inline unsigned long jmap_first(const struct jmap *map,
-				       unsigned long invalid)
-{
-	unsigned long index = 0;
-	if (!JudyLFirst(map->judy, &index, (JError_t *)&map->err))
-		index = invalid;
-	else
-		assert(index != invalid);
-	return index;
-}
+#define jmap_first(map)						\
+	tcon_cast((map), icanary, jmap_first_(&(map)->raw))
 
 /**
  * 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 unsigned long jmap_next(const struct jmap *map,
-				      unsigned long prev,
-				      unsigned long invalid)
-{
-	if (!JudyLNext(map->judy, &prev, (JError_t *)&map->err))
-		prev = invalid;
-	else
-		assert(prev != invalid);
-	return prev;
-}
+#define jmap_next(map, prev)						\
+	tcon_cast((map), icanary, jmap_next_(jmap_rawi((map), (prev)),	\
+					     (unsigned long)(prev)))
 
 /**
  * jmap_last - return the last index in the map.
  * @map: map from jmap_new
- * @invalid: return value if map is empty.
+ *
+ * Returns 0 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))
+ *	for (i = jmap_last(map); i; i = jmap_prev(map, i))
  *		printf(" %lu", i);
  *	printf("\n");
  * See Also:
  *	jmap_lastval()
  */
-static inline unsigned long jmap_last(const struct jmap *map,
-				      unsigned long invalid)
-{
-	unsigned long index = -1;
-	if (!JudyLLast(map->judy, &index, (JError_t *)&map->err))
-		index = invalid;
-	else
-		assert(index != invalid);
-	return index;
-}
+#define jmap_last(map)						\
+	tcon_cast((map), icanary, jmap_last_(&(map)->raw))
 
 /**
- * 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
  * @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.
+ * Returns 0 if no previous indices in map.
+ *
  * See Also:
  *	jmap_prevval()
  */
-static inline unsigned long jmap_prev(const struct jmap *map,
-				      unsigned long prev,
-				      unsigned long invalid)
-{
-	if (!JudyLPrev(map->judy, &prev, (JError_t *)&map->err))
-		prev = invalid;
-	else
-		assert(prev != invalid);
-	return prev;
-}
+#define jmap_prev(map, prev)						\
+	tcon_cast((map), icanary, jmap_prev_(jmap_rawi((map), (prev)), (prev)))
 
 /**
  * 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,
  * have called jmap_putval().
  *
  * Example:
- *	unsigned long *p;
- *	jmap_add(map, 0, 1);
+ *	char **p;
+ *	jmap_add(map, 0, "hello");
  *	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;
+ *	if (strcmp(*p, "hello") != 0)
+ *		errx(1, "Value in map was not correct?!");
+ *	*p = (char *)"goodbye";
  *	jmap_putval(map, &p);
  *	// Accessing p now would probably crash.
  *
  * See Also:
  *	jmap_putval(), jmap_firstval()
  */
-static inline unsigned long *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;
-}
+#define jmap_getval(map, index)						\
+	tcon_cast_ptr((map), ccanary,					\
+		      jmap_getval_(jmap_rawi((map), (index)),		\
+				   (unsigned long)(index)))
 
 /**
  * jmap_putval - revoke access to a value.
@@ -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_lastval(), jmap_prevval().
  */
-static inline void jmap_putval(struct jmap *map, unsigned long **p)
-{
-	jmap_debug_del_access(map, p);
-}
+#define jmap_putval(map, p)						\
+	jmap_putval_(jmap_rawc((map), **(p)), (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)
+ * @index: set to 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.
  * You must use jmap_putval() on the pointer once you are done with it.
  *
  * Example:
- *	unsigned long *val;
+ *	char **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 %lu = %lu, value = %lu\n", i, index, *val);
+ *		printf("Index %lu = %lu, value = %s\n", i, index, *val);
  *		jmap_putval(map, &val);
  *	}
  *
  * See Also:
  *	jmap_nth();
  */
-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;
-}
+#define jmap_nthval(map, n, index)					\
+	tcon_cast_ptr((map), ccanary,					\
+		      jmap_nthval_(jmap_rawi((map), *(index)), (n), (index)))
 
 /**
  * jmap_firstval - access the first value in the 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!
  *
  * 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)) {
  *		(*val)++;
  *		jmap_putval(map, &val);
@@ -472,16 +415,10 @@ static inline unsigned long *jmap_nthval(const struct jmap *map,
  * See Also:
  *	jmap_first, jmap_nextval()
  */
-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;
-}
+#define jmap_firstval(map, index)	      \
+	tcon_cast_ptr((map), ccanary,				\
+		      jmap_firstval_(jmap_rawi((map), *(index)),	\
+				     (unsigned long *)(index)))
 
 /**
  * jmap_nextval - access the next value in the map.
@@ -494,15 +431,11 @@ static inline unsigned long *jmap_firstval(const struct jmap *map,
  * See Also:
  *	jmap_firstval(), jmap_putval()
  */
-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;
-}
+#define jmap_nextval(map, index)				\
+	tcon_cast_ptr((map), ccanary,				\
+		      jmap_nextval_(jmap_rawi((map), *(index)),	\
+				    (unsigned long *)(index)))
+
 
 /**
  * jmap_lastval - access the last value in the map.
@@ -512,16 +445,11 @@ static inline unsigned long *jmap_nextval(const struct jmap *map,
  * See Also:
  *	jmap_last(), jmap_putval()
  */
-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;
-}
+#define jmap_lastval(map, index)	      \
+	tcon_cast_ptr((map), ccanary,				\
+		      jmap_lastval_(jmap_rawi((map), *(index)),	\
+				    (unsigned long *)(index)))
+
 
 /**
  * jmap_prevval - access the previous value in the map.
@@ -534,8 +462,207 @@ static inline unsigned long *jmap_lastval(const struct jmap *map,
  * See Also:
  *	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 *val;
 	val = (unsigned long *)JudyLPrev(map->judy, index,
diff --git a/ccan/jmap/jmap_type.h b/ccan/jmap/jmap_type.h
deleted file mode 100644
index 43155a2c..00000000
--- a/ccan/jmap/jmap_type.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/* 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 */
diff --git a/ccan/jmap/test/run-access-count.c b/ccan/jmap/test/run-access-count.c
index 288e894c..d9773c9e 100644
--- a/ccan/jmap/test/run-access-count.c
+++ b/ccan/jmap/test/run-access-count.c
@@ -5,15 +5,19 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+struct map {
+	JMAP_MEMBERS(unsigned long, unsigned long);
+};
+
 int main(int argc, char *argv[])
 {
-	struct jmap *map;
+	struct map *map;
 	unsigned long *value;
 	int status;
 
 	plan_tests(9);
 
-	map = jmap_new();
+	map = jmap_new(struct map);
 	ok1(jmap_error(map) == NULL);
 	ok1(jmap_add(map, 0, 1));
 
diff --git a/ccan/jmap/test/run-ptridx-int.c b/ccan/jmap/test/run-ptridx-int.c
new file mode 100644
index 00000000..112f5cbe
--- /dev/null
+++ b/ccan/jmap/test/run-ptridx-int.c
@@ -0,0 +1,99 @@
+#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();
+}
diff --git a/ccan/jmap/test/run-ptridx-type.c b/ccan/jmap/test/run-ptridx-type.c
index 20a604a1..58c90b44 100644
--- a/ccan/jmap/test/run-ptridx-type.c
+++ b/ccan/jmap/test/run-ptridx-type.c
@@ -1,11 +1,12 @@
 #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);
+struct jmap_foo {
+	JMAP_MEMBERS(struct idx *, struct foo *);
+};
 
 #define NUM 100
 
@@ -32,70 +33,70 @@ int main(int argc, char *argv[])
 	for (i = 0; i < NUM+1; i++)
 		idx[i] = (void *)((char *)foo[i] + 1);
 
-	map = jmap_foo_new();
-	ok1(jmap_foo_error(map) == NULL);
+	map = jmap_new(struct jmap_foo);
+	ok1(jmap_error(map) == NULL);
 
-	ok1(jmap_foo_test(map, idx[NUM]) == false);
-	ok1(jmap_foo_get(map, idx[NUM]) == (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);
+	ok1(jmap_test(map, idx[NUM]) == false);
+	ok1(jmap_get(map, idx[NUM]) == (struct foo *)NULL);
+	ok1(jmap_count(map) == 0);
+	ok1(jmap_first(map) == (struct idx *)NULL);
+	ok1(jmap_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_set(map, idx[0], foo[0]) == false);
+	ok1(jmap_add(map, idx[0], foo[1]) == true);
+	ok1(jmap_get(map, idx[0]) == foo[1]);
+	ok1(jmap_set(map, idx[0], foo[0]) == true);
+	ok1(jmap_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_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_foo_del(map, idx[0]) == true);
-	ok1(jmap_foo_test(map, idx[0]) == false);
-	ok1(jmap_foo_count(map) == 0);
+	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_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_foo_next(map, idx[0]) == idx[1]);
-	ok1(jmap_foo_next(map, idx[NUM-1]) == NULL);
+	ok1(jmap_first(map) == idx[0]);
+	ok1(jmap_next(map, idx[0]) == idx[1]);
+	ok1(jmap_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);
+	ok1(jmap_get(map, idx[0]) == foo[0]);
+	ok1(jmap_get(map, idx[NUM-1]) == foo[NUM-1]);
+	ok1(jmap_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]);
+		foop = jmap_getval(map, idx[i]);
 		ok1(*foop == foo[i]);
 		*foop = foo[NUM-1-i];
-		jmap_foo_putval(map, &foop);
+		jmap_putval(map, &foop);
 	}
 	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(*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(*foop == foo[NUM-2]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
 	index = idx[NUM-1];
-	foop = jmap_foo_nextval(map, &index);
+	foop = jmap_nextval(map, &index);
 	ok1(foop == NULL);
 
-	ok1(jmap_foo_error(map) == NULL);
-	jmap_foo_free(map);
+	ok1(jmap_error(map) == NULL);
+	jmap_free(map);
 
 	for (i = 0; i < NUM+1; i++)
 		free(foo[i]);
diff --git a/ccan/jmap/test/run-uintidx-type.c b/ccan/jmap/test/run-uintidx-type.c
index 2a371427..7427d33c 100644
--- a/ccan/jmap/test/run-uintidx-type.c
+++ b/ccan/jmap/test/run-uintidx-type.c
@@ -1,10 +1,11 @@
 #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);
+struct jmap_foo {
+	JMAP_MEMBERS(unsigned long, struct foo *);
+};
 
 #define NUM 100
 
@@ -14,117 +15,120 @@ int main(int argc, char *argv[])
 	struct foo *foo[NUM], **foop;
 	unsigned long i;
 
-	plan_tests(37 + NUM*2 + 19);
+	plan_tests(40 + NUM*2 + 19);
 	for (i = 0; i < NUM; i++)
 		foo[i] = malloc(20);
 
-	map = jmap_foo_new();
-	ok1(jmap_foo_error(map) == NULL);
+	map = jmap_new(struct jmap_foo);
+	ok1(jmap_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);
+	ok1(jmap_test(map, 0) == false);
+	ok1(jmap_get(map, 0) == (struct foo *)NULL);
+	ok1(jmap_popcount(map, 0, -1) == 0);
+	ok1(jmap_first(map) == 0);
+	ok1(jmap_last(map) == 0);
+	ok1(jmap_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);
+	ok1(jmap_set(map, 1, foo[0]) == false);
+	ok1(jmap_add(map, 1, foo[1]) == true);
+	ok1(jmap_get(map, 1) == foo[1]);
+	ok1(jmap_set(map, 1, foo[0]) == true);
+	ok1(jmap_get(map, 1) == foo[0]);
+
+	ok1(jmap_test(map, 1) == true);
+	ok1(jmap_popcount(map, 0, -1) == 1);
+	ok1(jmap_first(map) == 1);
+	ok1(jmap_last(map) == 1);
+	ok1(jmap_next(map, 0) == 1);
+	ok1(jmap_next(map, 1) == 0);
+	ok1(jmap_prev(map, 2) == 1);
+	ok1(jmap_prev(map, 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++)
-		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);
+		jmap_add(map, i+1, foo[i]);
+
+	ok1(jmap_count(map) == NUM);
+	ok1(jmap_popcount(map, 0, -1) == NUM);
+	ok1(jmap_popcount(map, 1, NUM) == NUM);
+	ok1(jmap_popcount(map, 1, NUM/2) == NUM/2);
+	ok1(jmap_popcount(map, NUM/2+1, NUM) == NUM - NUM/2);
+
+	ok1(jmap_nth(map, 0, -1) == 1);
+	ok1(jmap_nth(map, NUM-1, -1) == NUM);
+	ok1(jmap_nth(map, NUM, -1) == (size_t)-1);
+	ok1(jmap_first(map) == 1);
+	ok1(jmap_last(map) == NUM);
+	ok1(jmap_next(map, 1) == 2);
+	ok1(jmap_next(map, NUM) == 0);
+	ok1(jmap_prev(map, 2) == 1);
+	ok1(jmap_prev(map, 1) == 0);
+
+	ok1(jmap_get(map, 1) == foo[0]);
+	ok1(jmap_get(map, NUM) == foo[NUM-1]);
+	ok1(jmap_get(map, NUM+1) == NULL);
 
 	/* Reverse values in map. */
 	for (i = 0; i < NUM; i++) {
-		foop = jmap_foo_getval(map, i);
+		foop = jmap_getval(map, i+1);
 		ok1(*foop == foo[i]);
 		*foop = foo[NUM-1-i];
-		jmap_foo_putval(map, &foop);
+		jmap_putval(map, &foop);
 	}
 	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);
-	ok1(i == 0);
+	foop = jmap_nthval(map, 0, &i);
+	ok1(i == 1);
 	ok1(*foop == foo[NUM-1]);
-	jmap_foo_putval(map, &foop);
-	foop = jmap_foo_nthval(map, NUM-1, &i);
-	ok1(i == NUM-1);
+	jmap_putval(map, &foop);
+	foop = jmap_nthval(map, NUM-1, &i);
+	ok1(i == NUM);
 	ok1(*foop == foo[0]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
-	foop = jmap_foo_firstval(map, &i);
-	ok1(i == 0);
+	foop = jmap_firstval(map, &i);
+	ok1(i == 1);
 	ok1(*foop == foo[NUM-1]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
-	foop = jmap_foo_nextval(map, &i);
-	ok1(i == 1);
+	foop = jmap_nextval(map, &i);
+	ok1(i == 2);
 	ok1(*foop == foo[NUM-2]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
-	foop = jmap_foo_prevval(map, &i);
-	ok1(i == 0);
+	foop = jmap_prevval(map, &i);
+	ok1(i == 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);
 
-	foop = jmap_foo_lastval(map, &i);
-	ok1(i == NUM-1);
+	foop = jmap_lastval(map, &i);
+	ok1(i == NUM);
 	ok1(*foop == foo[0]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
-	foop = jmap_foo_prevval(map, &i);
-	ok1(i == NUM-2);
+	foop = jmap_prevval(map, &i);
+	ok1(i == NUM-1);
 	ok1(*foop == foo[1]);
-	jmap_foo_putval(map, &foop);
+	jmap_putval(map, &foop);
 
-	foop = jmap_foo_nextval(map, &i);
-	ok1(i == NUM-1);
+	foop = jmap_nextval(map, &i);
+	ok1(i == NUM);
 	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(jmap_foo_error(map) == NULL);
-	jmap_foo_free(map);
+	ok1(jmap_error(map) == NULL);
+	jmap_free(map);
 
 	for (i = 0; i < NUM; i++)
 		free(foo[i]);
diff --git a/ccan/jmap/test/run.c b/ccan/jmap/test/run.c
index e2c72ae3..3a4249dc 100644
--- a/ccan/jmap/test/run.c
+++ b/ccan/jmap/test/run.c
@@ -2,111 +2,113 @@
 #define CCAN_JMAP_DEBUG
 #include <ccan/jmap/jmap.c>
 
+struct map {
+	JMAP_MEMBERS(unsigned long, unsigned long);
+};
+
 int main(int argc, char *argv[])
 {
-	struct jmap *map;
+	struct map *map;
 	unsigned long i, *value;
 	const char *err;
 
-	plan_tests(53);
+	plan_tests(51);
 
-	map = jmap_new();
+	map = jmap_new(struct map);
 	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_get(map, 0) == 1);
+	ok1(jmap_get(map, 1) == 0);
 	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_first(map) == 0);
+	ok1(jmap_last(map) == 0);
 
 	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);
+		jmap_add(map, (i << 4) + 1, (i << 5) + 1);
 
 	/* 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, 999999 << 4, -1) == (999999 << 5) + 1);
+	ok1(jmap_get(map, 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, 0, -1) == 1);
+	ok1(jmap_nth(map, 999999, -1) == (999999 << 4) + 1);
 	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_first(map) == 1);
+	ok1(jmap_last(map) == (999999 << 4) + 1);
+	ok1(jmap_next(map, 1) == (1 << 4) + 1);
+	ok1(jmap_next(map, (999999 << 4) + 1) == 0);
+	ok1(jmap_prev(map, 2) == 1);
+	ok1(jmap_prev(map, 0) == 0);
 	ok1(jmap_error(map) == NULL);
 
 	/* Accessors. */
-	value = jmap_getval(map, 0);
+	value = jmap_getval(map, 1);
 	ok1(value && *value == 1);
 	*value = 2;
-	ok1(jmap_get(map, 0, -1) == 2);
+	ok1(jmap_get(map, 1) == 2);
 	jmap_putval(map, &value);
-	ok1(jmap_get(map, 0, -1) == 2);
-	ok1(jmap_set(map, 0, 1));
+	ok1(jmap_get(map, 1) == 2);
+	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);
 	jmap_putval(map, &value);
 
 	value = jmap_nthval(map, 0, &i);
-	ok1(i == 0);
+	ok1(i == 1);
 	ok1(value && *value == 1);
 	jmap_putval(map, &value);
 	value = jmap_nthval(map, 999999, &i);
-	ok1(i == 999999 << 4);
+	ok1(i == (999999 << 4) + 1);
 	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(i == 1);
 	ok1(value && *value == 1);
 	jmap_putval(map, &value);
 	ok1(jmap_prevval(map, &i) == NULL);
 
-	i = 0;
+	i = 1;
 	value = jmap_nextval(map, &i);
-	ok1(i == 1 << 4);
+	ok1(i == (1 << 4) + 1);
 	ok1(value && *value == (1 << 5) + 1);
 	jmap_putval(map, &value);
 
 	value = jmap_lastval(map, &i);
-	ok1(i == 999999 << 4);
+	ok1(i == (999999 << 4) + 1);
 	ok1(value && *value == (999999 << 5) + 1);
 	jmap_putval(map, &value);
 	ok1(jmap_nextval(map, &i) == NULL);
 
-	i = 999999 << 4;
+	i = (999999 << 4) + 1;
 	value = jmap_prevval(map, &i);
-	ok1(i == 999998 << 4);
+	ok1(i == (999998 << 4) + 1);
 	ok1(value && *value == (999998 << 5) + 1);
 	jmap_putval(map, &value);
 
 	/* Test error handling */
-	JU_ERRNO(&map->err) = 100;
-	JU_ERRID(&map->err) = 991;
+	JU_ERRNO(&map->raw.err) = 100;
+	JU_ERRID(&map->raw.err) = 991;
 	err = jmap_error(map);
 	ok1(err);
 	ok1(strstr(err, "100"));
 	ok1(strstr(err, "991"));
-	ok1(err == map->errstr);
+	ok1(err == map->raw.errstr);
 	jmap_free(map);
 
 	return exit_status();
diff --git a/ccan/tcon/tcon.h b/ccan/tcon/tcon.h
index 5b38c719..0f6981d9 100644
--- a/ccan/tcon/tcon.h
+++ b/ccan/tcon/tcon.h
@@ -74,8 +74,10 @@
  */
 #if HAVE_TYPEOF
 #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
 #define tcon_cast(x, canary, expr) ((void *)(expr))
+#define tcon_cast_ptr(x, canary, expr) ((void *)(expr))
 #endif
 
 #endif /* CCAN_TCON_H */
-- 
2.30.9