Browse Source

ccan: update to more recent version.

In particular, this gets some MacOS fixes from #1327.
It also includes a major intmap update which fixes corner cases in traversals,
and requires ccan/bitops.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
9c3691340f
  1. 6
      Makefile
  2. 2
      ccan/README
  3. 1
      ccan/ccan/bitops/LICENSE
  4. 43
      ccan/ccan/bitops/_info
  5. 79
      ccan/ccan/bitops/bitops.c
  6. 223
      ccan/ccan/bitops/bitops.h
  7. 89
      ccan/ccan/bitops/test/run-selftest.c
  8. 113
      ccan/ccan/bitops/test/run.c
  9. 2
      ccan/ccan/check_type/check_type.h
  10. 2
      ccan/ccan/intmap/_info
  11. 24
      ccan/ccan/intmap/benchmark/Makefile
  12. 246
      ccan/ccan/intmap/benchmark/speed.c
  13. 182
      ccan/ccan/intmap/intmap.c
  14. 89
      ccan/ccan/intmap/intmap.h
  15. 41
      ccan/ccan/intmap/test/run-after-exhaustive.c
  16. 26
      ccan/ccan/intmap/test/run-after-fail.c
  17. 34
      ccan/ccan/intmap/test/run-order.c
  18. 2
      ccan/ccan/ptr_valid/ptr_valid.c
  19. 16
      ccan/ccan/tal/grab_file/grab_file.c
  20. 3
      ccan/ccan/tal/grab_file/grab_file.h
  21. 2
      ccan/ccan/typesafe_cb/typesafe_cb.h
  22. 4
      ccan/tools/configurator/configurator.c

6
Makefile

@ -52,6 +52,7 @@ FEATURES :=
CCAN_OBJS := \ CCAN_OBJS := \
ccan-asort.o \ ccan-asort.o \
ccan-autodata.o \ ccan-autodata.o \
ccan-bitops.o \
ccan-breakpoint.o \ ccan-breakpoint.o \
ccan-crypto-hmac.o \ ccan-crypto-hmac.o \
ccan-crypto-hkdf.o \ ccan-crypto-hkdf.o \
@ -97,6 +98,7 @@ CCAN_HEADERS := \
$(CCANDIR)/ccan/array_size/array_size.h \ $(CCANDIR)/ccan/array_size/array_size.h \
$(CCANDIR)/ccan/asort/asort.h \ $(CCANDIR)/ccan/asort/asort.h \
$(CCANDIR)/ccan/autodata/autodata.h \ $(CCANDIR)/ccan/autodata/autodata.h \
$(CCANDIR)/ccan/bitops/bitops.h \
$(CCANDIR)/ccan/breakpoint/breakpoint.h \ $(CCANDIR)/ccan/breakpoint/breakpoint.h \
$(CCANDIR)/ccan/build_assert/build_assert.h \ $(CCANDIR)/ccan/build_assert/build_assert.h \
$(CCANDIR)/ccan/cast/cast.h \ $(CCANDIR)/ccan/cast/cast.h \
@ -264,7 +266,7 @@ check-cppcheck: .cppcheck-suppress
@trap 'rm -f .cppcheck-suppress' 0; git ls-files -- "*.c" "*.h" | grep -vE '^ccan/' | xargs cppcheck -q --language=c --std=c11 --error-exitcode=1 --suppressions-list=.cppcheck-suppress @trap 'rm -f .cppcheck-suppress' 0; git ls-files -- "*.c" "*.h" | grep -vE '^ccan/' | xargs cppcheck -q --language=c --std=c11 --error-exitcode=1 --suppressions-list=.cppcheck-suppress
check-shellcheck: check-shellcheck:
git ls-files -- "*.sh" | xargs shellcheck true||git ls-files -- "*.sh" | xargs shellcheck
check-source: check-makefile check-source-bolt check-whitespace check-markdown check-spelling check-python check-includes check-cppcheck check-shellcheck check-source: check-makefile check-source-bolt check-whitespace check-markdown check-spelling check-python check-includes check-cppcheck check-shellcheck
@ -540,3 +542,5 @@ ccan-mem.o: $(CCANDIR)/ccan/mem/mem.c
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
ccan-fdpass.o: $(CCANDIR)/ccan/fdpass/fdpass.c ccan-fdpass.o: $(CCANDIR)/ccan/fdpass/fdpass.c
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<
ccan-bitops.o: $(CCANDIR)/ccan/bitops/bitops.c
$(CC) $(CFLAGS) -c -o $@ $<

2
ccan/README

@ -1,3 +1,3 @@
CCAN imported from http://ccodearchive.net. CCAN imported from http://ccodearchive.net.
CCAN version: init-2405-g41a0af50 CCAN version: init-2419-g9bdb4be8

1
ccan/ccan/bitops/LICENSE

@ -0,0 +1 @@
../../licenses/CC0

43
ccan/ccan/bitops/_info

@ -0,0 +1,43 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* bitops - bit counting routines
*
* These offer convenience wrappers around (and, as necessary,
* replacements for) the builtin bit testing/counting routines.
*
* Example:
* #include <ccan/bitops/bitops.h>
* #include <stdio.h>
*
* int main(int argc, char *argv[])
* {
* unsigned int v = atoi(argv[1]);
*
* printf("Number of 1 bits: %i\n", bitops_weight32(v));
* if (v != 0) {
* printf("Least-significant set bit: %i\n", bitops_ls32(v));
* printf("Most-significant set bit: %i\n", bitops_hs32(v));
* printf("Least-significant clear bit: %i\n", bitops_lc32(v));
* printf("Most-significant clear bit: %i\n", bitops_hc32(v));
* }
* return 0;
* }
*
* License: CC0 (Public Domain)
* Author: Rusty Russell <rusty@rustcorp.com.au>
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
return 0;
}
return 1;
}

79
ccan/ccan/bitops/bitops.c

