Revert "Update CCAN code snippets"

This reverts commit d78f57994a.

Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
Nikos Mavrogiannopoulos
2023-05-07 14:21:37 +02:00
parent 1bc33ad612
commit 2bdbf7927c
12 changed files with 162 additions and 1553 deletions

2
NEWS
View File

@@ -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.

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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( \