mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
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>
This commit is contained in:
parent
9ab28d1659
commit
9c3691340f
6
Makefile
6
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 $@ $<
|
||||
|
@ -1,3 +1,3 @@
|
||||
CCAN imported from http://ccodearchive.net.
|
||||
|
||||
CCAN version: init-2405-g41a0af50
|
||||
CCAN version: init-2419-g9bdb4be8
|
||||
|
1
ccan/ccan/bitops/LICENSE
Symbolic link
1
ccan/ccan/bitops/LICENSE
Symbolic link
@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
43
ccan/ccan/bitops/_info
Normal file
43
ccan/ccan/bitops/_info
Normal file
@ -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
Normal file
79
ccan/ccan/bitops/bitops.c
Normal file
@ -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
Normal file
223
ccan/ccan/bitops/bitops.h
Normal file
@ -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
Normal file
89
ccan/ccan/bitops/test/run-selftest.c
Normal file
@ -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
Normal file
113
ccan/ccan/bitops/test/run.c
Normal file
@ -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();
|
||||
}
|
@ -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) \
|
||||
|
@ -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"
|
||||
|
24
ccan/ccan/intmap/benchmark/Makefile
Normal file
24
ccan/ccan/intmap/benchmark/Makefile
Normal file
@ -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
Normal file
246
ccan/ccan/intmap/benchmark/speed.c
Normal file
@ -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);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
/* CC0 license (public domain) - see LICENSE file for details */
|
||||
/* This code is based on ccan/strmap.c. */
|
||||
#include <ccan/bitops/bitops.h>
|
||||
#include <ccan/intmap/intmap.h>
|
||||
#include <ccan/short_types/short_types.h>
|
||||
#include <ccan/str/str.h>
|
||||
#include <ccan/ilog/ilog.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
static intmap_index_t prefix_mask(int critbit)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
struct intmap *n;
|
||||
|
||||
/* 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,11 +50,38 @@ void *intmap_get_(const struct intmap *map, intmap_index_t index)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool split_node(struct intmap *n, intmap_index_t nodeindex,
|
||||
intmap_index_t index, const void *value)
|
||||
{
|
||||
struct node *newn;
|
||||
int new_dir;
|
||||
|
||||
/* Find highest bit where they differ. */
|
||||
unsigned int critbit = bitops_hs64(nodeindex ^ index);
|
||||
assert(critbit < CHAR_BIT*sizeof(index));
|
||||
|
||||
/* Which direction do we go at this bit? */
|
||||
new_dir = (index >> critbit) & 1;
|
||||
|
||||
/* Allocate new node. */
|
||||
newn = malloc(sizeof(*newn));
|
||||
if (!newn) {
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
struct node *newn;
|
||||
u8 bit_num, new_dir;
|
||||
|
||||
assert(value);
|
||||
|
||||
@ -55,49 +92,25 @@ bool intmap_add_(struct intmap *map, intmap_index_t index, const void *value)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Find closest existing member. */
|
||||
n = closest(map, index);
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Which direction do we go at this bit? */
|
||||
new_dir = (index >> bit_num) & 1;
|
||||
|
||||
/* Allocate new node. */
|
||||
newn = malloc(sizeof(*newn));
|
||||
if (!newn) {
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
newn->bit_num = bit_num;
|
||||
newn->child[new_dir].v = (void *)value;
|
||||
newn->child[new_dir].u.i = index;
|
||||
|
||||
/* Find where to insert: not closest, but first which differs! */
|
||||
n = map;
|
||||
/* Anything with NULL value is a node. */
|
||||
while (!n->v) {
|
||||
u8 direction;
|
||||
int crit = critbit(n);
|
||||
intmap_index_t mask = prefix_mask(crit);
|
||||
u8 direction = (index >> crit) & 1;
|
||||
|
||||
/* Subtle: bit numbers are "backwards" for comparison */
|
||||
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];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
41
ccan/ccan/intmap/test/run-after-exhaustive.c
Normal file
41
ccan/ccan/intmap/test/run-after-exhaustive.c
Normal file
@ -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
Normal file
26
ccan/ccan/intmap/test/run-after-fail.c
Normal file
@ -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();
|
||||
}
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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 <ccan/tal/str/str.h>
|
||||
* #include <ccan/tal/tal.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( \
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user