@ -0,0 +1,79 @@
/* CC0 license (public domain) - see LICENSE file for details */
#include <ccan/bitops/bitops.h>
#include <stdlib.h>
/* We do naive replacement versions: good for testing, and really your
* compiler should do better. */
#ifdef BITOPS_NEED_FFS
int bitops_ffs32(uint32_t u)
{
int i;
for (i = 0; i < 32; i++)
if (u & ((uint32_t)1 << i))
return i + 1;
return 0;
}
int bitops_ffs64(uint64_t u)
{
int i;
for (i = 0; i < 64; i++)
if (u & ((uint64_t)1 << i))
return i + 1;
return 0;
}
#endif
#ifdef BITOPS_NEED_CLZ
int bitops_clz32(uint32_t u)
{
int i;
for (i = 0; i < 32; i++)
if (u & ((uint32_t)1 << (31 - i)))
return i;
abort();
}
int bitops_clz64(uint64_t u)
{
int i;
for (i = 0; i < 64; i++)
if (u & ((uint64_t)1 << (63 - i)))
return i;
abort();
}
#endif
#ifdef BITOPS_NEED_CTZ
int bitops_ctz32(uint32_t u)
{
BITOPS_ASSERT_NONZERO(u);
return bitops_ffs32(u) - 1;
}
int bitops_ctz64(uint64_t u)
{
BITOPS_ASSERT_NONZERO(u);
return bitops_ffs64(u) - 1;
}
#endif
#ifdef BITOPS_NEED_WEIGHT
int bitops_weight32(uint32_t u)
{
int i, num = 0;
for (i = 0; i < 32; i++)
if (u & ((uint32_t)1 << i))
num++;
return num;
}
int bitops_weight64(uint64_t u)
{
int i, num = 0;
for (i = 0; i < 64; i++)
if (u & ((uint64_t)1 << i))
num++;
return num;
}
#endif

223
ccan/ccan/bitops/bitops.h

@ -0,0 +1,223 @@
/* CC0 license (public domain) - see LICENSE file for details */
#ifndef CCAN_BITOPS_H
#define CCAN_BITOPS_H
#include "config.h"
#include <stdint.h>
#if defined(CCAN_DEBUG) || defined(CCAN_BITOPS_DEBUG)
#include <assert.h>
#define BITOPS_ASSERT_NONZERO(u) assert((u) != 0)
#else
#define BITOPS_ASSERT_NONZERO(u)
#endif
#if HAVE_BUILTIN_FFS && HAVE_BUILTIN_FFSL && HAVE_BUILTIN_FFSLL
/**
* bitops_ffs32: find first set bit in a uint32_t
*
* Returns 1 for least signficant bit, 32 for most significant bit, 0
* for no bits set.
*/
static inline int bitops_ffs32(uint32_t u)
{
return __builtin_ffs(u);
}
/**
* bitops_ffs64: find lowest set bit in a uint64_t
*
* Returns 1 for least signficant bit, 32 for most significant bit, 0
* for no bits set.
*/
static inline int bitops_ffs64(uint64_t u)
{
if (sizeof(u) == sizeof(long))
return __builtin_ffsl(u);
else
return __builtin_ffsll(u);
}
#else
int bitops_ffs32(uint32_t u);
int bitops_ffs64(uint64_t u);
#define BITOPS_NEED_FFS 1
#endif
#if HAVE_BUILTIN_CLZ && HAVE_BUILTIN_CLZL && HAVE_BUILTIN_CLZLL
/**
* bitops_clz32: count leading zeros in a uint32_t (must not be 0)
*
* Returns 0 if most signficant bit is set, 31 if only least
* signficant bit is set.
*/
static inline int bitops_clz32(uint32_t u)
{
BITOPS_ASSERT_NONZERO(u);
return __builtin_clz(u);
}
/**
* bitops_clz64: count leading zeros in a uint64_t (must not be 0)
*
* Returns 0 if most signficant bit is set, 63 if only least
* signficant bit is set.
*/
static inline int bitops_clz64(uint64_t u)
{
BITOPS_ASSERT_NONZERO(u);
if (sizeof(u) == sizeof(long))
return __builtin_clzl(u);
else
return __builtin_clzll(u);
}
#else
int bitops_clz32(uint32_t u);
int bitops_clz64(uint64_t u);
#define BITOPS_NEED_CLZ 1
#endif
#if HAVE_BUILTIN_CTZ && HAVE_BUILTIN_CTZL && HAVE_BUILTIN_CTZLL
/**
* bitops_ctz32: count trailing zeros in a uint32_t (must not be 0)
*
* Returns 0 if least signficant bit is set, 31 if only most
* signficant bit is set.
*/
static inline int bitops_ctz32(uint32_t u)
{
BITOPS_ASSERT_NONZERO(u);
return __builtin_ctz(u);
}
/**
* bitops_ctz64: count trailing zeros in a uint64_t (must not be 0)
*
* Returns 0 if least signficant bit is set, 63 if only most
* signficant bit is set.
*/
static inline int bitops_ctz64(uint64_t u)
{
BITOPS_ASSERT_NONZERO(u);
if (sizeof(u) == sizeof(long))
return __builtin_ctzl(u);
else
return __builtin_ctzll(u);
}
#else
int bitops_ctz32(uint32_t u);
int bitops_ctz64(uint64_t u);
#define BITOPS_NEED_CTZ 1
#endif
/**
* bitops_ls32: find lowest set bit in a uint32_t (must not be zero)
*
* Returns 0 for least signficant bit, 31 for most significant bit.
*/
static inline int bitops_ls32(uint32_t u)
{
BITOPS_ASSERT_NONZERO(u);
return bitops_ffs32(u) - 1;
}
/**
* bitops_ls64: find lowest set bit in a uint64_t (must not be zero)
*
* Returns 0 for least signficant bit, 63 for most significant bit.
*/
static inline int bitops_ls64(uint64_t u)
{
BITOPS_ASSERT_NONZERO(u);
return bitops_ffs64(u) - 1;
}
/**
* bitops_hs32: find highest set bit in a uint32_t (must not be zero)
*
* Returns 0 for least signficant bit, 31 for most significant bit.
*/
static inline int bitops_hs32(uint32_t u)
{
BITOPS_ASSERT_NONZERO(u);
return 31 - bitops_clz32(u);
}
/**
* bitops_hs64: find highest set bit in a uint64_t (must not be zero)
*
* Returns 0 for least signficant bit, 63 for most significant bit.
*/
static inline int bitops_hs64(uint64_t u)
{
BITOPS_ASSERT_NONZERO(u);
return 63 - bitops_clz64(u);
}
/**
* bitops_lc32: find lowest clear bit in a uint32_t (must not be 0xFFFFFFFF)
*
* Returns 0 for least signficant bit, 31 for most significant bit.
*/
static inline int bitops_lc32(uint32_t u)
{
return bitops_ctz32(~u);
}
/**
* bitops_lc64: find lowest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF)
*
* Returns 0 for least signficant bit, 63 for most significant bit.
*/
static inline int bitops_lc64(uint64_t u)
{
return bitops_ctz64(~u);
}
/**
* bitops_hc32: find highest clear bit in a uint32_t (must not be 0xFFFFFFFF)
*
* Returns 0 for least signficant bit, 31 for most significant bit.
*/
static inline int bitops_hc32(uint32_t u)
{
return 31 - bitops_clz32(~u);
}
/**
* bitops_hc64: find highest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF)
*
* Returns 0 for least signficant bit, 63 for most significant bit.
*/
static inline int bitops_hc64(uint64_t u)
{
return 63 - bitops_clz64(~u);
}
#if HAVE_BUILTIN_POPCOUNT && HAVE_BUILTIN_POPCOUNTL && HAVE_BUILTIN_POPCOUNTLL
/**
* bitops_weight32: count number of bits set in a uint32_t
*
* Returns 0 to 32.
*/
static inline int bitops_weight32(uint32_t u)
{
return __builtin_popcount(u);
}
/**
* bitops_weight64: count number of bits set in a uint64_t
*
* Returns 0 to 64.
*/
static inline int bitops_weight64(uint64_t u)
{
if (sizeof(u) == sizeof(long))
return __builtin_popcountl(u);
else
return __builtin_popcountll(u);
}
#else
int bitops_weight32(uint32_t u);
int bitops_weight64(uint64_t u);
#define BITOPS_NEED_WEIGHT 1
#endif
#endif /* CCAN_BITOPS_H */

