mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-03-16 06:49:19 +08:00
Revert "Update CCAN code snippets"
This reverts commit d78f57994a.
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
2
NEWS
2
NEWS
@@ -1,6 +1,4 @@
|
||||
* Version 1.1.7 (released 2023-05-07)
|
||||
- Move vendored CCAN hex code snippet from src/occtl to src/ccan.
|
||||
- Update vendored CCAN code snippets.
|
||||
- Emit a LOG_ERR error message with plain authentication fails
|
||||
- The bundled inih was updated to r56.
|
||||
- The bundled protobuf-c was updated to 1.4.1.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
|
||||
* }
|
||||
*/
|
||||
#define COLD __attribute__((__cold__))
|
||||
#define COLD __attribute__((cold))
|
||||
#else
|
||||
#define COLD
|
||||
#endif
|
||||
@@ -37,7 +37,7 @@
|
||||
* exit(1);
|
||||
* }
|
||||
*/
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
#define NORETURN
|
||||
#endif
|
||||
@@ -71,24 +71,10 @@
|
||||
* same value for the exact same arguments. This implies that the function
|
||||
* must not use global variables, or dereference pointer arguments.
|
||||
*/
|
||||
#define CONST_FUNCTION __attribute__((__const__))
|
||||
#define CONST_FUNCTION __attribute__((const))
|
||||
#else
|
||||
#define CONST_FUNCTION
|
||||
#endif
|
||||
|
||||
#ifndef PURE_FUNCTION
|
||||
#if HAVE_ATTRIBUTE_PURE
|
||||
/**
|
||||
* PURE_FUNCTION - a function is pure
|
||||
*
|
||||
* A pure function is one that has no side effects other than it's return value
|
||||
* and uses no inputs other than it's arguments and global variables.
|
||||
*/
|
||||
#define PURE_FUNCTION __attribute__((__pure__))
|
||||
#else
|
||||
#define PURE_FUNCTION
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if HAVE_ATTRIBUTE_UNUSED
|
||||
@@ -109,7 +95,7 @@
|
||||
* counter += add;
|
||||
* }
|
||||
*/
|
||||
#define UNNEEDED __attribute__((__unused__))
|
||||
#define UNNEEDED __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#ifndef NEEDED
|
||||
@@ -128,10 +114,10 @@
|
||||
* printf("Counter is %i\n", counter);
|
||||
* }
|
||||
*/
|
||||
#define NEEDED __attribute__((__used__))
|
||||
#define NEEDED __attribute__((used))
|
||||
#else
|
||||
/* Before used, unused functions and vars were always emitted. */
|
||||
#define NEEDED __attribute__((__unused__))
|
||||
#define NEEDED __attribute__((unused))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -150,7 +136,7 @@
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
#define UNUSED __attribute__((__unused__))
|
||||
#define UNUSED __attribute__((unused))
|
||||
#endif
|
||||
#else
|
||||
#ifndef UNNEEDED
|
||||
@@ -223,95 +209,9 @@
|
||||
* return realloc(buf, (*size) *= 2);
|
||||
* }
|
||||
*/
|
||||
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
|
||||
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if HAVE_ATTRIBUTE_DEPRECATED
|
||||
/**
|
||||
* WARN_DEPRECATED - warn that a function/type/variable is deprecated when used.
|
||||
*
|
||||
* Used to mark a function, type or variable should not be used.
|
||||
*
|
||||
* Example:
|
||||
* WARN_DEPRECATED char *oldfunc(char *buf);
|
||||
*/
|
||||
#define WARN_DEPRECATED __attribute__((__deprecated__))
|
||||
#else
|
||||
#define WARN_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
#if HAVE_ATTRIBUTE_NONNULL
|
||||
/**
|
||||
* NO_NULL_ARGS - specify that no arguments to this function can be NULL.
|
||||
*
|
||||
* The compiler will warn if any pointer args are NULL.
|
||||
*
|
||||
* Example:
|
||||
* NO_NULL_ARGS char *my_copy(char *buf);
|
||||
*/
|
||||
#define NO_NULL_ARGS __attribute__((__nonnull__))
|
||||
|
||||
/**
|
||||
* NON_NULL_ARGS - specify that some arguments to this function can't be NULL.
|
||||
* @...: 1-based argument numbers for which args can't be NULL.
|
||||
*
|
||||
* The compiler will warn if any of the specified pointer args are NULL.
|
||||
*
|
||||
* Example:
|
||||
* char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
|
||||
*/
|
||||
#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
|
||||
#else
|
||||
#define NO_NULL_ARGS
|
||||
#define NON_NULL_ARGS(...)
|
||||
#endif
|
||||
|
||||
#if HAVE_ATTRIBUTE_RETURNS_NONNULL
|
||||
/**
|
||||
* RETURNS_NONNULL - specify that this function cannot return NULL.
|
||||
*
|
||||
* Mainly an optimization opportunity, but can also suppress warnings.
|
||||
*
|
||||
* Example:
|
||||
* RETURNS_NONNULL char *my_copy(char *buf);
|
||||
*/
|
||||
#define RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
#else
|
||||
#define RETURNS_NONNULL
|
||||
#endif
|
||||
|
||||
#if HAVE_ATTRIBUTE_SENTINEL
|
||||
/**
|
||||
* LAST_ARG_NULL - specify the last argument of a variadic function must be NULL.
|
||||
*
|
||||
* The compiler will warn if the last argument isn't NULL.
|
||||
*
|
||||
* Example:
|
||||
* char *join_string(char *buf, ...) LAST_ARG_NULL;
|
||||
*/
|
||||
#define LAST_ARG_NULL __attribute__((__sentinel__))
|
||||
#else
|
||||
#define LAST_ARG_NULL
|
||||
#endif
|
||||
|
||||
#if HAVE_BUILTIN_CPU_SUPPORTS
|
||||
/**
|
||||
* cpu_supports - test if current CPU supports the named feature.
|
||||
*
|
||||
* This takes a literal string, and currently only works on glibc platforms.
|
||||
*
|
||||
* Example:
|
||||
* if (cpu_supports("mmx"))
|
||||
* printf("MMX support engaged!\n");
|
||||
*/
|
||||
#define cpu_supports(x) __builtin_cpu_supports(x)
|
||||
#else
|
||||
#define cpu_supports(x) 0
|
||||
#endif /* HAVE_BUILTIN_CPU_SUPPORTS */
|
||||
|
||||
#endif /* CCAN_COMPILER_H */
|
||||
|
||||
@@ -36,42 +36,6 @@
|
||||
- container_off(containing_type, member)) \
|
||||
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
||||
|
||||
|
||||
/**
|
||||
* container_of_or_null - get pointer to enclosing structure, or NULL
|
||||
* @member_ptr: pointer to the structure member
|
||||
* @containing_type: the type this member is within
|
||||
* @member: the name of this member within the structure.
|
||||
*
|
||||
* Given a pointer to a member of a structure, this macro does pointer
|
||||
* subtraction to return the pointer to the enclosing type, unless it
|
||||
* is given NULL, in which case it also returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* struct foo {
|
||||
* int fielda, fieldb;
|
||||
* // ...
|
||||
* };
|
||||
* struct info {
|
||||
* int some_other_field;
|
||||
* struct foo my_foo;
|
||||
* };
|
||||
*
|
||||
* static struct info *foo_to_info_allowing_null(struct foo *foo)
|
||||
* {
|
||||
* return container_of_or_null(foo, struct info, my_foo);
|
||||
* }
|
||||
*/
|
||||
static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
||||
{
|
||||
return member_ptr ? (char *)member_ptr - offset : NULL;
|
||||
}
|
||||
#define container_of_or_null(member_ptr, containing_type, member) \
|
||||
((containing_type *) \
|
||||
container_of_or_null_(member_ptr, \
|
||||
container_off(containing_type, member)) \
|
||||
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
||||
|
||||
/**
|
||||
* container_off - get offset to enclosing structure
|
||||
* @containing_type: the type this member is within
|
||||
@@ -139,7 +103,7 @@ static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
||||
container_off(typeof(*var), member)
|
||||
#else
|
||||
#define container_off_var(var, member) \
|
||||
((const char *)&(var)->member - (const char *)(var))
|
||||
((char *)&(var)->member - (char *)(var))
|
||||
#endif
|
||||
|
||||
#endif /* CCAN_CONTAINER_OF_H */
|
||||
|
||||
@@ -280,7 +280,7 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t *val2 )
|
||||
* rest of the string. Every machine with memory protection I've seen
|
||||
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||
* still catch it and complain. The masking trick does make the hash
|
||||
* noticeably faster for short strings (like English words).
|
||||
* noticably faster for short strings (like English words).
|
||||
*
|
||||
* Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
|
||||
*/
|
||||
@@ -457,7 +457,7 @@ static uint32_t hashbig( const void *key, size_t length, uint32_t *val2)
|
||||
* rest of the string. Every machine with memory protection I've seen
|
||||
* does it on word boundaries, so is OK with this. But VALGRIND will
|
||||
* still catch it and complain. The masking trick does make the hash
|
||||
* noticeably faster for short strings (like English words).
|
||||
* noticably faster for short strings (like English words).
|
||||
*
|
||||
* Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
|
||||
*/
|
||||
@@ -710,216 +710,3 @@ uint64_t hash64_any(const void *key, size_t length, uint64_t base)
|
||||
return ((uint64_t)b32 << 32) | lower;
|
||||
}
|
||||
|
||||
#ifdef SELF_TEST
|
||||
|
||||
/* used for timings */
|
||||
void driver1()
|
||||
{
|
||||
uint8_t buf[256];
|
||||
uint32_t i;
|
||||
uint32_t h=0;
|
||||
time_t a,z;
|
||||
|
||||
time(&a);
|
||||
for (i=0; i<256; ++i) buf[i] = 'x';
|
||||
for (i=0; i<1; ++i)
|
||||
{
|
||||
h = hashlittle(&buf[0],1,h);
|
||||
}
|
||||
time(&z);
|
||||
if (z-a > 0) printf("time %d %.8x\n", z-a, h);
|
||||
}
|
||||
|
||||
/* check that every input bit changes every output bit half the time */
|
||||
#define HASHSTATE 1
|
||||
#define HASHLEN 1
|
||||
#define MAXPAIR 60
|
||||
#define MAXLEN 70
|
||||
void driver2()
|
||||
{
|
||||
uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
|
||||
uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
|
||||
uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
|
||||
uint32_t x[HASHSTATE],y[HASHSTATE];
|
||||
uint32_t hlen;
|
||||
|
||||
printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
|
||||
for (hlen=0; hlen < MAXLEN; ++hlen)
|
||||
{
|
||||
z=0;
|
||||
for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
|
||||
{
|
||||
for (j=0; j<8; ++j) /*------------------------ for each input bit, */
|
||||
{
|
||||
for (m=1; m<8; ++m) /*------------ for several possible initvals, */
|
||||
{
|
||||
for (l=0; l<HASHSTATE; ++l)
|
||||
e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
|
||||
|
||||
/*---- check that every output bit is affected by that input bit */
|
||||
for (k=0; k<MAXPAIR; k+=2)
|
||||
{
|
||||
uint32_t finished=1;
|
||||
/* keys have one bit different */
|
||||
for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
|
||||
/* have a and b be two keys differing in only one bit */
|
||||
a[i] ^= (k<<j);
|
||||
a[i] ^= (k>>(8-j));
|
||||
c[0] = hashlittle(a, hlen, m);
|
||||
b[i] ^= ((k+1)<<j);
|
||||
b[i] ^= ((k+1)>>(8-j));
|
||||
d[0] = hashlittle(b, hlen, m);
|
||||
/* check every bit is 1, 0, set, and not set at least once */
|
||||
for (l=0; l<HASHSTATE; ++l)
|
||||
{
|
||||
e[l] &= (c[l]^d[l]);
|
||||
f[l] &= ~(c[l]^d[l]);
|
||||
g[l] &= c[l];
|
||||
h[l] &= ~c[l];
|
||||
x[l] &= d[l];
|
||||
y[l] &= ~d[l];
|
||||
if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
|
||||
}
|
||||
if (finished) break;
|
||||
}
|
||||
if (k>z) z=k;
|
||||
if (k==MAXPAIR)
|
||||
{
|
||||
printf("Some bit didn't change: ");
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
|
||||
e[0],f[0],g[0],h[0],x[0],y[0]);
|
||||
printf("i %d j %d m %d len %d\n", i, j, m, hlen);
|
||||
}
|
||||
if (z==MAXPAIR) goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (z < MAXPAIR)
|
||||
{
|
||||
printf("Mix success %2d bytes %2d initvals ",i,m);
|
||||
printf("required %d trials\n", z/2);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Check for reading beyond the end of the buffer and alignment problems */
|
||||
void driver3()
|
||||
{
|
||||
uint8_t buf[MAXLEN+20], *b;
|
||||
uint32_t len;
|
||||
uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
|
||||
uint32_t h;
|
||||
uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
|
||||
uint32_t i;
|
||||
uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
|
||||
uint32_t j;
|
||||
uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
|
||||
uint32_t ref,x,y;
|
||||
uint8_t *p;
|
||||
|
||||
printf("Endianness. These lines should all be the same (for values filled in):\n");
|
||||
printf("%.8x %.8x %.8x\n",
|
||||
hash_word((const uint32_t *)q, (sizeof(q)-1)/4, 13),
|
||||
hash_word((const uint32_t *)q, (sizeof(q)-5)/4, 13),
|
||||
hash_word((const uint32_t *)q, (sizeof(q)-9)/4, 13));
|
||||
p = q;
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||
p = &qq[1];
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||
p = &qqq[2];
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||
p = &qqqq[3];
|
||||
printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
|
||||
hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
|
||||
hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
|
||||
hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
|
||||
hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
|
||||
hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
|
||||
hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
|
||||
printf("\n");
|
||||
|
||||
/* check that hashlittle2 and hashlittle produce the same results */
|
||||
i=47; j=0;
|
||||
hashlittle2(q, sizeof(q), &i, &j);
|
||||
if (hashlittle(q, sizeof(q), 47) != i)
|
||||
printf("hashlittle2 and hashlittle mismatch\n");
|
||||
|
||||
/* check that hash_word2 and hash_word produce the same results */
|
||||
len = 0xdeadbeef;
|
||||
i=47, j=0;
|
||||
hash_word2(&len, 1, &i, &j);
|
||||
if (hash_word(&len, 1, 47) != i)
|
||||
printf("hash_word2 and hash_word mismatch %x %x\n",
|
||||
i, hash_word(&len, 1, 47));
|
||||
|
||||
/* check hashlittle doesn't read before or after the ends of the string */
|
||||
for (h=0, b=buf+1; h<8; ++h, ++b)
|
||||
{
|
||||
for (i=0; i<MAXLEN; ++i)
|
||||
{
|
||||
len = i;
|
||||
for (j=0; j<i; ++j) *(b+j)=0;
|
||||
|
||||
/* these should all be equal */
|
||||
ref = hashlittle(b, len, (uint32_t)1);
|
||||
*(b+i)=(uint8_t)~0;
|
||||
*(b-1)=(uint8_t)~0;
|
||||
x = hashlittle(b, len, (uint32_t)1);
|
||||
y = hashlittle(b, len, (uint32_t)1);
|
||||
if ((ref != x) || (ref != y))
|
||||
{
|
||||
printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
|
||||
h, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check for problems with nulls */
|
||||
void driver4()
|
||||
{
|
||||
uint8_t buf[1];
|
||||
uint32_t h,i,state[HASHSTATE];
|
||||
|
||||
|
||||
buf[0] = ~0;
|
||||
for (i=0; i<HASHSTATE; ++i) state[i] = 1;
|
||||
printf("These should all be different\n");
|
||||
for (i=0, h=0; i<8; ++i)
|
||||
{
|
||||
h = hashlittle(buf, 0, h);
|
||||
printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
driver1(); /* test that the key is hashed: used for timings */
|
||||
driver2(); /* test that whole key is hashed thoroughly */
|
||||
driver3(); /* test that nothing but the key is hashed */
|
||||
driver4(); /* test hashing multiple buffers (all buffers are null) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* SELF_TEST */
|
||||
|
||||
@@ -1,43 +1,16 @@
|
||||
/* Licensed under LGPLv2+ - see LICENSE file for details */
|
||||
#include <config.h>
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define COLD
|
||||
|
||||
/* We use 0x1 as deleted marker. */
|
||||
#define HTABLE_DELETED (0x1)
|
||||
|
||||
/* perfect_bitnum 63 means there's no perfect bitnum */
|
||||
#define NO_PERFECT_BIT (sizeof(uintptr_t) * CHAR_BIT - 1)
|
||||
|
||||
static void *htable_default_alloc(struct htable *ht, size_t len)
|
||||
{
|
||||
return calloc(len, 1);
|
||||
}
|
||||
|
||||
static void htable_default_free(struct htable *ht, void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
static void *(*htable_alloc)(struct htable *, size_t) = htable_default_alloc;
|
||||
static void (*htable_free)(struct htable *, void *) = htable_default_free;
|
||||
|
||||
void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
|
||||
void (*free)(struct htable *, void *p))
|
||||
{
|
||||
if (!alloc)
|
||||
alloc = htable_default_alloc;
|
||||
if (!free)
|
||||
free = htable_default_free;
|
||||
htable_alloc = alloc;
|
||||
htable_free = free;
|
||||
}
|
||||
|
||||
/* We clear out the bits which are always the same, and put metadata there. */
|
||||
static inline uintptr_t get_extra_ptr_bits(const struct htable *ht,
|
||||
uintptr_t e)
|
||||
@@ -61,11 +34,6 @@ static inline bool entry_is_valid(uintptr_t e)
|
||||
return e > HTABLE_DELETED;
|
||||
}
|
||||
|
||||
static inline uintptr_t ht_perfect_mask(const struct htable *ht)
|
||||
{
|
||||
return (uintptr_t)2 << ht->perfect_bitnum;
|
||||
}
|
||||
|
||||
static inline uintptr_t get_hash_ptr_bits(const struct htable *ht,
|
||||
size_t hash)
|
||||
{
|
||||
@@ -73,7 +41,7 @@ static inline uintptr_t get_hash_ptr_bits(const struct htable *ht,
|
||||
* end is quite expensive. But the lower bits are redundant, so
|
||||
* we fold the value first. */
|
||||
return (hash ^ (hash >> ht->bits))
|
||||
& ht->common_mask & ~ht_perfect_mask(ht);
|
||||
& ht->common_mask & ~ht->perfect_bit;
|
||||
}
|
||||
|
||||
void htable_init(struct htable *ht,
|
||||
@@ -83,62 +51,16 @@ void htable_init(struct htable *ht,
|
||||
*ht = empty;
|
||||
ht->rehash = rehash;
|
||||
ht->priv = priv;
|
||||
ht->table = &ht->common_bits;
|
||||
}
|
||||
|
||||
/* Fill to 87.5% */
|
||||
static inline size_t ht_max(const struct htable *ht)
|
||||
{
|
||||
return ((size_t)7 << ht->bits) / 8;
|
||||
}
|
||||
|
||||
/* Clean deleted if we're full, and more than 12.5% deleted */
|
||||
static inline size_t ht_max_deleted(const struct htable *ht)
|
||||
{
|
||||
return ((size_t)1 << ht->bits) / 8;
|
||||
}
|
||||
|
||||
bool htable_init_sized(struct htable *ht,
|
||||
size_t (*rehash)(const void *, void *),
|
||||
void *priv, size_t expect)
|
||||
{
|
||||
htable_init(ht, rehash, priv);
|
||||
|
||||
/* Don't go insane with sizing. */
|
||||
for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) {
|
||||
if (ht->bits == 30)
|
||||
break;
|
||||
}
|
||||
|
||||
ht->table = htable_alloc(ht, sizeof(size_t) << ht->bits);
|
||||
if (!ht->table) {
|
||||
ht->table = &ht->common_bits;
|
||||
return false;
|
||||
}
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
return true;
|
||||
ht->table = &ht->perfect_bit;
|
||||
}
|
||||
|
||||
void htable_clear(struct htable *ht)
|
||||
{
|
||||
if (ht->table != &ht->common_bits)
|
||||
htable_free(ht, (void *)ht->table);
|
||||
if (ht->table != &ht->perfect_bit)
|
||||
free((void *)ht->table);
|
||||
htable_init(ht, ht->rehash, ht->priv);
|
||||
}
|
||||
|
||||
bool htable_copy_(struct htable *dst, const struct htable *src)
|
||||
{
|
||||
uintptr_t *htable = htable_alloc(dst, sizeof(size_t) << src->bits);
|
||||
|
||||
if (!htable)
|
||||
return false;
|
||||
|
||||
*dst = *src;
|
||||
dst->table = htable;
|
||||
memcpy(dst->table, src->table, sizeof(size_t) << src->bits);
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t hash_bucket(const struct htable *ht, size_t h)
|
||||
{
|
||||
return h & ((1 << ht->bits)-1);
|
||||
@@ -160,21 +82,21 @@ static void *htable_val(const struct htable *ht,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *htable_firstval_(const struct htable *ht,
|
||||
void *htable_firstval(const struct htable *ht,
|
||||
struct htable_iter *i, size_t hash)
|
||||
{
|
||||
i->off = hash_bucket(ht, hash);
|
||||
return htable_val(ht, i, hash, ht_perfect_mask(ht));
|
||||
return htable_val(ht, i, hash, ht->perfect_bit);
|
||||
}
|
||||
|
||||
void *htable_nextval_(const struct htable *ht,
|
||||
void *htable_nextval(const struct htable *ht,
|
||||
struct htable_iter *i, size_t hash)
|
||||
{
|
||||
i->off = (i->off + 1) & ((1 << ht->bits)-1);
|
||||
return htable_val(ht, i, hash, 0);
|
||||
}
|
||||
|
||||
void *htable_first_(const struct htable *ht, struct htable_iter *i)
|
||||
void *htable_first(const struct htable *ht, struct htable_iter *i)
|
||||
{
|
||||
for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) {
|
||||
if (entry_is_valid(ht->table[i->off]))
|
||||
@@ -183,7 +105,7 @@ void *htable_first_(const struct htable *ht, struct htable_iter *i)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *htable_next_(const struct htable *ht, struct htable_iter *i)
|
||||
void *htable_next(const struct htable *ht, struct htable_iter *i)
|
||||
{
|
||||
for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) {
|
||||
if (entry_is_valid(ht->table[i->off]))
|
||||
@@ -192,93 +114,11 @@ void *htable_next_(const struct htable *ht, struct htable_iter *i)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *htable_prev_(const struct htable *ht, struct htable_iter *i)
|
||||
{
|
||||
for (;;) {
|
||||
if (!i->off)
|
||||
return NULL;
|
||||
i->off--;
|
||||
if (entry_is_valid(ht->table[i->off]))
|
||||
return get_raw_ptr(ht, ht->table[i->off]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Another bit currently in mask needs to be exposed, so that a bucket with p in
|
||||
* it won't appear invalid */
|
||||
static COLD void unset_another_common_bit(struct htable *ht,
|
||||
uintptr_t *maskdiff,
|
||||
const void *p)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = sizeof(uintptr_t) * CHAR_BIT - 1; i > 0; i--) {
|
||||
if (((uintptr_t)p & ((uintptr_t)1 << i))
|
||||
&& ht->common_mask & ~*maskdiff & ((uintptr_t)1 << i))
|
||||
break;
|
||||
}
|
||||
/* There must have been one, right? */
|
||||
assert(i > 0);
|
||||
|
||||
*maskdiff |= ((uintptr_t)1 << i);
|
||||
}
|
||||
|
||||
/* We want to change the common mask: this fixes up the table */
|
||||
static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff)
|
||||
{
|
||||
size_t i;
|
||||
uintptr_t bitsdiff;
|
||||
|
||||
again:
|
||||
bitsdiff = ht->common_bits & maskdiff;
|
||||
|
||||
for (i = 0; i < (size_t)1 << ht->bits; i++) {
|
||||
uintptr_t e;
|
||||
if (!entry_is_valid(e = ht->table[i]))
|
||||
continue;
|
||||
|
||||
/* Clear the bits no longer in the mask, set them as
|
||||
* expected. */
|
||||
e &= ~maskdiff;
|
||||
e |= bitsdiff;
|
||||
/* If this made it invalid, restart with more exposed */
|
||||
if (!entry_is_valid(e)) {
|
||||
unset_another_common_bit(ht, &maskdiff, get_raw_ptr(ht, e));
|
||||
goto again;
|
||||
}
|
||||
ht->table[i] = e;
|
||||
}
|
||||
|
||||
/* Take away those bits from our mask, bits and perfect bit. */
|
||||
ht->common_mask &= ~maskdiff;
|
||||
ht->common_bits &= ~maskdiff;
|
||||
if (ht_perfect_mask(ht) & maskdiff)
|
||||
ht->perfect_bitnum = NO_PERFECT_BIT;
|
||||
}
|
||||
|
||||
/* Limited recursion */
|
||||
static void ht_add(struct htable *ht, const void *new, size_t h);
|
||||
|
||||
/* We tried to add this entry, but it looked invalid! We need to
|
||||
* let another pointer bit through mask */
|
||||
static COLD void update_common_fix_invalid(struct htable *ht, const void *p, size_t h)
|
||||
{
|
||||
uintptr_t maskdiff;
|
||||
|
||||
assert(ht->elems != 0);
|
||||
|
||||
maskdiff = 0;
|
||||
unset_another_common_bit(ht, &maskdiff, p);
|
||||
fixup_table_common(ht, maskdiff);
|
||||
|
||||
/* Now won't recurse */
|
||||
ht_add(ht, p, h);
|
||||
}
|
||||
|
||||
/* This does not expand the hash table, that's up to caller. */
|
||||
static void ht_add(struct htable *ht, const void *new, size_t h)
|
||||
{
|
||||
size_t i;
|
||||
uintptr_t perfect = ht_perfect_mask(ht);
|
||||
uintptr_t perfect = ht->perfect_bit;
|
||||
|
||||
i = hash_bucket(ht, h);
|
||||
|
||||
@@ -287,8 +127,6 @@ static void ht_add(struct htable *ht, const void *new, size_t h)
|
||||
i = (i + 1) & ((1 << ht->bits)-1);
|
||||
}
|
||||
ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect);
|
||||
if (!entry_is_valid(ht->table[i]))
|
||||
update_common_fix_invalid(ht, new, h);
|
||||
}
|
||||
|
||||
static COLD bool double_table(struct htable *ht)
|
||||
@@ -298,42 +136,42 @@ static COLD bool double_table(struct htable *ht)
|
||||
uintptr_t *oldtable, e;
|
||||
|
||||
oldtable = ht->table;
|
||||
ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1));
|
||||
ht->table = calloc(1 << (ht->bits+1), sizeof(size_t));
|
||||
if (!ht->table) {
|
||||
ht->table = oldtable;
|
||||
return false;
|
||||
}
|
||||
ht->bits++;
|
||||
ht->max = ((size_t)3 << ht->bits) / 4;
|
||||
ht->max_with_deleted = ((size_t)9 << ht->bits) / 10;
|
||||
|
||||
/* If we lost our "perfect bit", get it back now. */
|
||||
if (ht->perfect_bitnum == NO_PERFECT_BIT && ht->common_mask) {
|
||||
if (!ht->perfect_bit && ht->common_mask) {
|
||||
for (i = 0; i < sizeof(ht->common_mask) * CHAR_BIT; i++) {
|
||||
if (ht->common_mask & ((size_t)2 << i)) {
|
||||
ht->perfect_bitnum = i;
|
||||
if (ht->common_mask & ((size_t)1 << i)) {
|
||||
ht->perfect_bit = (size_t)1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldtable != &ht->common_bits) {
|
||||
if (oldtable != &ht->perfect_bit) {
|
||||
for (i = 0; i < oldnum; i++) {
|
||||
if (entry_is_valid(e = oldtable[i])) {
|
||||
void *p = get_raw_ptr(ht, e);
|
||||
ht_add(ht, p, ht->rehash(p, ht->priv));
|
||||
}
|
||||
}
|
||||
htable_free(ht, oldtable);
|
||||
free(oldtable);
|
||||
}
|
||||
ht->deleted = 0;
|
||||
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
return true;
|
||||
}
|
||||
|
||||
static COLD void rehash_table(struct htable *ht)
|
||||
{
|
||||
size_t start, i;
|
||||
uintptr_t e, perfect = ht_perfect_mask(ht);
|
||||
uintptr_t e;
|
||||
|
||||
/* Beware wrap cases: we need to start from first empty bucket. */
|
||||
for (start = 0; ht->table[start]; start++);
|
||||
@@ -345,51 +183,65 @@ static COLD void rehash_table(struct htable *ht)
|
||||
continue;
|
||||
if (e == HTABLE_DELETED)
|
||||
ht->table[h] = 0;
|
||||
else if (!(e & perfect)) {
|
||||
else if (!(e & ht->perfect_bit)) {
|
||||
void *p = get_raw_ptr(ht, e);
|
||||
ht->table[h] = 0;
|
||||
ht_add(ht, p, ht->rehash(p, ht->priv));
|
||||
}
|
||||
}
|
||||
ht->deleted = 0;
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
}
|
||||
|
||||
/* We stole some bits, now we need to put them back... */
|
||||
static COLD void update_common(struct htable *ht, const void *p)
|
||||
{
|
||||
uintptr_t maskdiff;
|
||||
unsigned int i;
|
||||
uintptr_t maskdiff, bitsdiff;
|
||||
|
||||
if (ht->elems == 0) {
|
||||
ht->common_mask = -1;
|
||||
/* Always reveal one bit of the pointer in the bucket,
|
||||
* so it's not zero or HTABLE_DELETED (1), even if
|
||||
* hash happens to be 0. Assumes (void *)1 is not a
|
||||
* valid pointer. */
|
||||
for (i = sizeof(uintptr_t)*CHAR_BIT - 1; i > 0; i--) {
|
||||
if ((uintptr_t)p & ((uintptr_t)1 << i))
|
||||
break;
|
||||
}
|
||||
|
||||
ht->common_mask = ~((uintptr_t)1 << i);
|
||||
ht->common_bits = ((uintptr_t)p & ht->common_mask);
|
||||
ht->perfect_bitnum = 0;
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
ht->perfect_bit = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find bits which are unequal to old common set. */
|
||||
maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask);
|
||||
|
||||
fixup_table_common(ht, maskdiff);
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
/* These are the bits which go there in existing entries. */
|
||||
bitsdiff = ht->common_bits & maskdiff;
|
||||
|
||||
for (i = 0; i < (size_t)1 << ht->bits; i++) {
|
||||
if (!entry_is_valid(ht->table[i]))
|
||||
continue;
|
||||
/* Clear the bits no longer in the mask, set them as
|
||||
* expected. */
|
||||
ht->table[i] &= ~maskdiff;
|
||||
ht->table[i] |= bitsdiff;
|
||||
}
|
||||
|
||||
/* Take away those bits from our mask, bits and perfect bit. */
|
||||
ht->common_mask &= ~maskdiff;
|
||||
ht->common_bits &= ~maskdiff;
|
||||
ht->perfect_bit &= ~maskdiff;
|
||||
}
|
||||
|
||||
bool htable_add_(struct htable *ht, size_t hash, const void *p)
|
||||
bool htable_add(struct htable *ht, size_t hash, const void *p)
|
||||
{
|
||||
/* Cannot insert NULL, or (void *)1. */
|
||||
assert(p);
|
||||
assert(entry_is_valid((uintptr_t)p));
|
||||
|
||||
/* Getting too full? */
|
||||
if (ht->elems+1 + ht->deleted > ht_max(ht)) {
|
||||
/* If we're more than 1/8 deleted, clean those,
|
||||
* otherwise double table size. */
|
||||
if (ht->deleted > ht_max_deleted(ht))
|
||||
rehash_table(ht);
|
||||
else if (!double_table(ht))
|
||||
if (ht->elems+1 > ht->max && !double_table(ht))
|
||||
return false;
|
||||
}
|
||||
if (ht->elems+1 + ht->deleted > ht->max_with_deleted)
|
||||
rehash_table(ht);
|
||||
assert(p);
|
||||
if (((uintptr_t)p & ht->common_mask) != ht->common_bits)
|
||||
update_common(ht, p);
|
||||
|
||||
@@ -398,7 +250,7 @@ bool htable_add_(struct htable *ht, size_t hash, const void *p)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool htable_del_(struct htable *ht, size_t h, const void *p)
|
||||
bool htable_del(struct htable *ht, size_t h, const void *p)
|
||||
{
|
||||
struct htable_iter i;
|
||||
void *c;
|
||||
@@ -412,80 +264,12 @@ bool htable_del_(struct htable *ht, size_t h, const void *p)
|
||||
return false;
|
||||
}
|
||||
|
||||
void htable_delval_(struct htable *ht, struct htable_iter *i)
|
||||
void htable_delval(struct htable *ht, struct htable_iter *i)
|
||||
{
|
||||
assert(i->off < (size_t)1 << ht->bits);
|
||||
assert(entry_is_valid(ht->table[i->off]));
|
||||
|
||||
ht->elems--;
|
||||
/* Cheap test: if the next bucket is empty, don't need delete marker */
|
||||
if (ht->table[hash_bucket(ht, i->off+1)] != 0) {
|
||||
ht->table[i->off] = HTABLE_DELETED;
|
||||
ht->deleted++;
|
||||
} else
|
||||
ht->table[i->off] = 0;
|
||||
}
|
||||
|
||||
void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i)
|
||||
{
|
||||
void *e;
|
||||
struct htable_iter unwanted;
|
||||
|
||||
if (!i)
|
||||
i = &unwanted;
|
||||
i->off = seed % ((size_t)1 << ht->bits);
|
||||
e = htable_next(ht, i);
|
||||
if (!e)
|
||||
e = htable_first(ht, i);
|
||||
return e;
|
||||
}
|
||||
|
||||
struct htable *htable_check(const struct htable *ht, const char *abortstr)
|
||||
{
|
||||
void *p;
|
||||
struct htable_iter i;
|
||||
size_t n = 0;
|
||||
|
||||
/* Use non-DEBUG versions here, to avoid infinite recursion with
|
||||
* CCAN_HTABLE_DEBUG! */
|
||||
for (p = htable_first_(ht, &i); p; p = htable_next_(ht, &i)) {
|
||||
struct htable_iter i2;
|
||||
void *c;
|
||||
size_t h = ht->rehash(p, ht->priv);
|
||||
bool found = false;
|
||||
|
||||
n++;
|
||||
|
||||
/* Open-code htable_get to avoid CCAN_HTABLE_DEBUG */
|
||||
for (c = htable_firstval_(ht, &i2, h);
|
||||
c;
|
||||
c = htable_nextval_(ht, &i2, h)) {
|
||||
if (c == p) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (abortstr) {
|
||||
fprintf(stderr,
|
||||
"%s: element %p in position %zu"
|
||||
" cannot find itself\n",
|
||||
abortstr, p, i.off);
|
||||
abort();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (n != ht->elems) {
|
||||
if (abortstr) {
|
||||
fprintf(stderr,
|
||||
"%s: found %zu elems, expected %zu\n",
|
||||
abortstr, n, ht->elems);
|
||||
abort();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct htable *)ht;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
/* Licensed under LGPLv2+ - see LICENSE file for details */
|
||||
#ifndef CCAN_HTABLE_H
|
||||
#define CCAN_HTABLE_H
|
||||
#include "config.h"
|
||||
#include <ccan/str/str.h>
|
||||
#include <config.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Define CCAN_HTABLE_DEBUG for expensive debugging checks on each call. */
|
||||
#define HTABLE_LOC __FILE__ ":" stringify(__LINE__)
|
||||
#ifdef CCAN_HTABLE_DEBUG
|
||||
#define htable_debug(h, loc) htable_check((h), loc)
|
||||
#else
|
||||
#define htable_debug(h, loc) ((void)loc, h)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct htable - private definition of a htable.
|
||||
*
|
||||
@@ -24,10 +15,11 @@
|
||||
struct htable {
|
||||
size_t (*rehash)(const void *elem, void *priv);
|
||||
void *priv;
|
||||
unsigned int bits, perfect_bitnum;
|
||||
size_t elems, deleted;
|
||||
unsigned int bits;
|
||||
size_t elems, deleted, max, max_with_deleted;
|
||||
/* These are the bits which are the same in all pointers. */
|
||||
uintptr_t common_mask, common_bits;
|
||||
uintptr_t perfect_bit;
|
||||
uintptr_t *table;
|
||||
};
|
||||
|
||||
@@ -43,13 +35,12 @@ struct htable {
|
||||
* // For simplicity's sake, say hash value is contents of elem.
|
||||
* static size_t rehash(const void *elem, void *unused)
|
||||
* {
|
||||
* (void)unused;
|
||||
* return *(size_t *)elem;
|
||||
* }
|
||||
* static struct htable ht = HTABLE_INITIALIZER(ht, rehash, NULL);
|
||||
*/
|
||||
#define HTABLE_INITIALIZER(name, rehash, priv) \
|
||||
{ rehash, priv, 0, 0, 0, 0, -1, 0, &name.common_bits }
|
||||
{ rehash, priv, 0, 0, 0, 0, 0, -1, 0, 0, &name.perfect_bit }
|
||||
|
||||
/**
|
||||
* htable_init - initialize an empty hash table.
|
||||
@@ -60,30 +51,6 @@ struct htable {
|
||||
void htable_init(struct htable *ht,
|
||||
size_t (*rehash)(const void *elem, void *priv), void *priv);
|
||||
|
||||
/**
|
||||
* htable_init_sized - initialize an empty hash table of given size.
|
||||
* @ht: the hash table to initialize
|
||||
* @rehash: hash function to use for rehashing.
|
||||
* @priv: private argument to @rehash function.
|
||||
* @size: the number of element.
|
||||
*
|
||||
* If this returns false, @ht is still usable, but may need to do reallocation
|
||||
* upon an add. If this returns true, it will not need to reallocate within
|
||||
* @size htable_adds.
|
||||
*/
|
||||
bool htable_init_sized(struct htable *ht,
|
||||
size_t (*rehash)(const void *elem, void *priv),
|
||||
void *priv, size_t size);
|
||||
|
||||
/**
|
||||
* htable_count - count number of entries in a hash table.
|
||||
* @ht: the hash table
|
||||
*/
|
||||
static inline size_t htable_count(const struct htable *ht)
|
||||
{
|
||||
return ht->elems;
|
||||
}
|
||||
|
||||
/**
|
||||
* htable_clear - empty a hash table.
|
||||
* @ht: the hash table to clear
|
||||
@@ -92,54 +59,23 @@ static inline size_t htable_count(const struct htable *ht)
|
||||
*/
|
||||
void htable_clear(struct htable *ht);
|
||||
|
||||
|
||||
/**
|
||||
* htable_check - check hash table for consistency
|
||||
* @ht: the htable
|
||||
* @abortstr: the location to print on aborting, or NULL.
|
||||
* htable_rehash - use a hashtree's rehash function
|
||||
* @elem: the argument to rehash()
|
||||
*
|
||||
* Because hash tables have redundant information, consistency checking that
|
||||
* each element is in the correct location can be done. This is useful as a
|
||||
* debugging check. If @abortstr is non-NULL, that will be printed in a
|
||||
* diagnostic if the htable is inconsistent, and the function will abort.
|
||||
*
|
||||
* Returns the htable if it is consistent, NULL if not (it can never return
|
||||
* NULL if @abortstr is set).
|
||||
*/
|
||||
struct htable *htable_check(const struct htable *ht, const char *abortstr);
|
||||
|
||||
/**
|
||||
* htable_copy - duplicate a hash table.
|
||||
* @dst: the hash table to overwrite
|
||||
* @src: the hash table to copy
|
||||
*
|
||||
* Only fails on out-of-memory.
|
||||
*
|
||||
* Equivalent to (but faster than):
|
||||
* if (!htable_init_sized(dst, src->rehash, src->priv, 1U << src->bits))
|
||||
* return false;
|
||||
* v = htable_first(src, &i);
|
||||
* while (v) {
|
||||
* htable_add(dst, v);
|
||||
* v = htable_next(src, i);
|
||||
* }
|
||||
* return true;
|
||||
*/
|
||||
#define htable_copy(dst, src) htable_copy_(dst, htable_debug(src, HTABLE_LOC))
|
||||
bool htable_copy_(struct htable *dst, const struct htable *src);
|
||||
size_t htable_rehash(const void *elem);
|
||||
|
||||
/**
|
||||
* htable_add - add a pointer into a hash table.
|
||||
* @ht: the htable
|
||||
* @hash: the hash value of the object
|
||||
* @p: the non-NULL pointer (also cannot be (void *)1).
|
||||
* @p: the non-NULL pointer
|
||||
*
|
||||
* Also note that this can only fail due to allocation failure. Otherwise, it
|
||||
* returns true.
|
||||
*/
|
||||
#define htable_add(ht, hash, p) \
|
||||
htable_add_(htable_debug(ht, HTABLE_LOC), hash, p)
|
||||
bool htable_add_(struct htable *ht, size_t hash, const void *p);
|
||||
bool htable_add(struct htable *ht, size_t hash, const void *p);
|
||||
|
||||
/**
|
||||
* htable_del - remove a pointer from a hash table
|
||||
@@ -149,9 +85,7 @@ bool htable_add_(struct htable *ht, size_t hash, const void *p);
|
||||
*
|
||||
* Returns true if the pointer was found (and deleted).
|
||||
*/
|
||||
#define htable_del(ht, hash, p) \
|
||||
htable_del_(htable_debug(ht, HTABLE_LOC), hash, p)
|
||||
bool htable_del_(struct htable *ht, size_t hash, const void *p);
|
||||
bool htable_del(struct htable *ht, size_t hash, const void *p);
|
||||
|
||||
/**
|
||||
* struct htable_iter - iterator or htable_first or htable_firstval etc.
|
||||
@@ -172,10 +106,7 @@ struct htable_iter {
|
||||
* See Also:
|
||||
* htable_delval()
|
||||
*/
|
||||
#define htable_firstval(htable, i, hash) \
|
||||
htable_firstval_(htable_debug(htable, HTABLE_LOC), i, hash)
|
||||
|
||||
void *htable_firstval_(const struct htable *htable,
|
||||
void *htable_firstval(const struct htable *htable,
|
||||
struct htable_iter *i, size_t hash);
|
||||
|
||||
/**
|
||||
@@ -186,9 +117,7 @@ void *htable_firstval_(const struct htable *htable,
|
||||
*
|
||||
* You'll need to check the value is what you want; returns NULL if no more.
|
||||
*/
|
||||
#define htable_nextval(htable, i, hash) \
|
||||
htable_nextval_(htable_debug(htable, HTABLE_LOC), i, hash)
|
||||
void *htable_nextval_(const struct htable *htable,
|
||||
void *htable_nextval(const struct htable *htable,
|
||||
struct htable_iter *i, size_t hash);
|
||||
|
||||
/**
|
||||
@@ -222,9 +151,7 @@ static inline void *htable_get(const struct htable *ht,
|
||||
*
|
||||
* Get an entry in the hashtable; NULL if empty.
|
||||
*/
|
||||
#define htable_first(htable, i) \
|
||||
htable_first_(htable_debug(htable, HTABLE_LOC), i)
|
||||
void *htable_first_(const struct htable *htable, struct htable_iter *i);
|
||||
void *htable_first(const struct htable *htable, struct htable_iter *i);
|
||||
|
||||
/**
|
||||
* htable_next - find another entry in the hash table
|
||||
@@ -234,26 +161,7 @@ void *htable_first_(const struct htable *htable, struct htable_iter *i);
|
||||
* Get another entry in the hashtable; NULL if all done.
|
||||
* This is usually used after htable_first or prior non-NULL htable_next.
|
||||
*/
|
||||
#define htable_next(htable, i) \
|
||||
htable_next_(htable_debug(htable, HTABLE_LOC), i)
|
||||
void *htable_next_(const struct htable *htable, struct htable_iter *i);
|
||||
|
||||
/**
|
||||
* htable_prev - find the previous entry in the hash table
|
||||
* @ht: the hashtable
|
||||
* @i: the struct htable_iter to use
|
||||
*
|
||||
* Get previous entry in the hashtable; NULL if all done.
|
||||
*
|
||||
* "previous" here only means the item that would have been returned by
|
||||
* htable_next() before the item it returned most recently.
|
||||
*
|
||||
* This is usually used in the middle of (or after) a htable_next iteration and
|
||||
* to "unwind" actions taken.
|
||||
*/
|
||||
#define htable_prev(htable, i) \
|
||||
htable_prev_(htable_debug(htable, HTABLE_LOC), i)
|
||||
void *htable_prev_(const struct htable *htable, struct htable_iter *i);
|
||||
void *htable_next(const struct htable *htable, struct htable_iter *i);
|
||||
|
||||
/**
|
||||
* htable_delval - remove an iterated pointer from a hash table
|
||||
@@ -263,28 +171,6 @@ void *htable_prev_(const struct htable *htable, struct htable_iter *i);
|
||||
* Usually used to delete a hash entry after it has been found with
|
||||
* htable_firstval etc.
|
||||
*/
|
||||
#define htable_delval(htable, i) \
|
||||
htable_delval_(htable_debug(htable, HTABLE_LOC), i)
|
||||
void htable_delval_(struct htable *ht, struct htable_iter *i);
|
||||
void htable_delval(struct htable *ht, struct htable_iter *i);
|
||||
|
||||
/**
|
||||
* htable_pick - set iterator to a random valid entry.
|
||||
* @ht: the htable
|
||||
* @seed: a random number to use.
|
||||
* @i: the htable_iter which is output (or NULL).
|
||||
*
|
||||
* Usually used with htable_delval to delete a random entry. Returns
|
||||
* NULL iff the table is empty, otherwise a random entry.
|
||||
*/
|
||||
#define htable_pick(htable, seed, i) \
|
||||
htable_pick_(htable_debug(htable, HTABLE_LOC), seed, i)
|
||||
void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i);
|
||||
|
||||
/**
|
||||
* htable_set_allocator - set calloc/free functions.
|
||||
* @alloc: allocator to use, must zero memory!
|
||||
* @free: unallocator to use (@p is NULL or a return from @alloc)
|
||||
*/
|
||||
void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
|
||||
void (*free)(struct htable *, void *p));
|
||||
#endif /* CCAN_HTABLE_H */
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#ifndef CCAN_HTABLE_TYPE_H
|
||||
#define CCAN_HTABLE_TYPE_H
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
@@ -21,12 +20,7 @@
|
||||
*
|
||||
* It also defines initialization and freeing functions:
|
||||
* void <name>_init(struct <name> *);
|
||||
* bool <name>_init_sized(struct <name> *, size_t);
|
||||
* void <name>_clear(struct <name> *);
|
||||
* bool <name>_copy(struct <name> *dst, const struct <name> *src);
|
||||
*
|
||||
* Count entries:
|
||||
* size_t <name>_count(const struct <name> *ht);
|
||||
*
|
||||
* Add function only fails if we run out of memory:
|
||||
* bool <name>_add(struct <name> *ht, const <type> *e);
|
||||
@@ -35,24 +29,13 @@
|
||||
* bool <name>_del(struct <name> *ht, const <type> *e);
|
||||
* bool <name>_delkey(struct <name> *ht, const <keytype> *k);
|
||||
*
|
||||
* Delete by iterator:
|
||||
* bool <name>_delval(struct <name> *ht, struct <name>_iter *i);
|
||||
*
|
||||
* Find and return the (first) matching element, or NULL:
|
||||
* Find function return the matching element, or NULL:
|
||||
* type *<name>_get(const struct @name *ht, const <keytype> *k);
|
||||
*
|
||||
* Find and return all matching elements, or NULL:
|
||||
* type *<name>_getfirst(const struct @name *ht, const <keytype> *k,
|
||||
* struct <name>_iter *i);
|
||||
* type *<name>_getnext(const struct @name *ht, const <keytype> *k,
|
||||
* struct <name>_iter *i);
|
||||
*
|
||||
* Iteration over hashtable is also supported:
|
||||
* type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
|
||||
* type *<name>_next(const struct <name> *ht, struct <name>_iter *i);
|
||||
* type *<name>_prev(const struct <name> *ht, struct <name>_iter *i);
|
||||
* type *<name>_pick(const struct <name> *ht, size_t seed,
|
||||
* struct <name>_iter *i);
|
||||
*
|
||||
* It's currently safe to iterate over a changing hashtable, but you might
|
||||
* miss an element. Iteration isn't very efficient, either.
|
||||
*
|
||||
@@ -64,126 +47,57 @@
|
||||
struct name##_iter { struct htable_iter i; }; \
|
||||
static inline size_t name##_hash(const void *elem, void *priv) \
|
||||
{ \
|
||||
(void)priv; \
|
||||
return hashfn(keyof((const type *)elem)); \
|
||||
} \
|
||||
static inline UNNEEDED void name##_init(struct name *ht) \
|
||||
static inline void name##_init(struct name *ht) \
|
||||
{ \
|
||||
htable_init(&ht->raw, name##_hash, NULL); \
|
||||
} \
|
||||
static inline UNNEEDED bool name##_init_sized(struct name *ht, \
|
||||
size_t s) \
|
||||
{ \
|
||||
return htable_init_sized(&ht->raw, name##_hash, NULL, s); \
|
||||
} \
|
||||
static inline UNNEEDED size_t name##_count(const struct name *ht) \
|
||||
{ \
|
||||
return htable_count(&ht->raw); \
|
||||
} \
|
||||
static inline UNNEEDED void name##_clear(struct name *ht) \
|
||||
static inline void name##_clear(struct name *ht) \
|
||||
{ \
|
||||
htable_clear(&ht->raw); \
|
||||
} \
|
||||
static inline UNNEEDED bool name##_copy(struct name *dst, \
|
||||
const struct name *src) \
|
||||
{ \
|
||||
return htable_copy(&dst->raw, &src->raw); \
|
||||
} \
|
||||
static inline bool name##_add(struct name *ht, const type *elem) \
|
||||
{ \
|
||||
return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \
|
||||
} \
|
||||
static inline UNNEEDED bool name##_del(struct name *ht, \
|
||||
const type *elem) \
|
||||
static inline bool name##_del(struct name *ht, const type *elem) \
|
||||
{ \
|
||||
return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_get(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof, type) k) \
|
||||
static inline type *name##_get(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k) \
|
||||
{ \
|
||||
struct htable_iter i; \
|
||||
size_t h = hashfn(k); \
|
||||
void *c; \
|
||||
\
|
||||
for (c = htable_firstval(&ht->raw,&i,h); \
|
||||
c; \
|
||||
c = htable_nextval(&ht->raw,&i,h)) { \
|
||||
if (eqfn(c, k)) \
|
||||
return c; \
|
||||
/* Typecheck for eqfn */ \
|
||||
(void)sizeof(eqfn((const type *)NULL, \
|
||||
keyof((const type *)NULL))); \
|
||||
return htable_get(&ht->raw, \
|
||||
hashfn(k), \
|
||||
(bool (*)(const void *, void *))(eqfn), \
|
||||
k); \
|
||||
} \
|
||||
return NULL; \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof, type) k, \
|
||||
size_t h, \
|
||||
type *v, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
while (v) { \
|
||||
if (eqfn(v, k)) \
|
||||
break; \
|
||||
v = htable_nextval(&ht->raw, &iter->i, h); \
|
||||
} \
|
||||
return v; \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_getfirst(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof, type) k, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
size_t h = hashfn(k); \
|
||||
type *v = htable_firstval(&ht->raw, &iter->i, h); \
|
||||
return name##_getmatch_(ht, k, h, v, iter); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_getnext(const struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof, type) k, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
size_t h = hashfn(k); \
|
||||
type *v = htable_nextval(&ht->raw, &iter->i, h); \
|
||||
return name##_getmatch_(ht, k, h, v, iter); \
|
||||
} \
|
||||
static inline UNNEEDED bool name##_delkey(struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof, type) k) \
|
||||
static inline bool name##_delkey(struct name *ht, \
|
||||
const HTABLE_KTYPE(keyof) k) \
|
||||
{ \
|
||||
type *elem = name##_get(ht, k); \
|
||||
if (elem) \
|
||||
return name##_del(ht, elem); \
|
||||
return false; \
|
||||
} \
|
||||
static inline UNNEEDED void name##_delval(struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
htable_delval(&ht->raw, &iter->i); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_pick(const struct name *ht, \
|
||||
size_t seed, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
/* Note &iter->i == NULL iff iter is NULL */ \
|
||||
return htable_pick(&ht->raw, seed, &iter->i); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_first(const struct name *ht, \
|
||||
static inline type *name##_first(const struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
return htable_first(&ht->raw, &iter->i); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_next(const struct name *ht, \
|
||||
static inline type *name##_next(const struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
return htable_next(&ht->raw, &iter->i); \
|
||||
} \
|
||||
static inline UNNEEDED type *name##_prev(const struct name *ht, \
|
||||
struct name##_iter *iter) \
|
||||
{ \
|
||||
return htable_prev(&ht->raw, &iter->i); \
|
||||
}
|
||||
|
||||
#if HAVE_TYPEOF
|
||||
#define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL))
|
||||
#define HTABLE_KTYPE(keyof) typeof(keyof(NULL))
|
||||
#else
|
||||
/* Assumes keys are a pointer: if not, override. */
|
||||
#ifndef HTABLE_KTYPE
|
||||
#define HTABLE_KTYPE(keyof, type) void *
|
||||
#endif
|
||||
#define HTABLE_KTYPE(keyof) void *
|
||||
#endif
|
||||
#endif /* CCAN_HTABLE_TYPE_H */
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/* Licensed under BSD-MIT - see LICENSE file for details */
|
||||
#ifndef CCAN_LIST_H
|
||||
#define CCAN_LIST_H
|
||||
//#define CCAN_LIST_DEBUG 1
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <ccan/str/str.h>
|
||||
#include <ccan/container_of/container_of.h>
|
||||
#include <ccan/check_type/check_type.h>
|
||||
|
||||
#undef LIST_HEAD
|
||||
#undef LIST_HEAD_INIT
|
||||
|
||||
/**
|
||||
* struct list_node - an entry in a doubly-linked list
|
||||
* @next: next entry (self if empty)
|
||||
@@ -90,13 +91,12 @@ struct list_head *list_check(const struct list_head *h, const char *abortstr);
|
||||
struct list_node *list_check_node(const struct list_node *n,
|
||||
const char *abortstr);
|
||||
|
||||
#define LIST_LOC __FILE__ ":" stringify(__LINE__)
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
#define list_debug(h, loc) list_check((h), loc)
|
||||
#define list_debug_node(n, loc) list_check_node((n), loc)
|
||||
#define list_debug(h) list_check((h), __func__)
|
||||
#define list_debug_node(n) list_check_node((n), __func__)
|
||||
#else
|
||||
#define list_debug(h, loc) ((void)loc, h)
|
||||
#define list_debug_node(n, loc) ((void)loc, n)
|
||||
#define list_debug(h) (h)
|
||||
#define list_debug_node(n) (n)
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -111,7 +111,7 @@ struct list_node *list_check_node(const struct list_node *n,
|
||||
* Example:
|
||||
* static struct list_head my_list = LIST_HEAD_INIT(my_list);
|
||||
*/
|
||||
#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }
|
||||
#define LIST_HEAD_INIT(name) { { &name.n, &name.n } }
|
||||
|
||||
/**
|
||||
* LIST_HEAD - define and initialize an empty list_head
|
||||
@@ -145,48 +145,6 @@ static inline void list_head_init(struct list_head *h)
|
||||
h->n.next = h->n.prev = &h->n;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_node_init - initialize a list_node
|
||||
* @n: the list_node to link to itself.
|
||||
*
|
||||
* You don't need to use this normally! But it lets you list_del(@n)
|
||||
* safely.
|
||||
*/
|
||||
static inline void list_node_init(struct list_node *n)
|
||||
{
|
||||
n->next = n->prev = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_after - add an entry after an existing node in a linked list
|
||||
* @h: the list_head to add the node to (for debugging)
|
||||
* @p: the existing list_node to add the node after
|
||||
* @n: the new list_node to add to the list.
|
||||
*
|
||||
* The existing list_node must already be a member of the list.
|
||||
* The new list_node does not need to be initialized; it will be overwritten.
|
||||
*
|
||||
* Example:
|
||||
* struct child c1, c2, c3;
|
||||
* LIST_HEAD(h);
|
||||
*
|
||||
* list_add_tail(&h, &c1.list);
|
||||
* list_add_tail(&h, &c3.list);
|
||||
* list_add_after(&h, &c1.list, &c2.list);
|
||||
*/
|
||||
#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)
|
||||
static inline void list_add_after_(struct list_head *h,
|
||||
struct list_node *p,
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
{
|
||||
n->next = p->next;
|
||||
n->prev = p;
|
||||
p->next->prev = n;
|
||||
p->next = n;
|
||||
(void)list_debug(h, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add an entry at the start of a linked list.
|
||||
* @h: the list_head to add the node to
|
||||
@@ -200,40 +158,13 @@ static inline void list_add_after_(struct list_head *h,
|
||||
* list_add(&parent->children, &child->list);
|
||||
* parent->num_children++;
|
||||
*/
|
||||
#define list_add(h, n) list_add_(h, n, LIST_LOC)
|
||||
static inline void list_add_(struct list_head *h,
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
static inline void list_add(struct list_head *h, struct list_node *n)
|
||||
{
|
||||
list_add_after_(h, &h->n, n, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_before - add an entry before an existing node in a linked list
|
||||
* @h: the list_head to add the node to (for debugging)
|
||||
* @p: the existing list_node to add the node before
|
||||
* @n: the new list_node to add to the list.
|
||||
*
|
||||
* The existing list_node must already be a member of the list.
|
||||
* The new list_node does not need to be initialized; it will be overwritten.
|
||||
*
|
||||
* Example:
|
||||
* list_head_init(&h);
|
||||
* list_add_tail(&h, &c1.list);
|
||||
* list_add_tail(&h, &c3.list);
|
||||
* list_add_before(&h, &c3.list, &c2.list);
|
||||
*/
|
||||
#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)
|
||||
static inline void list_add_before_(struct list_head *h,
|
||||
struct list_node *p,
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
{
|
||||
n->next = p;
|
||||
n->prev = p->prev;
|
||||
p->prev->next = n;
|
||||
p->prev = n;
|
||||
(void)list_debug(h, abortstr);
|
||||
n->next = h->n.next;
|
||||
n->prev = &h->n;
|
||||
h->n.next->prev = n;
|
||||
h->n.next = n;
|
||||
(void)list_debug(h);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,12 +177,13 @@ static inline void list_add_before_(struct list_head *h,
|
||||
* list_add_tail(&parent->children, &child->list);
|
||||
* parent->num_children++;
|
||||
*/
|
||||
#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC)
|
||||
static inline void list_add_tail_(struct list_head *h,
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
static inline void list_add_tail(struct list_head *h, struct list_node *n)
|
||||
{
|
||||
list_add_before_(h, &h->n, n, abortstr);
|
||||
n->next = &h->n;
|
||||
n->prev = h->n.prev;
|
||||
h->n.prev->next = n;
|
||||
h->n.prev = n;
|
||||
(void)list_debug(h);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,46 +195,9 @@ static inline void list_add_tail_(struct list_head *h,
|
||||
* Example:
|
||||
* assert(list_empty(&parent->children) == (parent->num_children == 0));
|
||||
*/
|
||||
#define list_empty(h) list_empty_(h, LIST_LOC)
|
||||
static inline bool list_empty_(const struct list_head *h, const char* abortstr)
|
||||
{
|
||||
(void)list_debug(h, abortstr);
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty_nodebug - is a list empty (and don't perform debug checks)?
|
||||
* @h: the list_head
|
||||
*
|
||||
* If the list is empty, returns true.
|
||||
* This differs from list_empty() in that if CCAN_LIST_DEBUG is set it
|
||||
* will NOT perform debug checks. Only use this function if you REALLY
|
||||
* know what you're doing.
|
||||
*
|
||||
* Example:
|
||||
* assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
|
||||
*/
|
||||
#ifndef CCAN_LIST_DEBUG
|
||||
#define list_empty_nodebug(h) list_empty(h)
|
||||
#else
|
||||
static inline bool list_empty_nodebug(const struct list_head *h)
|
||||
{
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_empty_nocheck - is a list empty?
|
||||
* @h: the list_head
|
||||
*
|
||||
* If the list is empty, returns true. This doesn't perform any
|
||||
* debug check for list consistency, so it can be called without
|
||||
* locks, racing with the list being modified. This is ok for
|
||||
* checks where an incorrect result is not an issue (optimized
|
||||
* bail out path for example).
|
||||
*/
|
||||
static inline bool list_empty_nocheck(const struct list_head *h)
|
||||
static inline bool list_empty(const struct list_head *h)
|
||||
{
|
||||
(void)list_debug(h);
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
|
||||
@@ -314,16 +209,15 @@ static inline bool list_empty_nocheck(const struct list_head *h)
|
||||
* another list, but not deleted again.
|
||||
*
|
||||
* See also:
|
||||
* list_del_from(), list_del_init()
|
||||
* list_del_from()
|
||||
*
|
||||
* Example:
|
||||
* list_del(&child->list);
|
||||
* parent->num_children--;
|
||||
*/
|
||||
#define list_del(n) list_del_(n, LIST_LOC)
|
||||
static inline void list_del_(struct list_node *n, const char* abortstr)
|
||||
static inline void list_del(struct list_node *n)
|
||||
{
|
||||
(void)list_debug_node(n, abortstr);
|
||||
(void)list_debug_node(n);
|
||||
n->next->prev = n->prev;
|
||||
n->prev->next = n->next;
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
@@ -332,27 +226,6 @@ static inline void list_del_(struct list_node *n, const char* abortstr)
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - delete a node, and reset it so it can be deleted again.
|
||||
* @n: the list_node to be deleted.
|
||||
*
|
||||
* list_del(@n) or list_del_init() again after this will be safe,
|
||||
* which can be useful in some cases.
|
||||
*
|
||||
* See also:
|
||||
* list_del_from(), list_del()
|
||||
*
|
||||
* Example:
|
||||
* list_del_init(&child->list);
|
||||
* parent->num_children--;
|
||||
*/
|
||||
#define list_del_init(n) list_del_init_(n, LIST_LOC)
|
||||
static inline void list_del_init_(struct list_node *n, const char *abortstr)
|
||||
{
|
||||
list_del_(n, abortstr);
|
||||
list_node_init(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_from - delete an entry from a known linked list.
|
||||
* @h: the list_head the node is in.
|
||||
@@ -383,39 +256,6 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)
|
||||
list_del(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_swap - swap out an entry from an (unknown) linked list for a new one.
|
||||
* @o: the list_node to replace from the list.
|
||||
* @n: the list_node to insert in place of the old one.
|
||||
*
|
||||
* Note that this leaves @o in an undefined state; it can be added to
|
||||
* another list, but not deleted/swapped again.
|
||||
*
|
||||
* See also:
|
||||
* list_del()
|
||||
*
|
||||
* Example:
|
||||
* struct child x1, x2;
|
||||
* LIST_HEAD(xh);
|
||||
*
|
||||
* list_add(&xh, &x1.list);
|
||||
* list_swap(&x1.list, &x2.list);
|
||||
*/
|
||||
#define list_swap(o, n) list_swap_(o, n, LIST_LOC)
|
||||
static inline void list_swap_(struct list_node *o,
|
||||
struct list_node *n,
|
||||
const char* abortstr)
|
||||
{
|
||||
(void)list_debug_node(o, abortstr);
|
||||
*n = *o;
|
||||
n->next->prev = n;
|
||||
n->prev->next = n;
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
/* Catch use-after-del. */
|
||||
o->next = o->prev = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - convert a list_node back into the structure containing it.
|
||||
* @n: the list_node
|
||||
@@ -455,34 +295,6 @@ static inline const void *list_top_(const struct list_head *h, size_t off)
|
||||
return (const char *)h->n.next - off;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_pop - remove the first entry in a list
|
||||
* @h: the list_head
|
||||
* @type: the type of the entry
|
||||
* @member: the list_node member of the type
|
||||
*
|
||||
* If the list is empty, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* struct child *one;
|
||||
* one = list_pop(&parent->children, struct child, list);
|
||||
* if (!one)
|
||||
* printf("Empty list!\n");
|
||||
*/
|
||||
#define list_pop(h, type, member) \
|
||||
((type *)list_pop_((h), list_off_(type, member)))
|
||||
|
||||
static inline const void *list_pop_(const struct list_head *h, size_t off)
|
||||
{
|
||||
struct list_node *n;
|
||||
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
n = h->n.next;
|
||||
list_del(n);
|
||||
return (const char *)n - off;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_tail - get the last entry in a list
|
||||
* @h: the list_head
|
||||
@@ -537,29 +349,9 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* printf("Name: %s\n", child->name);
|
||||
*/
|
||||
#define list_for_each_rev(h, i, member) \
|
||||
list_for_each_rev_off(h, i, list_off_var_(i, member))
|
||||
|
||||
/**
|
||||
* list_for_each_rev_safe - iterate through a list backwards,
|
||||
* maybe during deletion
|
||||
* @h: the list_head
|
||||
* @i: the structure containing the list_node
|
||||
* @nxt: the structure containing the list_node
|
||||
* @member: the list_node member of the structure
|
||||
*
|
||||
* This is a convenient wrapper to iterate @i over the entire list backwards.
|
||||
* It's a for loop, so you can break and continue as normal. The extra
|
||||
* variable * @nxt is used to hold the next element, so you can delete @i
|
||||
* from the list.
|
||||
*
|
||||
* Example:
|
||||
* struct child *next;
|
||||
* list_for_each_rev_safe(&parent->children, child, next, list) {
|
||||
* printf("Name: %s\n", child->name);
|
||||
* }
|
||||
*/
|
||||
#define list_for_each_rev_safe(h, i, nxt, member) \
|
||||
list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
|
||||
for (i = container_of_var(list_debug(h)->n.prev, i, member); \
|
||||
&i->member != &(h)->n; \
|
||||
i = container_of_var(i->member.prev, i, member))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate through a list, maybe during deletion
|
||||
@@ -573,6 +365,7 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* @nxt is used to hold the next element, so you can delete @i from the list.
|
||||
*
|
||||
* Example:
|
||||
* struct child *next;
|
||||
* list_for_each_safe(&parent->children, child, next, list) {
|
||||
* list_del(&child->list);
|
||||
* parent->num_children--;
|
||||
@@ -581,134 +374,10 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
#define list_for_each_safe(h, i, nxt, member) \
|
||||
list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
|
||||
|
||||
/**
|
||||
* list_next - get the next entry in a list
|
||||
* @h: the list_head
|
||||
* @i: a pointer to an entry in the list.
|
||||
* @member: the list_node member of the structure
|
||||
*
|
||||
* If @i was the last entry in the list, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* struct child *second;
|
||||
* second = list_next(&parent->children, first, list);
|
||||
* if (!second)
|
||||
* printf("No second child!\n");
|
||||
*/
|
||||
#define list_next(h, i, member) \
|
||||
((list_typeof(i))list_entry_or_null(list_debug(h, \
|
||||
__FILE__ ":" stringify(__LINE__)), \
|
||||
(i)->member.next, \
|
||||
list_off_var_((i), member)))
|
||||
|
||||
/**
|
||||
* list_prev - get the previous entry in a list
|
||||
* @h: the list_head
|
||||
* @i: a pointer to an entry in the list.
|
||||
* @member: the list_node member of the structure
|
||||
*
|
||||
* If @i was the first entry in the list, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* first = list_prev(&parent->children, second, list);
|
||||
* if (!first)
|
||||
* printf("Can't go back to first child?!\n");
|
||||
*/
|
||||
#define list_prev(h, i, member) \
|
||||
((list_typeof(i))list_entry_or_null(list_debug(h, \
|
||||
__FILE__ ":" stringify(__LINE__)), \
|
||||
(i)->member.prev, \
|
||||
list_off_var_((i), member)))
|
||||
|
||||
/**
|
||||
* list_append_list - empty one list onto the end of another.
|
||||
* @to: the list to append into
|
||||
* @from: the list to empty.
|
||||
*
|
||||
* This takes the entire contents of @from and moves it to the end of
|
||||
* @to. After this @from will be empty.
|
||||
*
|
||||
* Example:
|
||||
* struct list_head adopter;
|
||||
*
|
||||
* list_append_list(&adopter, &parent->children);
|
||||
* assert(list_empty(&parent->children));
|
||||
* parent->num_children = 0;
|
||||
*/
|
||||
#define list_append_list(t, f) list_append_list_(t, f, \
|
||||
__FILE__ ":" stringify(__LINE__))
|
||||
static inline void list_append_list_(struct list_head *to,
|
||||
struct list_head *from,
|
||||
const char *abortstr)
|
||||
{
|
||||
struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
|
||||
struct list_node *to_tail = list_debug(to, abortstr)->n.prev;
|
||||
|
||||
/* Sew in head and entire list. */
|
||||
to->n.prev = from_tail;
|
||||
from_tail->next = &to->n;
|
||||
to_tail->next = &from->n;
|
||||
from->n.prev = to_tail;
|
||||
|
||||
/* Now remove head. */
|
||||
list_del(&from->n);
|
||||
list_head_init(from);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_prepend_list - empty one list into the start of another.
|
||||
* @to: the list to prepend into
|
||||
* @from: the list to empty.
|
||||
*
|
||||
* This takes the entire contents of @from and moves it to the start
|
||||
* of @to. After this @from will be empty.
|
||||
*
|
||||
* Example:
|
||||
* list_prepend_list(&adopter, &parent->children);
|
||||
* assert(list_empty(&parent->children));
|
||||
* parent->num_children = 0;
|
||||
*/
|
||||
#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC)
|
||||
static inline void list_prepend_list_(struct list_head *to,
|
||||
struct list_head *from,
|
||||
const char *abortstr)
|
||||
{
|
||||
struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
|
||||
struct list_node *to_head = list_debug(to, abortstr)->n.next;
|
||||
|
||||
/* Sew in head and entire list. */
|
||||
to->n.next = &from->n;
|
||||
from->n.prev = &to->n;
|
||||
to_head->prev = from_tail;
|
||||
from_tail->next = to_head;
|
||||
|
||||
/* Now remove head. */
|
||||
list_del(&from->n);
|
||||
list_head_init(from);
|
||||
}
|
||||
|
||||
/* internal macros, do not use directly */
|
||||
#define list_for_each_off_dir_(h, i, off, dir) \
|
||||
for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
|
||||
(off)); \
|
||||
list_node_from_off_((void *)i, (off)) != &(h)->n; \
|
||||
i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \
|
||||
(off)))
|
||||
|
||||
#define list_for_each_safe_off_dir_(h, i, nxt, off, dir) \
|
||||
for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
|
||||
(off)), \
|
||||
nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
|
||||
(off)); \
|
||||
list_node_from_off_(i, (off)) != &(h)->n; \
|
||||
i = nxt, \
|
||||
nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
|
||||
(off)))
|
||||
|
||||
/**
|
||||
* list_for_each_off - iterate through a list of memory regions.
|
||||
* @h: the list_head
|
||||
* @i: the pointer to a memory region which contains list node data.
|
||||
* @i: the pointer to a memory region wich contains list node data.
|
||||
* @off: offset(relative to @i) at which list node data resides.
|
||||
*
|
||||
* This is a low-level wrapper to iterate @i over the entire list, used to
|
||||
@@ -716,12 +385,12 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* so you can break and continue as normal.
|
||||
*
|
||||
* WARNING! Being the low-level macro that it is, this wrapper doesn't know
|
||||
* nor care about the type of @i. The only assumption made is that @i points
|
||||
* nor care about the type of @i. The only assumtion made is that @i points
|
||||
* to a chunk of memory that at some @offset, relative to @i, contains a
|
||||
* properly filled `struct list_node' which in turn contains pointers to
|
||||
* memory chunks and it's turtles all the way down. With all that in mind
|
||||
* properly filled `struct node_list' which in turn contains pointers to
|
||||
* memory chunks and it's turtles all the way down. Whith all that in mind
|
||||
* remember that given the wrong pointer/offset couple this macro will
|
||||
* happily churn all you memory until SEGFAULT stops it, in other words
|
||||
* happilly churn all you memory until SEGFAULT stops it, in other words
|
||||
* caveat emptor.
|
||||
*
|
||||
* It is worth mentioning that one of legitimate use-cases for that wrapper
|
||||
@@ -735,24 +404,16 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* printf("Name: %s\n", child->name);
|
||||
*/
|
||||
#define list_for_each_off(h, i, off) \
|
||||
list_for_each_off_dir_((h),(i),(off),next)
|
||||
|
||||
/**
|
||||
* list_for_each_rev_off - iterate through a list of memory regions backwards
|
||||
* @h: the list_head
|
||||
* @i: the pointer to a memory region which contains list node data.
|
||||
* @off: offset(relative to @i) at which list node data resides.
|
||||
*
|
||||
* See list_for_each_off for details
|
||||
*/
|
||||
#define list_for_each_rev_off(h, i, off) \
|
||||
list_for_each_off_dir_((h),(i),(off),prev)
|
||||
for (i = list_node_to_off_(list_debug(h)->n.next, (off)); \
|
||||
list_node_from_off_((void *)i, (off)) != &(h)->n; \
|
||||
i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \
|
||||
(off)))
|
||||
|
||||
/**
|
||||
* list_for_each_safe_off - iterate through a list of memory regions, maybe
|
||||
* during deletion
|
||||
* @h: the list_head
|
||||
* @i: the pointer to a memory region which contains list node data.
|
||||
* @i: the pointer to a memory region wich contains list node data.
|
||||
* @nxt: the structure containing the list_node
|
||||
* @off: offset(relative to @i) at which list node data resides.
|
||||
*
|
||||
@@ -765,26 +426,14 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* printf("Name: %s\n", child->name);
|
||||
*/
|
||||
#define list_for_each_safe_off(h, i, nxt, off) \
|
||||
list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
|
||||
for (i = list_node_to_off_(list_debug(h)->n.next, (off)), \
|
||||
nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \
|
||||
(off)); \
|
||||
list_node_from_off_(i, (off)) != &(h)->n; \
|
||||
i = nxt, \
|
||||
nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \
|
||||
(off)))
|
||||
|
||||
/**
|
||||
* list_for_each_rev_safe_off - iterate backwards through a list of
|
||||
* memory regions, maybe during deletion
|
||||
* @h: the list_head
|
||||
* @i: the pointer to a memory region which contains list node data.
|
||||
* @nxt: the structure containing the list_node
|
||||
* @off: offset(relative to @i) at which list node data resides.
|
||||
*
|
||||
* For details see `list_for_each_rev_off' and `list_for_each_rev_safe'
|
||||
* descriptions.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each_rev_safe_off(&parent->children, child,
|
||||
* next, offsetof(struct child, list))
|
||||
* printf("Name: %s\n", child->name);
|
||||
*/
|
||||
#define list_for_each_rev_safe_off(h, i, nxt, off) \
|
||||
list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
|
||||
|
||||
/* Other -off variants. */
|
||||
#define list_entry_off(n, type, off) \
|
||||
@@ -824,19 +473,4 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
|
||||
(container_off_var(var, member) + \
|
||||
check_type(var->member, struct list_node))
|
||||
|
||||
#if HAVE_TYPEOF
|
||||
#define list_typeof(var) typeof(var)
|
||||
#else
|
||||
#define list_typeof(var) void *
|
||||
#endif
|
||||
|
||||
/* Returns member, or NULL if at end of list. */
|
||||
static inline void *list_entry_or_null(const struct list_head *h,
|
||||
const struct list_node *n,
|
||||
size_t off)
|
||||
{
|
||||
if (n == &h->n)
|
||||
return NULL;
|
||||
return (char *)n - off;
|
||||
}
|
||||
#endif /* CCAN_LIST_H */
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_STR_H
|
||||
#define CCAN_STR_H
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/**
|
||||
* streq - Are two strings equal?
|
||||
* @a: first string
|
||||
* @b: first string
|
||||
*
|
||||
* This macro is arguably more readable than "!strcmp(a, b)".
|
||||
*
|
||||
* Example:
|
||||
* if (streq(somestring, ""))
|
||||
* printf("String is empty!\n");
|
||||
*/
|
||||
#define streq(a,b) (strcmp((a),(b)) == 0)
|
||||
|
||||
/**
|
||||
* strstarts - Does this string start with this prefix?
|
||||
* @str: string to test
|
||||
* @prefix: prefix to look for at start of str
|
||||
*
|
||||
* Example:
|
||||
* if (strstarts(somestring, "foo"))
|
||||
* printf("String %s begins with 'foo'!\n", somestring);
|
||||
*/
|
||||
#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
|
||||
|
||||
/**
|
||||
* strends - Does this string end with this postfix?
|
||||
* @str: string to test
|
||||
* @postfix: postfix to look for at end of str
|
||||
*
|
||||
* Example:
|
||||
* if (strends(somestring, "foo"))
|
||||
* printf("String %s end with 'foo'!\n", somestring);
|
||||
*/
|
||||
static inline bool strends(const char *str, const char *postfix)
|
||||
{
|
||||
if (strlen(str) < strlen(postfix))
|
||||
return false;
|
||||
|
||||
return streq(str + strlen(str) - strlen(postfix), postfix);
|
||||
}
|
||||
|
||||
/**
|
||||
* stringify - Turn expression into a string literal
|
||||
* @expr: any C expression
|
||||
*
|
||||
* Example:
|
||||
* #define PRINT_COND_IF_FALSE(cond) \
|
||||
* ((cond) || printf("%s is false!", stringify(cond)))
|
||||
*/
|
||||
#define stringify(expr) stringify_1(expr)
|
||||
/* Double-indirection required to stringify expansions */
|
||||
#define stringify_1(expr) #expr
|
||||
|
||||
/**
|
||||
* strcount - Count number of (non-overlapping) occurrences of a substring.
|
||||
* @haystack: a C string
|
||||
* @needle: a substring
|
||||
*
|
||||
* Example:
|
||||
* assert(strcount("aaa aaa", "a") == 6);
|
||||
* assert(strcount("aaa aaa", "ab") == 0);
|
||||
* assert(strcount("aaa aaa", "aa") == 2);
|
||||
*/
|
||||
size_t strcount(const char *haystack, const char *needle);
|
||||
|
||||
/**
|
||||
* STR_MAX_CHARS - Maximum possible size of numeric string for this type.
|
||||
* @type_or_expr: a pointer or integer type or expression.
|
||||
*
|
||||
* This provides enough space for a nul-terminated string which represents the
|
||||
* largest possible value for the type or expression.
|
||||
*
|
||||
* Note: The implementation adds extra space so hex values or negative
|
||||
* values will fit (eg. sprintf(... "%p"). )
|
||||
*
|
||||
* Example:
|
||||
* char str[STR_MAX_CHARS(int)];
|
||||
*
|
||||
* sprintf(str, "%i", 7);
|
||||
*/
|
||||
#define STR_MAX_CHARS(type_or_expr) \
|
||||
((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \
|
||||
+ STR_MAX_CHARS_TCHECK_(type_or_expr))
|
||||
|
||||
#if HAVE_TYPEOF
|
||||
/* Only a simple type can have 0 assigned, so test that. */
|
||||
#define STR_MAX_CHARS_TCHECK_(type_or_expr) \
|
||||
(sizeof(({ typeof(type_or_expr) x = 0; x; }))*0)
|
||||
#else
|
||||
#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* cisalnum - isalnum() which takes a char (and doesn't accept EOF)
|
||||
* @c: a character
|
||||
*
|
||||
* Surprisingly, the standard ctype.h isalnum() takes an int, which
|
||||
* must have the value of EOF (-1) or an unsigned char. This variant
|
||||
* takes a real char, and doesn't accept EOF.
|
||||
*/
|
||||
static inline bool cisalnum(char c)
|
||||
{
|
||||
return isalnum((unsigned char)c);
|
||||
}
|
||||
static inline bool cisalpha(char c)
|
||||
{
|
||||
return isalpha((unsigned char)c);
|
||||
}
|
||||
static inline bool cisascii(char c)
|
||||
{
|
||||
return isascii((unsigned char)c);
|
||||
}
|
||||
#if HAVE_ISBLANK
|
||||
static inline bool cisblank(char c)
|
||||
{
|
||||
return isblank((unsigned char)c);
|
||||
}
|
||||
#endif
|
||||
static inline bool ciscntrl(char c)
|
||||
{
|
||||
return iscntrl((unsigned char)c);
|
||||
}
|
||||
static inline bool cisdigit(char c)
|
||||
{
|
||||
return isdigit((unsigned char)c);
|
||||
}
|
||||
static inline bool cisgraph(char c)
|
||||
{
|
||||
return isgraph((unsigned char)c);
|
||||
}
|
||||
static inline bool cislower(char c)
|
||||
{
|
||||
return islower((unsigned char)c);
|
||||
}
|
||||
static inline bool cisprint(char c)
|
||||
{
|
||||
return isprint((unsigned char)c);
|
||||
}
|
||||
static inline bool cispunct(char c)
|
||||
{
|
||||
return ispunct((unsigned char)c);
|
||||
}
|
||||
static inline bool cisspace(char c)
|
||||
{
|
||||
return isspace((unsigned char)c);
|
||||
}
|
||||
static inline bool cisupper(char c)
|
||||
{
|
||||
return isupper((unsigned char)c);
|
||||
}
|
||||
static inline bool cisxdigit(char c)
|
||||
{
|
||||
return isxdigit((unsigned char)c);
|
||||
}
|
||||
|
||||
#include <ccan/str/str_debug.h>
|
||||
|
||||
/* These checks force things out of line, hence they are under DEBUG. */
|
||||
#ifdef CCAN_STR_DEBUG
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
|
||||
/* These are commonly misused: they take -1 or an *unsigned* char value. */
|
||||
#undef isalnum
|
||||
#undef isalpha
|
||||
#undef isascii
|
||||
#undef isblank
|
||||
#undef iscntrl
|
||||
#undef isdigit
|
||||
#undef isgraph
|
||||
#undef islower
|
||||
#undef isprint
|
||||
#undef ispunct
|
||||
#undef isspace
|
||||
#undef isupper
|
||||
#undef isxdigit
|
||||
|
||||
/* You can use a char if char is unsigned. */
|
||||
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
|
||||
#define str_check_arg_(i) \
|
||||
((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
|
||||
char) \
|
||||
|| (char)255 > 0))
|
||||
#else
|
||||
#define str_check_arg_(i) (i)
|
||||
#endif
|
||||
|
||||
#define isalnum(i) str_isalnum(str_check_arg_(i))
|
||||
#define isalpha(i) str_isalpha(str_check_arg_(i))
|
||||
#define isascii(i) str_isascii(str_check_arg_(i))
|
||||
#if HAVE_ISBLANK
|
||||
#define isblank(i) str_isblank(str_check_arg_(i))
|
||||
#endif
|
||||
#define iscntrl(i) str_iscntrl(str_check_arg_(i))
|
||||
#define isdigit(i) str_isdigit(str_check_arg_(i))
|
||||
#define isgraph(i) str_isgraph(str_check_arg_(i))
|
||||
#define islower(i) str_islower(str_check_arg_(i))
|
||||
#define isprint(i) str_isprint(str_check_arg_(i))
|
||||
#define ispunct(i) str_ispunct(str_check_arg_(i))
|
||||
#define isspace(i) str_isspace(str_check_arg_(i))
|
||||
#define isupper(i) str_isupper(str_check_arg_(i))
|
||||
#define isxdigit(i) str_isxdigit(str_check_arg_(i))
|
||||
|
||||
#if HAVE_TYPEOF
|
||||
/* With GNU magic, we can make const-respecting standard string functions. */
|
||||
#undef strstr
|
||||
#undef strchr
|
||||
#undef strrchr
|
||||
|
||||
/* + 0 is needed to decay array into pointer. */
|
||||
#define strstr(haystack, needle) \
|
||||
((typeof((haystack) + 0))str_strstr((haystack), (needle)))
|
||||
#define strchr(haystack, c) \
|
||||
((typeof((haystack) + 0))str_strchr((haystack), (c)))
|
||||
#define strrchr(haystack, c) \
|
||||
((typeof((haystack) + 0))str_strrchr((haystack), (c)))
|
||||
#endif
|
||||
#endif /* CCAN_STR_DEBUG */
|
||||
|
||||
#endif /* CCAN_STR_H */
|
||||
@@ -1,30 +0,0 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_STR_DEBUG_H
|
||||
#define CCAN_STR_DEBUG_H
|
||||
|
||||
/* #define CCAN_STR_DEBUG 1 */
|
||||
|
||||
#ifdef CCAN_STR_DEBUG
|
||||
/* Because we mug the real ones with macros, we need our own wrappers. */
|
||||
int str_isalnum(int i);
|
||||
int str_isalpha(int i);
|
||||
int str_isascii(int i);
|
||||
#if HAVE_ISBLANK
|
||||
int str_isblank(int i);
|
||||
#endif
|
||||
int str_iscntrl(int i);
|
||||
int str_isdigit(int i);
|
||||
int str_isgraph(int i);
|
||||
int str_islower(int i);
|
||||
int str_isprint(int i);
|
||||
int str_ispunct(int i);
|
||||
int str_isspace(int i);
|
||||
int str_isupper(int i);
|
||||
int str_isxdigit(int i);
|
||||
|
||||
char *str_strstr(const char *haystack, const char *needle);
|
||||
char *str_strchr(const char *s, int c);
|
||||
char *str_strrchr(const char *s, int c);
|
||||
#endif /* CCAN_STR_DEBUG */
|
||||
|
||||
#endif /* CCAN_STR_DEBUG_H */
|
||||
@@ -621,7 +621,7 @@ static inline int talloc_unreference(const void *context, const void *ptr)
|
||||
|
||||
/*
|
||||
remove a specific parent context from a pointer. This is a more
|
||||
controlled variant of talloc_free()
|
||||
controlled varient of talloc_free()
|
||||
*/
|
||||
int talloc_unlink(const void *context, void *ptr)
|
||||
{
|
||||
@@ -810,7 +810,7 @@ void *_talloc(const void *context, size_t size)
|
||||
|
||||
static int talloc_destroy_pointer(void ***pptr)
|
||||
{
|
||||
if ((uintptr_t)**pptr < (uintptr_t)sysconf(_SC_PAGESIZE))
|
||||
if ((uintptr_t)**pptr < getpagesize())
|
||||
TALLOC_ABORT("Double free or invalid talloc_set?");
|
||||
/* Invalidate pointer so it can't be used again. */
|
||||
**pptr = (void *)1;
|
||||
|
||||
@@ -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 *, unsigned long, (e)))
|
||||
* _set_some_value(typesafe_cb_cast(void *, (e), unsigned long))
|
||||
*/
|
||||
#define typesafe_cb_cast(desttype, oktype, expr) \
|
||||
__builtin_choose_expr( \
|
||||
|
||||
Reference in New Issue
Block a user