diff --git a/Makefile b/Makefile index 9d7580475..b26377f3a 100644 --- a/Makefile +++ b/Makefile @@ -52,6 +52,7 @@ FEATURES := CCAN_OBJS := \ ccan-asort.o \ ccan-autodata.o \ + ccan-bitops.o \ ccan-breakpoint.o \ ccan-crypto-hmac.o \ ccan-crypto-hkdf.o \ @@ -97,6 +98,7 @@ CCAN_HEADERS := \ $(CCANDIR)/ccan/array_size/array_size.h \ $(CCANDIR)/ccan/asort/asort.h \ $(CCANDIR)/ccan/autodata/autodata.h \ + $(CCANDIR)/ccan/bitops/bitops.h \ $(CCANDIR)/ccan/breakpoint/breakpoint.h \ $(CCANDIR)/ccan/build_assert/build_assert.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 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 @@ -540,3 +542,5 @@ ccan-mem.o: $(CCANDIR)/ccan/mem/mem.c $(CC) $(CFLAGS) -c -o $@ $< ccan-fdpass.o: $(CCANDIR)/ccan/fdpass/fdpass.c $(CC) $(CFLAGS) -c -o $@ $< +ccan-bitops.o: $(CCANDIR)/ccan/bitops/bitops.c + $(CC) $(CFLAGS) -c -o $@ $< diff --git a/ccan/README b/ccan/README index 0b0787cf9..b5e83b62d 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2405-g41a0af50 +CCAN version: init-2419-g9bdb4be8 diff --git a/ccan/ccan/bitops/LICENSE b/ccan/ccan/bitops/LICENSE new file mode 120000 index 000000000..b7951dabd --- /dev/null +++ b/ccan/ccan/bitops/LICENSE @@ -0,0 +1 @@ +../../licenses/CC0 \ No newline at end of file diff --git a/ccan/ccan/bitops/_info b/ccan/ccan/bitops/_info new file mode 100644 index 000000000..d47fe7b2c --- /dev/null +++ b/ccan/ccan/bitops/_info @@ -0,0 +1,43 @@ +#include "config.h" +#include +#include + +/** + * bitops - bit counting routines + * + * These offer convenience wrappers around (and, as necessary, + * replacements for) the builtin bit testing/counting routines. + * + * Example: + * #include + * #include + * + * 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 + */ +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; +} diff --git a/ccan/ccan/bitops/bitops.c b/ccan/ccan/bitops/bitops.c new file mode 100644 index 000000000..fef857a42 --- /dev/null +++ b/ccan/ccan/bitops/bitops.c @@ -0,0 +1,79 @@ +/* CC0 license (public domain) - see LICENSE file for details */ +#include +#include + +/* 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 diff --git a/ccan/ccan/bitops/bitops.h b/ccan/ccan/bitops/bitops.h new file mode 100644 index 000000000..899b91508 --- /dev/null +++ b/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 + +#if defined(CCAN_DEBUG) || defined(CCAN_BITOPS_DEBUG) +#include +#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 */ diff --git a/ccan/ccan/bitops/test/run-selftest.c b/ccan/ccan/bitops/test/run-selftest.c new file mode 100644 index 000000000..c3b3d2c13 --- /dev/null +++ b/ccan/ccan/bitops/test/run-selftest.c @@ -0,0 +1,89 @@ +#include +#include + +/* 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 + +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(); +} diff --git a/ccan/ccan/bitops/test/run.c b/ccan/ccan/bitops/test/run.c new file mode 100644 index 000000000..5dba932d4 --- /dev/null +++ b/ccan/ccan/bitops/test/run.c @@ -0,0 +1,113 @@ +#define CCAN_BITOPS_DEBUG 1 +#include +#include + +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(); +} diff --git a/ccan/ccan/check_type/check_type.h b/ccan/ccan/check_type/check_type.h index 77501a955..837aef7b1 100644 --- a/ccan/ccan/check_type/check_type.h +++ b/ccan/ccan/check_type/check_type.h @@ -43,7 +43,7 @@ * #define container_of(mbr_ptr, encl_type, mbr) \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * ((encl_type *) \ - * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) + * ((char *)(mbr_ptr) - offsetof(encl_type, mbr)))) */ #if HAVE_TYPEOF #define check_type(expr, type) \ diff --git a/ccan/ccan/intmap/_info b/ccan/ccan/intmap/_info index d9ba46223..1b64e1b63 100644 --- a/ccan/ccan/intmap/_info +++ b/ccan/ccan/intmap/_info @@ -22,7 +22,7 @@ int main(int argc, char *argv[]) return 1; if (strcmp(argv[1], "depends") == 0) { - printf("ccan/ilog\n" + printf("ccan/bitops\n" "ccan/short_types\n" "ccan/str\n" "ccan/tcon\n" diff --git a/ccan/ccan/intmap/benchmark/Makefile b/ccan/ccan/intmap/benchmark/Makefile new file mode 100644 index 000000000..bebc61612 --- /dev/null +++ b/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 $@ $< diff --git a/ccan/ccan/intmap/benchmark/speed.c b/ccan/ccan/intmap/benchmark/speed.c new file mode 100644 index 000000000..16eb40f35 --- /dev/null +++ b/ccan/ccan/intmap/benchmark/speed.c @@ -0,0 +1,246 @@ +/* Test speed of intmap */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); +} diff --git a/ccan/ccan/intmap/intmap.c b/ccan/ccan/intmap/intmap.c index 447f8eec4..3473ef323 100644 --- a/ccan/ccan/intmap/intmap.c +++ b/ccan/ccan/intmap/intmap.c @@ -1,9 +1,9 @@ /* CC0 license (public domain) - see LICENSE file for details */ /* This code is based on ccan/strmap.c. */ +#include #include #include #include -#include #include #include #include @@ -11,28 +11,38 @@ struct node { /* These point to strings or nodes. */ struct intmap child[2]; - /* The bit where these children differ (0 == lsb) */ - u8 bit_num; + /* Encoding both prefix and critbit: 1 is appended to prefix. */ + intmap_index_t prefix_and_critbit; }; -/* Closest member to this in a non-empty map. */ -static struct intmap *closest(struct intmap *n, intmap_index_t index) +static int critbit(const struct intmap *n) { - /* Anything with NULL value is a node. */ - while (!n->v) { - u8 direction = (index >> n->u.n->bit_num) & 1; - n = &n->u.n->child[direction]; - } - return n; + return bitops_ls64(n->u.n->prefix_and_critbit); } -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? */ 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) return n->v; } @@ -40,36 +50,18 @@ void *intmap_get_(const struct intmap *map, intmap_index_t index) 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; - u8 bit_num, new_dir; - - assert(value); - - /* Empty map? */ - if (intmap_empty_(map)) { - map->u.i = index; - map->v = (void *)value; - return true; - } - - /* Find closest existing member. */ - n = closest(map, index); + int new_dir; /* Find highest bit where they differ. */ - bit_num = ilog64(n->u.i ^ index); - if (bit_num == 0) { - errno = EEXIST; - return false; - } - bit_num--; - - assert(bit_num < CHAR_BIT*sizeof(index)); + unsigned int critbit = bitops_hs64(nodeindex ^ index); + assert(critbit < CHAR_BIT*sizeof(index)); /* Which direction do we go at this bit? */ - new_dir = (index >> bit_num) & 1; + new_dir = (index >> critbit) & 1; /* Allocate new node. */ newn = malloc(sizeof(*newn)); @@ -77,27 +69,48 @@ bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value) errno = ENOMEM; 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].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; + /* Anything with NULL value is a node. */ while (!n->v) { - u8 direction; - - /* Subtle: bit numbers are "backwards" for comparison */ - if (n->u.n->bit_num < bit_num) - break; + int crit = critbit(n); + intmap_index_t mask = prefix_mask(crit); + u8 direction = (index >> crit) & 1; - 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]; } - newn->child[!new_dir] = *n; - n->u.n = newn; - n->v = NULL; - return true; + if (index == n->u.i) { + errno = EEXIST; + return false; + } + + return split_node(n, n->u.i, index, value); } 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; /* Anything with NULL value is a node. */ while (!n->v) { + /* FIXME: compare cmp prefix, if not equal, ENOENT */ parent = n; - direction = (index >> n->u.n->bit_num) & 1; + direction = (index >> critbit(n)) & 1; 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) { 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 */ - if (intmap_empty_(map)) { - errno = ENOENT; - return NULL; - } + if (intmap_empty_(map)) + goto none_left; - /* Follow down, track the last place where we could have set a bit - * instead of clearing it: this is the higher alternative tree. */ + /* Follow down, until prefix differs. */ n = map; 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) prev = n; n = &n->u.n->child[direction]; } /* Found a successor? */ - if (n->u.i > *indexp) { + if (n->u.i >= index) { errno = 0; *indexp = n->u.i; return n->v; } - /* Nowhere to go back up to? */ - if (!prev) { - errno = ENOENT; - return NULL; - } +try_greater_tree: + /* If we ever took a lesser branch, go back to greater branch */ + if (prev) + return intmap_first_(&prev->u.n->child[1], indexp); - /* Get first one from that other branch. */ - return intmap_first_(&prev->u.n->child[1], indexp); +none_left: + errno = ENOENT; + return NULL; } void *intmap_last_(const struct intmap *map, intmap_index_t *indexp) @@ -230,3 +264,19 @@ void intmap_clear_(struct intmap *map) clear(*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); +} diff --git a/ccan/ccan/intmap/intmap.h b/ccan/ccan/intmap/intmap.h index 07a863515..7724ea255 100644 --- a/ccan/ccan/intmap/intmap.h +++ b/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, \ 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. */ /* These make sure it really is a uintmap/sintmap */ diff --git a/ccan/ccan/intmap/test/run-after-exhaustive.c b/ccan/ccan/intmap/test/run-after-exhaustive.c new file mode 100644 index 000000000..1655ddb5e --- /dev/null +++ b/ccan/ccan/intmap/test/run-after-exhaustive.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +#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(); +} diff --git a/ccan/ccan/intmap/test/run-after-fail.c b/ccan/ccan/intmap/test/run-after-fail.c new file mode 100644 index 000000000..4105b12f1 --- /dev/null +++ b/ccan/ccan/intmap/test/run-after-fail.c @@ -0,0 +1,26 @@ +#include +#include +#include + +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(); +} diff --git a/ccan/ccan/intmap/test/run-order.c b/ccan/ccan/intmap/test/run-order.c index 0f8168d7f..f7e86692a 100644 --- a/ccan/ccan/intmap/test/run-order.c +++ b/ccan/ccan/intmap/test/run-order.c @@ -7,6 +7,16 @@ typedef UINTMAP(unsigned int *) umap; 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) { /* This is a larger type than unsigned, and allows negative */ @@ -25,7 +35,22 @@ static bool check_umap(const umap *map) prev = i; 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) @@ -45,7 +70,12 @@ static bool check_smap(const smap *map) last = (sintmap_last(map, &last_idx) == v); prev = i; } - return last; + + if (!last) + return false; + + prev = -1; + return sintmap_iterate(map, sint_iterate_check, &prev); } int main(void) diff --git a/ccan/ccan/ptr_valid/ptr_valid.c b/ccan/ccan/ptr_valid/ptr_valid.c index dc61dd27c..793198402 100644 --- a/ccan/ccan/ptr_valid/ptr_valid.c +++ b/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->from_child); - waitpid(batch->child_pid, NULL, 0); + while (waitpid(batch->child_pid, NULL, 0) < 0 && errno == EINTR); batch->child_pid = 0; } diff --git a/ccan/ccan/tal/grab_file/grab_file.c b/ccan/ccan/tal/grab_file/grab_file.c index 88e7c2253..6528780a6 100644 --- a/ccan/ccan/tal/grab_file/grab_file.c +++ b/ccan/ccan/tal/grab_file/grab_file.c @@ -5,6 +5,7 @@ #include #include #include +#include #include void *grab_fd(const void *ctx, int fd) @@ -22,7 +23,12 @@ void *grab_fd(const void *ctx, int fd) max = 16384; 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; if (size == max) { size_t extra = max; @@ -35,12 +41,8 @@ void *grab_fd(const void *ctx, int fd) max += extra; } } - if (ret < 0) - buffer = tal_free(buffer); - else { - buffer[size] = '\0'; - tal_resize(&buffer, size+1); - } + buffer[size] = '\0'; + tal_resize(&buffer, size+1); return buffer; } diff --git a/ccan/ccan/tal/grab_file/grab_file.h b/ccan/ccan/tal/grab_file/grab_file.h index 03bf32a73..2eb1a0082 100644 --- a/ccan/ccan/tal/grab_file/grab_file.h +++ b/ccan/ccan/tal/grab_file/grab_file.h @@ -13,6 +13,9 @@ * tal_count() is the size in bytes plus one: for convenience, the * byte after the end of the content will always be NUL. * + * Note that this does *not* currently exit on EINTR, but continues + * reading. + * * Example: * #include * #include diff --git a/ccan/ccan/typesafe_cb/typesafe_cb.h b/ccan/ccan/typesafe_cb/typesafe_cb.h index 942d5c2d1..126d325c7 100644 --- a/ccan/ccan/typesafe_cb/typesafe_cb.h +++ b/ccan/ccan/typesafe_cb/typesafe_cb.h @@ -27,7 +27,7 @@ * // We can take either an unsigned long or a void *. * void _set_some_value(void *val); * #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) \ __builtin_choose_expr( \ diff --git a/ccan/tools/configurator/configurator.c b/ccan/tools/configurator/configurator.c index ff9f64904..ecf8f9f5f 100644 --- a/ccan/tools/configurator/configurator.c +++ b/ccan/tools/configurator/configurator.c @@ -159,8 +159,12 @@ static struct test tests[] = { "return __builtin_ffsl(0L) == 0 ? 0 : 1;" }, { "HAVE_BUILTIN_FFSLL", INSIDE_MAIN, NULL, NULL, "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, "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, "return __builtin_types_compatible_p(char *, int) ? 1 : 0;" }, { "HAVE_ICCARM_INTRINSICS", DEFINES_FUNC, NULL, NULL,