89
ccan/ccan/bitops/test/run-selftest.c

@ -0,0 +1,89 @@
#include <ccan/bitops/bitops.c>
#include <ccan/tap/tap.h>
/* Get naive versions */
#ifndef BITOPS_NEED_FFS
#define BITOPS_NEED_FFS
#endif
#ifndef BITOPS_NEED_CLZ
#define BITOPS_NEED_CLZ
#endif
#ifndef BITOPS_NEED_CTZ
#define BITOPS_NEED_CTZ
#endif
#ifndef BITOPS_NEED_WEIGHT
#define BITOPS_NEED_WEIGHT
#endif
int naive_bitops_ffs32(uint32_t u);
int naive_bitops_ffs64(uint64_t u);
int naive_bitops_clz32(uint32_t u);
int naive_bitops_clz64(uint64_t u);
int naive_bitops_ctz32(uint32_t u);
int naive_bitops_ctz64(uint64_t u);
int naive_bitops_weight32(uint32_t u);
int naive_bitops_weight64(uint64_t u);
#define bitops_ffs32 naive_bitops_ffs32
#define bitops_ffs64 naive_bitops_ffs64
#define bitops_clz32 naive_bitops_clz32
#define bitops_clz64 naive_bitops_clz64
#define bitops_ctz32 naive_bitops_ctz32
#define bitops_ctz64 naive_bitops_ctz64
#define bitops_weight32 naive_bitops_weight32
#define bitops_weight64 naive_bitops_weight64
#include <ccan/bitops/bitops.c>
static void test_against_naive32(uint32_t v)
{
ok1(bitops_ffs32(v) == naive_bitops_ffs32(v));
ok1(bitops_clz32(v) == naive_bitops_clz32(v));
ok1(bitops_ctz32(v) == naive_bitops_ctz32(v));
ok1(bitops_weight32(v) == naive_bitops_weight32(v));
}
static void test_against_naive64(uint64_t v)
{
ok1(bitops_ffs64(v) == naive_bitops_ffs64(v));
ok1(bitops_clz64(v) == naive_bitops_clz64(v));
ok1(bitops_ctz64(v) == naive_bitops_ctz64(v));
ok1(bitops_weight64(v) == naive_bitops_weight64(v));
}
int main(void)
{
int i, j;
uint64_t v;
/* This is how many tests you plan to run */
plan_tests(32 * 32 * 8 + (64 * 64) * 8 + 4 + 4);
/* Various comparisons with any one or two bits set */
for (i = 0; i < 32; i++) {
for (j = 0; j < 32; j++) {
v = ((uint64_t)1 << i) | ((uint64_t)1 << j);
test_against_naive32(v);
test_against_naive32(~v);
}
}
for (i = 0; i < 64; i++) {
for (j = 0; j < 64; j++) {
v = ((uint64_t)1 << i) | ((uint64_t)1 << j);
test_against_naive64(v);
test_against_naive64(~v);
}
}
test_against_naive64(0xFFFFFFFFFFFFFFFFULL);
ok1(bitops_ffs32(0) == naive_bitops_ffs32(0));
ok1(bitops_ffs64(0) == naive_bitops_ffs64(0));
ok1(bitops_weight32(0) == naive_bitops_weight32(0));
ok1(bitops_weight64(0) == naive_bitops_weight64(0));
/* This exits depending on whether all tests passed */
return exit_status();
}

113
ccan/ccan/bitops/test/run.c

@ -0,0 +1,113 @@
#define CCAN_BITOPS_DEBUG 1
#include <ccan/bitops/bitops.c>
#include <ccan/tap/tap.h>
int main(void)
{
int i;
/* This is how many tests you plan to run */
plan_tests(68 + 6 * (31 + 63));
for (i = 0; i < 32; i++)
ok1(bitops_ffs32(1 << i) == i+1);
ok1(bitops_ffs32(0) == 0);
for (i = 0; i < 64; i++)
ok1(bitops_ffs64((uint64_t)1 << i) == i+1);
ok1(bitops_ffs64(0) == 0);
/* Higher bits don't affect result */
for (i = 0; i < 32; i++)
ok1(bitops_ffs32(0xFFFFFFFFFFFFFFFFULL << i) == i+1);
ok1(bitops_ffs32(0) == 0);
for (i = 0; i < 64; i++)
ok1(bitops_ffs64(0xFFFFFFFFFFFFFFFFULL << i) == i+1);
ok1(bitops_ffs64(0) == 0);
for (i = 0; i < 32; i++)
ok1(bitops_clz32(1 << i) == 31 - i);
for (i = 0; i < 64; i++)
ok1(bitops_clz64((uint64_t)1 << i) == 63 - i);
/* Lower bits don't effect results */
for (i = 0; i < 32; i++)
ok1(bitops_clz32((1 << i) + (1 << i)-1) == 31 - i);
for (i = 0; i < 64; i++)
ok1(bitops_clz64(((uint64_t)1 << i) + ((uint64_t)1 << i)-1)
== 63 - i);
for (i = 0; i < 32; i++)
ok1(bitops_ctz32(1 << i) == i);
for (i = 0; i < 64; i++)
ok1(bitops_ctz64((uint64_t)1 << i) == i);
/* Higher bits don't affect result */
for (i = 0; i < 32; i++)
ok1(bitops_ctz32(0xFFFFFFFFFFFFFFFFULL << i) == i);
for (i = 0; i < 64; i++)
ok1(bitops_ctz64(0xFFFFFFFFFFFFFFFFULL << i) == i);
/* Now we've tested low-level, test higher ones */
ok1(bitops_ls32(1U) == 0);
ok1(bitops_ls32(0xFFFFFFFF) == 0);
ok1(bitops_ls32(1U << 31) == 31);
ok1(bitops_ls32(0xFFFF0000) == 16);
ok1(bitops_ls64(1U) == 0);
ok1(bitops_ls64(0xFFFFFFFF) == 0);
ok1(bitops_ls64(1U << 31) == 31);
ok1(bitops_ls64(0xFFFF0000) == 16);
ok1(bitops_ls64((uint64_t)1 << 32) == 32);
ok1(bitops_ls64((uint64_t)1 << 63) == 63);
ok1(bitops_ls64(0xFFFFFFFFFFFF0000ULL) == 16);
ok1(bitops_ls64(0xFFFF000000000000ULL) == 48);
ok1(bitops_hs32(1U) == 0);
ok1(bitops_hs32(0xFFFFFFFF) == 31);
ok1(bitops_hs32(1U << 31) == 31);
ok1(bitops_hs32(0xFFFF0000) == 31);
ok1(bitops_hs32(0x0000FFFF) == 15);
ok1(bitops_hs64(1U) == 0);
ok1(bitops_hs64(0xFFFFFFFF) == 31);
ok1(bitops_hs64(1U << 31) == 31);
ok1(bitops_hs64(0xFFFF0000) == 31);
ok1(bitops_hs32(0x0000FFFF) == 15);
ok1(bitops_hs64((uint64_t)1 << 32) == 32);
ok1(bitops_hs64((uint64_t)1 << 63) == 63);
ok1(bitops_hs64(0xFFFFFFFFFFFF0000ULL) == 63);
ok1(bitops_hs64(0x0000FFFF00000000ULL) == 47);
ok1(bitops_lc32(~(1U)) == 0);
ok1(bitops_lc32(~(0xFFFFFFFF)) == 0);
ok1(bitops_lc32(~(1U << 31)) == 31);
ok1(bitops_lc32(~(0xFFFF0000)) == 16);
ok1(bitops_lc64(~(1U)) == 0);
ok1(bitops_lc64(~(0xFFFFFFFF)) == 0);
ok1(bitops_lc64(~(1U << 31)) == 31);
ok1(bitops_lc64(~(0xFFFF0000)) == 16);
ok1(bitops_lc64(~((uint64_t)1 << 32)) == 32);
ok1(bitops_lc64(~((uint64_t)1 << 63)) == 63);
ok1(bitops_lc64(~(0xFFFFFFFFFFFF0000ULL)) == 16);
ok1(bitops_lc64(~(0xFFFF000000000000ULL)) == 48);
ok1(bitops_hc32(~(1U)) == 0);
ok1(bitops_hc32(~(0xFFFFFFFF)) == 31);
ok1(bitops_hc32(~(1U << 31)) == 31);
ok1(bitops_hc32(~(0xFFFF0000)) == 31);
ok1(bitops_hc32(~(0x0000FFFF)) == 15);
ok1(bitops_hc64(~(1ULL)) == 0);
ok1(bitops_hc64(~(0xFFFFFFFFULL)) == 31);
ok1(bitops_hc64(~(1ULL << 31)) == 31);
ok1(bitops_hc64(~(0xFFFF0000ULL)) == 31);
ok1(bitops_hc64(~(0x0000FFFFULL)) == 15);
ok1(bitops_hc64(~((uint64_t)1 << 32)) == 32);
ok1(bitops_hc64(~((uint64_t)1 << 63)) == 63);
ok1(bitops_hc64(~(0xFFFFFFFFFFFF0000ULL)) == 63);
ok1(bitops_hc64(~(0x0000FFFF00000000ULL)) == 47);
/* This exits depending on whether all tests passed */
return exit_status();
}

2
ccan/ccan/check_type/check_type.h

@ -43,7 +43,7 @@
* #define container_of(mbr_ptr, encl_type, mbr) \ * #define container_of(mbr_ptr, encl_type, mbr) \
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
* ((encl_type *) \ * ((encl_type *) \
* ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) * ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
*/ */
#if HAVE_TYPEOF #if HAVE_TYPEOF
#define check_type(expr, type) \ #define check_type(expr, type) \

2
ccan/ccan/intmap/_info

@ -22,7 +22,7 @@ int main(int argc, char *argv[])
return 1; return 1;
if (strcmp(argv[1], "depends") == 0) { if (strcmp(argv[1], "depends") == 0) {
printf("ccan/ilog\n" printf("ccan/bitops\n"
"ccan/short_types\n" "ccan/short_types\n"
"ccan/str\n" "ccan/str\n"
"ccan/tcon\n" "ccan/tcon\n"

24
ccan/ccan/intmap/benchmark/Makefile

@ -0,0 +1,24 @@
CCANDIR=../../..
CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -flto
#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR)
LDFLAGS := -flto -O3
all: speed
CCAN_OBJS:=ccan-intmap.o ccan-time.o ccan-isaac64.o ccan-htable.o ccan-siphash24.o
speed: speed.o $(CCAN_OBJS)
clean:
rm -f speed *.o
ccan-time.o: $(CCANDIR)/ccan/time/time.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-intmap.o: $(CCANDIR)/ccan/intmap/intmap.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-isaac64.o: $(CCANDIR)/ccan/isaac/isaac64.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-htable.o: $(CCANDIR)/ccan/htable/htable.c
$(CC) $(CFLAGS) -c -o $@ $<
ccan-siphash24.o: $(CCANDIR)/ccan/crypto/siphash24/siphash24.c
$(CC) $(CFLAGS) -c -o $@ $<

246
ccan/ccan/intmap/benchmark/speed.c

@ -0,0 +1,246 @@
/* Test speed of intmap */
#include <ccan/time/time.h>
#include <ccan/intmap/intmap.h>
#include <ccan/isaac/isaac64.h>
#include <ccan/htable/htable_type.h>
#include <ccan/crypto/siphash24/siphash24.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <inttypes.h>
/* hack to let us gather span. */
struct node {
/* These point to strings or nodes. */
struct intmap child[2];
/* Encoding both prefix and critbit: 1 is appended to prefix. */
intmap_index_t prefix_and_critbit;
};
static void update_span(const void *p, size_t s, uintptr_t *min, uintptr_t *max)
{
if ((uintptr_t)p < *min)
*min = (uintptr_t)p;
if ((uintptr_t)p + s > *max)
*max = (uintptr_t)p + s;
}
static void getspan(const struct intmap *m, uintptr_t *min, uintptr_t *max)
{
struct node *n;
/* Leaf node? */
if (m->v)
return;
n = m->u.n;
update_span(n, sizeof(*n), min, max);
getspan(&n->child[0], min, max);
getspan(&n->child[1], min, max);
}
struct htable_elem {
uint64_t index;
uint64_t *v;
};
static struct siphash_seed sipseed;
static uint64_t keyof(const struct htable_elem *elem)
{
return elem->index;
}
static size_t hashfn(const uint64_t index)
{
return siphash24(&sipseed, &index, sizeof(index));
}
static bool eqfn(const struct htable_elem *elem, const uint64_t index)
{
return elem->index == index;
}
HTABLE_DEFINE_TYPE(struct htable_elem, keyof, hashfn, eqfn, hash);
static bool check_val(intmap_index_t i, uint64_t *v, uint64_t *expected)
{
if (v != expected)
abort();
return true;
}
int main(int argc, char *argv[])
{
uint64_t i, total = 0, seed, *v;
size_t max = argv[1] ? atol(argv[1]) : 100000000;
isaac64_ctx isaac;
struct timeabs start, end;
UINTMAP(uint64_t *) map;
struct hash hash;
struct htable_elem *e;
struct hash_iter it;
uintptr_t span_min, span_max;
uintmap_init(&map);
hash_init(&hash);
/* We don't want our randomness function to dominate the time,
* nor deal with duplicates (just abort, that's v. unlikely) */
seed = time_now().ts.tv_sec + time_now().ts.tv_nsec;
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++)
total += isaac64_next_uint64(&isaac);
end = time_now();
printf("%zu,random generation (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
if (!uintmap_add(&map, isaac64_next_uint64(&isaac), &i))
abort();
}
end = time_now();
printf("%zu,critbit insert (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
if (uintmap_get(&map, isaac64_next_uint64(&isaac)) != &i)
abort();
}
end = time_now();
printf("%zu,critbit successful lookup (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
start = time_now();
for (i = 0; i < max; i++) {
if (uintmap_get(&map, isaac64_next_uint64(&isaac)))
abort();
}
end = time_now();
printf("%zu,critbit failed lookup (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) {
if (v != &i)
abort();
}
end = time_now();
printf("%zu,critbit iteration (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
start = time_now();
uintmap_iterate(&map, check_val, &i);
end = time_now();
printf("%zu,critbit callback iteration (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
span_min = -1ULL;
span_max = 0;
getspan(uintmap_unwrap_(&map), &span_min, &span_max);
printf("%zu,critbit memory (bytes),%zu\n",
max, (size_t)(span_max - span_min + max / 2) / max);
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
if (!uintmap_del(&map, isaac64_next_uint64(&isaac)))
abort();
}
end = time_now();
printf("%zu,critbit delete (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
/* Fill with consecutive values */
for (i = 0; i < max; i++) {
if (!uintmap_add(&map, i, &i))
abort();
}
start = time_now();
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) {
if (v != &i)
abort();
}
end = time_now();
printf("%zu,critbit consecutive iteration (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
start = time_now();
uintmap_iterate(&map, check_val, &i);
end = time_now();
printf("%zu,critbit consecutive callback iteration (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
sipseed.u.u64[0] = isaac64_next_uint64(&isaac);
sipseed.u.u64[1] = isaac64_next_uint64(&isaac);
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
e = malloc(sizeof(*e));
e->v = &i;
e->index = isaac64_next_uint64(&isaac);
hash_add(&hash, e);
}
end = time_now();
printf("%zu,hash insert (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
if (hash_get(&hash, isaac64_next_uint64(&isaac))->v != &i)
abort();
}
end = time_now();
printf("%zu,hash successful lookup (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
start = time_now();
for (i = 0; i < max; i++) {
if (hash_get(&hash, isaac64_next_uint64(&isaac)))
abort();
}
end = time_now();
printf("%zu,hash failed lookup (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it)) {
if (e->v != &i)
abort();
}
end = time_now();
printf("%zu,hash iteration (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
span_min = -1ULL;
span_max = 0;
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it))
update_span(e, sizeof(*e), &span_min, &span_max);
/* table itself tends to be allocated in separate memory. */
span_max += (sizeof(uintptr_t) << hash.raw.bits);
printf("%zu,hash memory (bytes),%zu\n",
max, (size_t)(span_max - span_min + max / 2) / max);
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed));
start = time_now();
for (i = 0; i < max; i++) {
e = hash_get(&hash, isaac64_next_uint64(&isaac));
if (!hash_del(&hash, e))
abort();
free(e);
}
end = time_now();
printf("%zu,hash delete (nsec),%"PRIu64"\n", max,
time_to_nsec(time_divide(time_between(end, start), max)));
/* Use total, but "never happens". */
return (total == 0);
}

182
ccan/ccan/intmap/intmap.c

@ -1,9 +1,9 @@
/* CC0 license (public domain) - see LICENSE file for details */ /* CC0 license (public domain) - see LICENSE file for details */
/* This code is based on ccan/strmap.c. */ /* This code is based on ccan/strmap.c. */
#include <ccan/bitops/bitops.h>
#include <ccan/intmap/intmap.h> #include <ccan/intmap/intmap.h>
#include <ccan/short_types/short_types.h> #include <ccan/short_types/short_types.h>
#include <ccan/str/str.h> #include <ccan/str/str.h>
#include <ccan/ilog/ilog.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
@ -11,28 +11,38 @@
struct node { struct node {
/* These point to strings or nodes. */ /* These point to strings or nodes. */
struct intmap child[2]; struct intmap child[2];
/* The bit where these children differ (0 == lsb) */ /* Encoding both prefix and critbit: 1 is appended to prefix. */
u8 bit_num; intmap_index_t prefix_and_critbit;
}; };
/* Closest member to this in a non-empty map. */ static int critbit(const struct intmap *n)
static struct intmap *closest(struct intmap *n, intmap_index_t index)
{ {
/* Anything with NULL value is a node. */ return bitops_ls64(n->u.n->prefix_and_critbit);
while (!n->v) {
u8 direction = (index >> n->u.n->bit_num) & 1;
n = &n->u.n->child[direction];
}
return n;
} }
void *intmap_get_(const struct intmap *map, intmap_index_t index) static intmap_index_t prefix_mask(int critbit)
{ {
struct intmap *n; /* Mask does not include critbit itself, but can't shift by critbit+1 */
return -2ULL << critbit;
}
static intmap_index_t prefix_and_critbit(intmap_index_t v, int n)
{
intmap_index_t critbit = ((intmap_index_t)1 << n);
return (v & ~(critbit - 1)) | critbit;
}
void *intmap_get_(const struct intmap *map, intmap_index_t index)
{
/* Not empty map? */ /* Not empty map? */
if (!intmap_empty_(map)) { if (!intmap_empty_(map)) {
n = closest((struct intmap *)map, index); const struct intmap *n = map;
/* Anything with NULL value is a node. */
while (!n->v) {
/* FIXME: compare cmp prefix, if not equal, ENOENT */
u8 direction = (index >> critbit(n)) & 1;
n = &n->u.n->child[direction];
}
if (index == n->u.i) if (index == n->u.i)
return n->v; return n->v;
} }
@ -40,36 +50,18 @@ void *intmap_get_(const struct intmap *map, intmap_index_t index)
return NULL; return NULL;
} }
bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value) static bool split_node(struct intmap *n, intmap_index_t nodeindex,
intmap_index_t index, const void *value)
{ {
struct intmap *n;
struct node *newn; struct node *newn;
u8 bit_num, new_dir; int new_dir;
assert(value);
/* Empty map? */
if (intmap_empty_(map)) {
map->u.i = index;
map->v = (void *)value;
return true;
}
/* Find closest existing member. */
n = closest(map, index);
/* Find highest bit where they differ. */ /* Find highest bit where they differ. */
bit_num = ilog64(n->u.i ^ index); unsigned int critbit = bitops_hs64(nodeindex ^ index);
if (bit_num == 0) { assert(critbit < CHAR_BIT*sizeof(index));
errno = EEXIST;
return false;
}
bit_num--;
assert(bit_num < CHAR_BIT*sizeof(index));
/* Which direction do we go at this bit? */ /* Which direction do we go at this bit? */
new_dir = (index >> bit_num) & 1; new_dir = (index >> critbit) & 1;
/* Allocate new node. */ /* Allocate new node. */
newn = malloc(sizeof(*newn)); newn = malloc(sizeof(*newn));
@ -77,27 +69,48 @@ bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value)
errno = ENOMEM; errno = ENOMEM;
return false; return false;
} }
newn->bit_num = bit_num; newn->prefix_and_critbit = prefix_and_critbit(index, critbit);
newn->child[new_dir].v = (void *)value; newn->child[new_dir].v = (void *)value;
newn->child[new_dir].u.i = index; newn->child[new_dir].u.i = index;
newn->child[!new_dir] = *n;
n->u.n = newn;
n->v = NULL;
return true;
}
bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value)
{
struct intmap *n;
assert(value);
/* Empty map? */
if (intmap_empty_(map)) {
map->u.i = index;
map->v = (void *)value;
return true;
}
/* Find where to insert: not closest, but first which differs! */
n = map; n = map;
/* Anything with NULL value is a node. */
while (!n->v) { while (!n->v) {
u8 direction; int crit = critbit(n);
intmap_index_t mask = prefix_mask(crit);
/* Subtle: bit numbers are "backwards" for comparison */ u8 direction = (index >> crit) & 1;
if (n->u.n->bit_num < bit_num)
break;
direction = (index >> n->u.n->bit_num) & 1; if ((index & mask) != (n->u.n->prefix_and_critbit & mask))
return split_node(n, n->u.n->prefix_and_critbit & mask,
index, value);
n = &n->u.n->child[direction]; n = &n->u.n->child[direction];
} }
newn->child[!new_dir] = *n; if (index == n->u.i) {
n->u.n = newn; errno = EEXIST;
n->v = NULL; return false;
return true; }
return split_node(n, n->u.i, index, value);
} }
void *intmap_del_(struct intmap *map, intmap_index_t index) void *intmap_del_(struct intmap *map, intmap_index_t index)
@ -116,8 +129,9 @@ void *intmap_del_(struct intmap *map, intmap_index_t index)
n = map; n = map;
/* Anything with NULL value is a node. */ /* Anything with NULL value is a node. */
while (!n->v) { while (!n->v) {
/* FIXME: compare cmp prefix, if not equal, ENOENT */
parent = n; parent = n;
direction = (index >> n->u.n->bit_num) & 1; direction = (index >> critbit(n)) & 1;
n = &n->u.n->child[direction]; n = &n->u.n->child[direction];
} }
@ -163,38 +177,58 @@ void *intmap_first_(const struct intmap *map, intmap_index_t *indexp)
void *intmap_after_(const struct intmap *map, intmap_index_t *indexp) void *intmap_after_(const struct intmap *map, intmap_index_t *indexp)
{ {
const struct intmap *n, *prev = NULL; const struct intmap *n, *prev = NULL;
intmap_index_t index = (*indexp) + 1;
/* Special case of overflow */
if (index == 0)
goto none_left;
/* Special case of empty map */ /* Special case of empty map */
if (intmap_empty_(map)) { if (intmap_empty_(map))
errno = ENOENT; goto none_left;
return NULL;
}
/* Follow down, track the last place where we could have set a bit /* Follow down, until prefix differs. */
* instead of clearing it: this is the higher alternative tree. */
n = map; n = map;
while (!n->v) { while (!n->v) {
u8 direction = (*indexp >> n->u.n->bit_num) & 1; int crit = critbit(n);
u8 direction;
intmap_index_t prefix, idx;
idx = (index >> crit);
direction = idx & 1;
/* Leave critbit in place: we can't shift by 64 anyway */
idx |= 1;
prefix = n->u.n->prefix_and_critbit >> crit;
/* If this entire tree is greater than index, take first */
if (idx < prefix)
return intmap_first_(n, indexp);
/* If this entire tree is less than index, we're past it. */
else if (idx > prefix)
goto try_greater_tree;
/* Remember greater tree for backtracking */
if (!direction) if (!direction)
prev = n; prev = n;
n = &n->u.n->child[direction]; n = &n->u.n->child[direction];
} }
/* Found a successor? */ /* Found a successor? */
if (n->u.i > *indexp) { if (n->u.i >= index) {
errno = 0; errno = 0;
*indexp = n->u.i; *indexp = n->u.i;
return n->v; return n->v;
} }
/* Nowhere to go back up to? */ try_greater_tree:
if (!prev) { /* If we ever took a lesser branch, go back to greater branch */
errno = ENOENT; if (prev)
return NULL; return intmap_first_(&prev->u.n->child[1], indexp);
}
/* Get first one from that other branch. */ none_left:
return intmap_first_(&prev->u.n->child[1], indexp); errno = ENOENT;
return NULL;
} }
void *intmap_last_(const struct intmap *map, intmap_index_t *indexp) void *intmap_last_(const struct intmap *map, intmap_index_t *indexp)
@ -230,3 +264,19 @@ void intmap_clear_(struct intmap *map)
clear(*map); clear(*map);
intmap_init_(map); intmap_init_(map);
} }
bool intmap_iterate_(const struct intmap *n,
bool (*handle)(intmap_index_t, void *, void *),
void *data,
intmap_index_t offset)
{
/* Can only happen at root */
if (intmap_empty_(n))
return true;
if (n->v)
return handle(n->u.i - offset, n->v, data);
return intmap_iterate_(&n->u.n->child[0], handle, data, offset)
&& intmap_iterate_(&n->u.n->child[1], handle, data, offset);
}

89
ccan/ccan/intmap/intmap.h

@ -335,6 +335,95 @@ void *intmap_last_(const struct intmap *map, intmap_index_t *indexp);
tcon_cast((smap), sintmap_canary, \ tcon_cast((smap), sintmap_canary, \
sintmap_last_(sintmap_unwrap_(smap), (indexp))) sintmap_last_(sintmap_unwrap_(smap), (indexp)))
/**
* uintmap_iterate - ordered iteration over an unsigned intmap
* @umap: the typed intmap to iterate through.
* @handle: the function to call.
* @arg: the argument for the function (types should match).
*
* @handle's prototype should be:
* bool @handle(intmap_index_t index, type value, typeof(arg) arg)
*
* If @handle returns false, the iteration will stop and uintmap_iterate will
* return false, otherwise uintmap_iterate will return true.
* You should not alter the map within the @handle function!
*
* Example:
* typedef UINTMAP(int *) umap_intp;
* static bool dump_some(intmap_index_t index, int *value, int *num)
* {
* // Only dump out num nodes.
* if (*(num--) == 0)
* return false;
* printf("%lu=>%i\n", (unsigned long)index, *value);
* return true;
* }
*
* static void dump_map(const umap_intp *map)
* {
* int max = 100;
* uintmap_iterate(map, dump_some, &max);
* if (max < 0)
* printf("... (truncated to 100 entries)\n");
* }
*/
#define uintmap_iterate(map, handle, arg) \
intmap_iterate_(tcon_unwrap(map), \
typesafe_cb_cast(bool (*)(intmap_index_t, \
void *, void *), \
bool (*)(intmap_index_t, \
tcon_type((map), \
uintmap_canary), \
__typeof__(arg)), (handle)), \
(arg), 0)
/**
* sintmap_iterate - ordered iteration over a signed intmap
* @smap: the typed intmap to iterate through.
* @handle: the function to call.
* @arg: the argument for the function (types should match).
*
* @handle's prototype should be:
* bool @handle(sintmap_index_t index, type value, typeof(arg) arg)
*
* If @handle returns false, the iteration will stop and sintmap_iterate will
* return false, otherwise sintmap_iterate will return true.
* You should not alter the map within the @handle function!
*
* Example:
* typedef SINTMAP(int *) smap_intp;
* static bool dump_some(sintmap_index_t index, int *value, int *num)
* {
* // Only dump out num nodes.
* if (*(num--) == 0)
* return false;
* printf("%li=>%i\n", (long)index, *value);
* return true;
* }
*
* static void dump_map(const smap_intp *map)
* {
* int max = 100;
* sintmap_iterate(map, dump_some, &max);
* if (max < 0)
* printf("... (truncated to 100 entries)\n");
* }
*/
#define sintmap_iterate(map, handle, arg) \
intmap_iterate_(tcon_unwrap(map), \
typesafe_cb_cast(bool (*)(intmap_index_t, \
void *, void *), \
bool (*)(sintmap_index_t, \
tcon_type((map), \
sintmap_canary), \
__typeof__(arg)), (handle)), \
(arg), SINTMAP_OFFSET)
bool intmap_iterate_(const struct intmap *map,
bool (*handle)(intmap_index_t, void *, void *),
void *data,
intmap_index_t offset);
/* TODO: We could implement intmap_prefix. */ /* TODO: We could implement intmap_prefix. */
/* These make sure it really is a uintmap/sintmap */ /* These make sure it really is a uintmap/sintmap */

41
ccan/ccan/intmap/test/run-after-exhaustive.c

@ -0,0 +1,41 @@
#include <ccan/bitops/bitops.h>
#include <ccan/intmap/intmap.c>
#include <ccan/tap/tap.h>
#include <stdio.h>
#define ELEMENTS 8
int main(void)
{
UINTMAP(void *) umap;
plan_tests((1 << ELEMENTS) * ELEMENTS);
/* Run through every combination of elements */
for (int i = 0; i < (1 << ELEMENTS); i++) {
/* Set up map */
uintmap_init(&umap);
for (int j = 0; j < ELEMENTS; j++) {
if ((1 << j) & i)
uintmap_add(&umap, j, &umap);
}
/* Try each uintmap_after value */
for (int j = 0; j < ELEMENTS; j++) {
intmap_index_t idx = j, next;
if ((i >> (j + 1)) == 0)
next = 0;
else
next = j + 1 + bitops_ls32(i >> (j + 1));
if (!uintmap_after(&umap, &idx))
idx = 0;
ok1(idx == next);
}
uintmap_clear(&umap);
}
/* This exits depending on whether all tests passed */
return exit_status();
}

26
ccan/ccan/intmap/test/run-after-fail.c

@ -0,0 +1,26 @@
#include <ccan/intmap/intmap.h>
#include <ccan/intmap/intmap.c>
#include <ccan/tap/tap.h>
int main(void)
{
UINTMAP(const char *) map;
u64 idx;
/* This is how many tests you plan to run */
plan_tests(2);
uintmap_init(&map);
assert(uintmap_add(&map, 0x103, "103"));
assert(uintmap_add(&map, 0x10b, "10b"));
uintmap_first(&map, &idx);
ok1(idx > 0xF);
idx = 0xF;
ok1(strcmp(uintmap_after(&map, &idx), "103") == 0);
uintmap_clear(&map);
/* This exits depending on whether all tests passed */
return exit_status();
}

34
ccan/ccan/intmap/test/run-order.c

@ -7,6 +7,16 @@
typedef UINTMAP(unsigned int *) umap; typedef UINTMAP(unsigned int *) umap;
typedef SINTMAP(int *) smap; typedef SINTMAP(int *) smap;
static bool uint_iterate_check(intmap_index_t i, unsigned int *v, int64_t *prev)
{
if ((int64_t)i <= *prev)
return false;
if (*v != i)
return false;
*prev = i;
return true;
}
static bool check_umap(const umap *map) static bool check_umap(const umap *map)
{ {
/* This is a larger type than unsigned, and allows negative */ /* This is a larger type than unsigned, and allows negative */
@ -25,7 +35,22 @@ static bool check_umap(const umap *map)
prev = i; prev = i;
last = (uintmap_last(map, &last_idx) == v); last = (uintmap_last(map, &last_idx) == v);
} }
return last;
if (!last)
return false;
prev = -1;
return uintmap_iterate(map, uint_iterate_check, &prev);
}
static bool sint_iterate_check(sintmap_index_t i, int *v, int64_t *prev)
{
if (i <= *prev)
return false;
if (*v != i)
return false;
*prev = i;
return true;
} }
static bool check_smap(const smap *map) static bool check_smap(const smap *map)
@ -45,7 +70,12 @@ static bool check_smap(const smap *map)
last = (sintmap_last(map, &last_idx) == v); last = (sintmap_last(map, &last_idx) == v);
prev = i; prev = i;
} }
return last;
if (!last)
return false;
prev = -1;
return sintmap_iterate(map, sint_iterate_check, &prev);
} }
int main(void) int main(void)

2
ccan/ccan/ptr_valid/ptr_valid.c

@ -161,7 +161,7 @@ static void finish_child(struct ptr_valid_batch *batch)
{ {
close(batch->to_child); close(batch->to_child);
close(batch->from_child); close(batch->from_child);
waitpid(batch->child_pid, NULL, 0); while (waitpid(batch->child_pid, NULL, 0) < 0 && errno == EINTR);
batch->child_pid = 0; batch->child_pid = 0;
} }

16
ccan/ccan/tal/grab_file/grab_file.c

@ -5,6 +5,7 @@
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
void *grab_fd(const void *ctx, int fd) void *grab_fd(const void *ctx, int fd)
@ -22,7 +23,12 @@ void *grab_fd(const void *ctx, int fd)
max = 16384; max = 16384;
buffer = tal_arr(ctx, char, max+1); buffer = tal_arr(ctx, char, max+1);
while ((ret = read(fd, buffer + size, max - size)) > 0) { while ((ret = read(fd, buffer + size, max - size)) != 0) {
if (ret < 0) {
if (errno == EINTR)
continue;
return tal_free(buffer);
}
size += ret; size += ret;
if (size == max) { if (size == max) {
size_t extra = max; size_t extra = max;
@ -35,12 +41,8 @@ void *grab_fd(const void *ctx, int fd)
max += extra; max += extra;
} }
} }
if (ret < 0) buffer[size] = '\0';
buffer = tal_free(buffer); tal_resize(&buffer, size+1);
else {
buffer[size] = '\0';
tal_resize(&buffer, size+1);
}
return buffer; return buffer;
} }

3
ccan/ccan/tal/grab_file/grab_file.h

@ -13,6 +13,9 @@
* tal_count() is the size in bytes plus one: for convenience, the * tal_count() is the size in bytes plus one: for convenience, the
* byte after the end of the content will always be NUL. * byte after the end of the content will always be NUL.
* *
* Note that this does *not* currently exit on EINTR, but continues
* reading.
*
* Example: * Example:
* #include <ccan/tal/str/str.h> * #include <ccan/tal/str/str.h>
* #include <ccan/tal/tal.h> * #include <ccan/tal/tal.h>

2
ccan/ccan/typesafe_cb/typesafe_cb.h

@ -27,7 +27,7 @@
* // We can take either an unsigned long or a void *. * // We can take either an unsigned long or a void *.
* void _set_some_value(void *val); * void _set_some_value(void *val);
* #define set_some_value(e) \ * #define set_some_value(e) \
* _set_some_value(typesafe_cb_cast(void *, (e), unsigned long)) * _set_some_value(typesafe_cb_cast(void *, unsigned long, (e)))
*/ */
#define typesafe_cb_cast(desttype, oktype, expr) \ #define typesafe_cb_cast(desttype, oktype, expr) \
__builtin_choose_expr( \ __builtin_choose_expr( \

4
ccan/tools/configurator/configurator.c

@ -159,8 +159,12 @@ static struct test tests[] = {
"return __builtin_ffsl(0L) == 0 ? 0 : 1;" }, "return __builtin_ffsl(0L) == 0 ? 0 : 1;" },
{ "HAVE_BUILTIN_FFSLL", INSIDE_MAIN, NULL, NULL, { "HAVE_BUILTIN_FFSLL", INSIDE_MAIN, NULL, NULL,
"return __builtin_ffsll(0LL) == 0 ? 0 : 1;" }, "return __builtin_ffsll(0LL) == 0 ? 0 : 1;" },
{ "HAVE_BUILTIN_POPCOUNT", INSIDE_MAIN, NULL, NULL,
"return __builtin_popcount(255) == 8 ? 0 : 1;" },
{ "HAVE_BUILTIN_POPCOUNTL", INSIDE_MAIN, NULL, NULL, { "HAVE_BUILTIN_POPCOUNTL", INSIDE_MAIN, NULL, NULL,
"return __builtin_popcountl(255L) == 8 ? 0 : 1;" }, "return __builtin_popcountl(255L) == 8 ? 0 : 1;" },
{ "HAVE_BUILTIN_POPCOUNTLL", INSIDE_MAIN, NULL, NULL,
"return __builtin_popcountll(255LL) == 8 ? 0 : 1;" },
{ "HAVE_BUILTIN_TYPES_COMPATIBLE_P", INSIDE_MAIN, NULL, NULL, { "HAVE_BUILTIN_TYPES_COMPATIBLE_P", INSIDE_MAIN, NULL, NULL,
"return __builtin_types_compatible_p(char *, int) ? 1 : 0;" }, "return __builtin_types_compatible_p(char *, int) ? 1 : 0;" },
{ "HAVE_ICCARM_INTRINSICS", DEFINES_FUNC, NULL, NULL, { "HAVE_ICCARM_INTRINSICS", DEFINES_FUNC, NULL, NULL,

Loading…
Cancel
Save