nostrdb: ccan: sync with normal versions.
This is the version of CCAN which CLN was using at the time these were taken. Unfortunately lots of whitespace has been changed, but AFAICT no source changes. Here's the command I ran (with ../ccan checked out to 1ae4c432): ``` make update-ccan CCAN_NEW="alignof array_size build_assert check_type container_of cppmagic likely list mem short_types str structeq take tal tal/str typesafe_cb utf8 endian crypto/sha256" ``` Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
committed by
Daniel D’Aquino
parent
201cdd7edc
commit
a8d7d971b1
@@ -2,4 +2,4 @@ CCAN imported from https://github.com/rustyrussell/ccan
|
||||
|
||||
Use "make update-ccan" at top level to refresh from ../ccan.
|
||||
|
||||
CCAN version: unknown
|
||||
CCAN version: init-2577-g1ae4c432
|
||||
|
||||
1
nostrdb/ccan/ccan/alignof/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/alignof/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
51
nostrdb/ccan/ccan/alignof/_info
Normal file
51
nostrdb/ccan/ccan/alignof/_info
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* alignof - ALIGNOF() macro to determine alignment of a type.
|
||||
*
|
||||
* Many platforms have requirements that certain types must be aligned
|
||||
* to certain address boundaries, such as ints needing to be on 4-byte
|
||||
* boundaries. Attempting to access variables with incorrect
|
||||
* alignment may cause performance loss or even program failure (eg. a
|
||||
* bus signal).
|
||||
*
|
||||
* There are times which it's useful to be able to programatically
|
||||
* access these requirements, such as for dynamic allocators.
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <stdlib.h>
|
||||
* #include <ccan/alignof/alignof.h>
|
||||
*
|
||||
* // Output contains "ALIGNOF(char) == 1"
|
||||
* // Will also print out whether an onstack char array can hold a long.
|
||||
* int main(void)
|
||||
* {
|
||||
* char arr[sizeof(int)];
|
||||
*
|
||||
* printf("ALIGNOF(char) == %zu\n", ALIGNOF(char));
|
||||
* if ((unsigned long)arr % ALIGNOF(int)) {
|
||||
* printf("arr %p CANNOT hold an int\n", arr);
|
||||
* exit(1);
|
||||
* } else {
|
||||
* printf("arr %p CAN hold an int\n", arr);
|
||||
* exit(0);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_ALIGNOF_H
|
||||
#define CCAN_ALIGNOF_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* ALIGNOF - get the alignment of a type
|
||||
|
||||
1
nostrdb/ccan/ccan/array_size/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/array_size/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
46
nostrdb/ccan/ccan/array_size/_info
Normal file
46
nostrdb/ccan/ccan/array_size/_info
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* array_size - routine for safely deriving the size of a visible array.
|
||||
*
|
||||
* This provides a simple ARRAY_SIZE() macro, which (given a good compiler)
|
||||
* will also break compile if you try to use it on a pointer.
|
||||
*
|
||||
* This can ensure your code is robust to changes, without needing a gratuitous
|
||||
* macro or constant.
|
||||
*
|
||||
* Example:
|
||||
* // Outputs "Initialized 32 values\n"
|
||||
* #include <ccan/array_size/array_size.h>
|
||||
* #include <stdlib.h>
|
||||
* #include <stdio.h>
|
||||
*
|
||||
* // We currently use 32 random values.
|
||||
* static unsigned int vals[32];
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* unsigned int i;
|
||||
* for (i = 0; i < ARRAY_SIZE(vals); i++)
|
||||
* vals[i] = random();
|
||||
* printf("Initialized %u values\n", i);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/build_assert\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_ARRAY_SIZE_H
|
||||
#define CCAN_ARRAY_SIZE_H
|
||||
#include "../config.h"
|
||||
#include "ccan/build_assert/build_assert.h"
|
||||
#include "config.h"
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
|
||||
/**
|
||||
* ARRAY_SIZE - get the number of elements in a visible array
|
||||
@@ -17,9 +17,9 @@
|
||||
#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
|
||||
/* Two gcc extensions.
|
||||
* &a[0] degrades to a pointer: a different type from an array */
|
||||
#define _array_size_chk(arr) \
|
||||
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \
|
||||
typeof(&(arr)[0])))
|
||||
#define _array_size_chk(arr) \
|
||||
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \
|
||||
typeof(&(arr)[0])))
|
||||
#else
|
||||
#define _array_size_chk(arr) 0
|
||||
#endif
|
||||
|
||||
1
nostrdb/ccan/ccan/build_assert/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/build_assert/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
49
nostrdb/ccan/ccan/build_assert/_info
Normal file
49
nostrdb/ccan/ccan/build_assert/_info
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* build_assert - routines for build-time assertions
|
||||
*
|
||||
* This code provides routines which will cause compilation to fail should some
|
||||
* assertion be untrue: such failures are preferable to run-time assertions,
|
||||
* but much more limited since they can only depends on compile-time constants.
|
||||
*
|
||||
* These assertions are most useful when two parts of the code must be kept in
|
||||
* sync: it is better to avoid such cases if possible, but seconds best is to
|
||||
* detect invalid changes at build time.
|
||||
*
|
||||
* For example, a tricky piece of code might rely on a certain element being at
|
||||
* the start of the structure. To ensure that future changes don't break it,
|
||||
* you would catch such changes in your code like so:
|
||||
*
|
||||
* Example:
|
||||
* #include <stddef.h>
|
||||
* #include <ccan/build_assert/build_assert.h>
|
||||
*
|
||||
* struct foo {
|
||||
* char string[5];
|
||||
* int x;
|
||||
* };
|
||||
*
|
||||
* static char *foo_string(struct foo *foo)
|
||||
* {
|
||||
* // This trick requires that the string be first in the structure
|
||||
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
|
||||
* return (char *)foo;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0)
|
||||
/* Nothing. */
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -10,17 +10,17 @@
|
||||
* by the compiler. This can only be used within a function.
|
||||
*
|
||||
* Example:
|
||||
* #include <stddef.h>
|
||||
* ...
|
||||
* static char *foo_to_char(struct foo *foo)
|
||||
* {
|
||||
* // This code needs string to be at start of foo.
|
||||
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
|
||||
* return (char *)foo;
|
||||
* }
|
||||
* #include <stddef.h>
|
||||
* ...
|
||||
* static char *foo_to_char(struct foo *foo)
|
||||
* {
|
||||
* // This code needs string to be at start of foo.
|
||||
* BUILD_ASSERT(offsetof(struct foo, string) == 0);
|
||||
* return (char *)foo;
|
||||
* }
|
||||
*/
|
||||
#define BUILD_ASSERT(cond) \
|
||||
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
|
||||
do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
|
||||
|
||||
/**
|
||||
* BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
|
||||
@@ -30,11 +30,11 @@
|
||||
* by the compiler. This can be used in an expression: its value is "0".
|
||||
*
|
||||
* Example:
|
||||
* #define foo_to_char(foo) \
|
||||
* ((char *)(foo) \
|
||||
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
|
||||
* #define foo_to_char(foo) \
|
||||
* ((char *)(foo) \
|
||||
* + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
|
||||
*/
|
||||
#define BUILD_ASSERT_OR_ZERO(cond) \
|
||||
(sizeof(char [1 - 2*!(cond)]) - 1)
|
||||
(sizeof(char [1 - 2*!(cond)]) - 1)
|
||||
|
||||
#endif /* CCAN_BUILD_ASSERT_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/check_type/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/check_type/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
33
nostrdb/ccan/ccan/check_type/_info
Normal file
33
nostrdb/ccan/ccan/check_type/_info
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* check_type - routines for compile time type checking
|
||||
*
|
||||
* C has fairly weak typing: ints get automatically converted to longs, signed
|
||||
* to unsigned, etc. There are some cases where this is best avoided, and
|
||||
* these macros provide methods for evoking warnings (or build errors) when
|
||||
* a precise type isn't used.
|
||||
*
|
||||
* On compilers which don't support typeof() these routines are less effective,
|
||||
* since they have to use sizeof() which can only distiguish between types of
|
||||
* different size.
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
#if !HAVE_TYPEOF
|
||||
printf("ccan/build_assert\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_CHECK_TYPE_H
|
||||
#define CCAN_CHECK_TYPE_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* check_type - issue a warning or build failure if type is not correct.
|
||||
@@ -18,9 +18,9 @@
|
||||
* to compile if the sizes of the types are unequal (a less complete check).
|
||||
*
|
||||
* Example:
|
||||
* // They should always pass a 64-bit value to _set_some_value!
|
||||
* #define set_some_value(expr) \
|
||||
* _set_some_value((check_type((expr), uint64_t), (expr)))
|
||||
* // They should always pass a 64-bit value to _set_some_value!
|
||||
* #define set_some_value(expr) \
|
||||
* _set_some_value((check_type((expr), uint64_t), (expr)))
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -38,27 +38,27 @@
|
||||
* to compile if the sizes of the types are unequal (a less complete check).
|
||||
*
|
||||
* Example:
|
||||
* // Do subtraction to get to enclosing type, but make sure that
|
||||
* // pointer is of correct type for that member.
|
||||
* #define container_of(mbr_ptr, encl_type, mbr) \
|
||||
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
|
||||
* ((encl_type *) \
|
||||
* ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
|
||||
* // Do subtraction to get to enclosing type, but make sure that
|
||||
* // pointer is of correct type for that member.
|
||||
* #define container_of(mbr_ptr, encl_type, mbr) \
|
||||
* (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
|
||||
* ((encl_type *) \
|
||||
* ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
|
||||
*/
|
||||
#if HAVE_TYPEOF
|
||||
#define check_type(expr, type) \
|
||||
((typeof(expr) *)0 != (type *)0)
|
||||
#define check_type(expr, type) \
|
||||
((typeof(expr) *)0 != (type *)0)
|
||||
|
||||
#define check_types_match(expr1, expr2) \
|
||||
((typeof(expr1) *)0 != (typeof(expr2) *)0)
|
||||
#define check_types_match(expr1, expr2) \
|
||||
((typeof(expr1) *)0 != (typeof(expr2) *)0)
|
||||
#else
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
/* Without typeof, we can only test the sizes. */
|
||||
#define check_type(expr, type) \
|
||||
BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
|
||||
#define check_type(expr, type) \
|
||||
BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
|
||||
|
||||
#define check_types_match(expr1, expr2) \
|
||||
BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
|
||||
#define check_types_match(expr1, expr2) \
|
||||
BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
|
||||
#endif /* HAVE_TYPEOF */
|
||||
|
||||
#endif /* CCAN_CHECK_TYPE_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/compiler/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/compiler/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
64
nostrdb/ccan/ccan/compiler/_info
Normal file
64
nostrdb/ccan/ccan/compiler/_info
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* compiler - macros for common compiler extensions
|
||||
*
|
||||
* Abstracts away some compiler hints. Currently these include:
|
||||
* - COLD
|
||||
* For functions not called in fast paths (aka. cold functions)
|
||||
* - PRINTF_FMT
|
||||
* For functions which take printf-style parameters.
|
||||
* - CONST_FUNCTION
|
||||
* For functions which return the same value for same parameters.
|
||||
* - NEEDED
|
||||
* For functions and variables which must be emitted even if unused.
|
||||
* - UNNEEDED
|
||||
* For functions and variables which need not be emitted if unused.
|
||||
* - UNUSED
|
||||
* For parameters which are not used.
|
||||
* - IS_COMPILE_CONSTANT()
|
||||
* For using different tradeoffs for compiletime vs runtime evaluation.
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/compiler/compiler.h>
|
||||
* #include <stdio.h>
|
||||
* #include <stdarg.h>
|
||||
*
|
||||
* // Example of a (slow-path) logging function.
|
||||
* static int log_threshold = 2;
|
||||
* static void COLD PRINTF_FMT(2,3)
|
||||
* logger(int level, const char *fmt, ...)
|
||||
* {
|
||||
* va_list ap;
|
||||
* va_start(ap, fmt);
|
||||
* if (level >= log_threshold)
|
||||
* vfprintf(stderr, fmt, ap);
|
||||
* va_end(ap);
|
||||
* }
|
||||
*
|
||||
* int main(int argc, char *argv[] UNNEEDED)
|
||||
* {
|
||||
* if (argc != 1) {
|
||||
* logger(3, "Don't want %i arguments!\n", argc-1);
|
||||
* return 1;
|
||||
* }
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -3,12 +3,6 @@
|
||||
#define CCAN_COMPILER_H
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_UNALIGNED_ACCESS
|
||||
#define alignment_ok(p, n) 1
|
||||
#else
|
||||
#define alignment_ok(p, n) ((size_t)(p) % (n) == 0)
|
||||
#endif
|
||||
|
||||
#ifndef COLD
|
||||
#if HAVE_ATTRIBUTE_COLD
|
||||
/**
|
||||
@@ -20,7 +14,7 @@
|
||||
* Example:
|
||||
* static void COLD moan(const char *reason)
|
||||
* {
|
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
|
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
|
||||
* }
|
||||
*/
|
||||
#define COLD __attribute__((__cold__))
|
||||
@@ -39,8 +33,8 @@
|
||||
* Example:
|
||||
* static void NORETURN fail(const char *reason)
|
||||
* {
|
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
|
||||
* exit(1);
|
||||
* fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
|
||||
* exit(1);
|
||||
* }
|
||||
*/
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
@@ -62,7 +56,7 @@
|
||||
* void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...);
|
||||
*/
|
||||
#define PRINTF_FMT(nfmt, narg) \
|
||||
__attribute__((format(__printf__, nfmt, narg)))
|
||||
__attribute__((format(__printf__, nfmt, narg)))
|
||||
#else
|
||||
#define PRINTF_FMT(nfmt, narg)
|
||||
#endif
|
||||
@@ -112,7 +106,7 @@
|
||||
* // With some preprocessor options, this is unnecessary.
|
||||
* static UNNEEDED void add_to_counter(int add)
|
||||
* {
|
||||
* counter += add;
|
||||
* counter += add;
|
||||
* }
|
||||
*/
|
||||
#define UNNEEDED __attribute__((__unused__))
|
||||
@@ -127,12 +121,12 @@
|
||||
* the compiler that it must exist even if it (seems) unused.
|
||||
*
|
||||
* Example:
|
||||
* // Even if this is unused, these are vital for debugging.
|
||||
* static NEEDED int counter;
|
||||
* static NEEDED void dump_counter(void)
|
||||
* {
|
||||
* printf("Counter is %i\n", counter);
|
||||
* }
|
||||
* // Even if this is unused, these are vital for debugging.
|
||||
* static NEEDED int counter;
|
||||
* static NEEDED void dump_counter(void)
|
||||
* {
|
||||
* printf("Counter is %i\n", counter);
|
||||
* }
|
||||
*/
|
||||
#define NEEDED __attribute__((__used__))
|
||||
#else
|
||||
@@ -150,11 +144,11 @@
|
||||
* to the reader that it's deliberate.
|
||||
*
|
||||
* Example:
|
||||
* // This is used as a callback, so needs to have this prototype.
|
||||
* static int some_callback(void *unused UNUSED)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
* // This is used as a callback, so needs to have this prototype.
|
||||
* static int some_callback(void *unused UNUSED)
|
||||
* {
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
#define UNUSED __attribute__((__unused__))
|
||||
#endif
|
||||
@@ -184,28 +178,28 @@
|
||||
* This can be done using the IS_COMPILE_CONSTANT() macro.
|
||||
*
|
||||
* Example:
|
||||
* enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON };
|
||||
* enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON };
|
||||
*
|
||||
* // Out-of-line version.
|
||||
* const char *greek_name(enum greek greek);
|
||||
* // Out-of-line version.
|
||||
* const char *greek_name(enum greek greek);
|
||||
*
|
||||
* // Inline version.
|
||||
* static inline const char *_greek_name(enum greek greek)
|
||||
* {
|
||||
* switch (greek) {
|
||||
* case ALPHA: return "alpha";
|
||||
* case BETA: return "beta";
|
||||
* case GAMMA: return "gamma";
|
||||
* case DELTA: return "delta";
|
||||
* case EPSILON: return "epsilon";
|
||||
* default: return "**INVALID**";
|
||||
* }
|
||||
* }
|
||||
* // Inline version.
|
||||
* static inline const char *_greek_name(enum greek greek)
|
||||
* {
|
||||
* switch (greek) {
|
||||
* case ALPHA: return "alpha";
|
||||
* case BETA: return "beta";
|
||||
* case GAMMA: return "gamma";
|
||||
* case DELTA: return "delta";
|
||||
* case EPSILON: return "epsilon";
|
||||
* default: return "**INVALID**";
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Use inline if compiler knows answer. Otherwise call function
|
||||
* // to avoid copies of the same code everywhere.
|
||||
* #define greek_name(g) \
|
||||
* (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g))
|
||||
* // Use inline if compiler knows answer. Otherwise call function
|
||||
* // to avoid copies of the same code everywhere.
|
||||
* #define greek_name(g) \
|
||||
* (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g))
|
||||
*/
|
||||
#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr)
|
||||
#else
|
||||
@@ -226,7 +220,7 @@
|
||||
* // buf param may be freed by this; need return value!
|
||||
* static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size)
|
||||
* {
|
||||
* return realloc(buf, (*size) *= 2);
|
||||
* return realloc(buf, (*size) *= 2);
|
||||
* }
|
||||
*/
|
||||
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
|
||||
@@ -313,7 +307,7 @@
|
||||
*
|
||||
* Example:
|
||||
* if (cpu_supports("mmx"))
|
||||
* printf("MMX support engaged!\n");
|
||||
* printf("MMX support engaged!\n");
|
||||
*/
|
||||
#define cpu_supports(x) __builtin_cpu_supports(x)
|
||||
#else
|
||||
|
||||
1
nostrdb/ccan/ccan/container_of/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/container_of/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
65
nostrdb/ccan/ccan/container_of/_info
Normal file
65
nostrdb/ccan/ccan/container_of/_info
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* container_of - routine for upcasting
|
||||
*
|
||||
* It is often convenient to create code where the caller registers a pointer
|
||||
* to a generic structure and a callback. The callback might know that the
|
||||
* pointer points to within a larger structure, and container_of gives a
|
||||
* convenient and fairly type-safe way of returning to the enclosing structure.
|
||||
*
|
||||
* This idiom is an alternative to providing a void * pointer for every
|
||||
* callback.
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <ccan/container_of/container_of.h>
|
||||
*
|
||||
* struct timer {
|
||||
* void *members;
|
||||
* };
|
||||
*
|
||||
* struct info {
|
||||
* int my_stuff;
|
||||
* struct timer timer;
|
||||
* };
|
||||
*
|
||||
* static void my_timer_callback(struct timer *timer)
|
||||
* {
|
||||
* struct info *info = container_of(timer, struct info, timer);
|
||||
* printf("my_stuff is %u\n", info->my_stuff);
|
||||
* }
|
||||
*
|
||||
* static void register_timer(struct timer *timer)
|
||||
* {
|
||||
* (void)timer;
|
||||
* (void)my_timer_callback;
|
||||
* //...
|
||||
* }
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* struct info info = { .my_stuff = 1 };
|
||||
*
|
||||
* register_timer(&info.timer);
|
||||
* // ...
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/check_type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
#define CCAN_CONTAINER_OF_H
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../config.h"
|
||||
#include "ccan/check_type/check_type.h"
|
||||
#include "config.h"
|
||||
#include <ccan/check_type/check_type.h>
|
||||
|
||||
/**
|
||||
* container_of - get pointer to enclosing structure
|
||||
@@ -16,25 +16,25 @@
|
||||
* subtraction to return the pointer to the enclosing type.
|
||||
*
|
||||
* Example:
|
||||
* struct foo {
|
||||
* int fielda, fieldb;
|
||||
* // ...
|
||||
* };
|
||||
* struct info {
|
||||
* int some_other_field;
|
||||
* struct foo my_foo;
|
||||
* };
|
||||
* struct foo {
|
||||
* int fielda, fieldb;
|
||||
* // ...
|
||||
* };
|
||||
* struct info {
|
||||
* int some_other_field;
|
||||
* struct foo my_foo;
|
||||
* };
|
||||
*
|
||||
* static struct info *foo_to_info(struct foo *foo)
|
||||
* {
|
||||
* return container_of(foo, struct info, my_foo);
|
||||
* }
|
||||
* static struct info *foo_to_info(struct foo *foo)
|
||||
* {
|
||||
* return container_of(foo, struct info, my_foo);
|
||||
* }
|
||||
*/
|
||||
#define container_of(member_ptr, containing_type, member) \
|
||||
((containing_type *) \
|
||||
((char *)(member_ptr) \
|
||||
- container_off(containing_type, member)) \
|
||||
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
||||
#define container_of(member_ptr, containing_type, member) \
|
||||
((containing_type *) \
|
||||
((char *)(member_ptr) \
|
||||
- container_off(containing_type, member)) \
|
||||
+ check_types_match(*(member_ptr), ((containing_type *)0)->member))
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,29 +48,29 @@
|
||||
* 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;
|
||||
* };
|
||||
* 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 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;
|
||||
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))
|
||||
#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
|
||||
@@ -81,23 +81,23 @@ static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
||||
* typechecking and figures out the offset to the enclosing type.
|
||||
*
|
||||
* Example:
|
||||
* struct foo {
|
||||
* int fielda, fieldb;
|
||||
* // ...
|
||||
* };
|
||||
* struct info {
|
||||
* int some_other_field;
|
||||
* struct foo my_foo;
|
||||
* };
|
||||
* struct foo {
|
||||
* int fielda, fieldb;
|
||||
* // ...
|
||||
* };
|
||||
* struct info {
|
||||
* int some_other_field;
|
||||
* struct foo my_foo;
|
||||
* };
|
||||
*
|
||||
* static struct info *foo_to_info(struct foo *foo)
|
||||
* {
|
||||
* size_t off = container_off(struct info, my_foo);
|
||||
* return (void *)((char *)foo - off);
|
||||
* }
|
||||
* static struct info *foo_to_info(struct foo *foo)
|
||||
* {
|
||||
* size_t off = container_off(struct info, my_foo);
|
||||
* return (void *)((char *)foo - off);
|
||||
* }
|
||||
*/
|
||||
#define container_off(containing_type, member) \
|
||||
offsetof(containing_type, member)
|
||||
#define container_off(containing_type, member) \
|
||||
offsetof(containing_type, member)
|
||||
|
||||
/**
|
||||
* container_of_var - get pointer to enclosing structure using a variable
|
||||
@@ -109,19 +109,19 @@ static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
||||
* subtraction to return the pointer to the enclosing type.
|
||||
*
|
||||
* Example:
|
||||
* static struct info *foo_to_i(struct foo *foo)
|
||||
* {
|
||||
* struct info *i = container_of_var(foo, i, my_foo);
|
||||
* return i;
|
||||
* }
|
||||
* static struct info *foo_to_i(struct foo *foo)
|
||||
* {
|
||||
* struct info *i = container_of_var(foo, i, my_foo);
|
||||
* return i;
|
||||
* }
|
||||
*/
|
||||
#if HAVE_TYPEOF
|
||||
#define container_of_var(member_ptr, container_var, member) \
|
||||
container_of(member_ptr, typeof(*container_var), member)
|
||||
container_of(member_ptr, typeof(*container_var), member)
|
||||
#else
|
||||
#define container_of_var(member_ptr, container_var, member) \
|
||||
((void *)((char *)(member_ptr) - \
|
||||
container_off_var(container_var, member)))
|
||||
#define container_of_var(member_ptr, container_var, member) \
|
||||
((void *)((char *)(member_ptr) - \
|
||||
container_off_var(container_var, member)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -135,11 +135,11 @@ static inline char *container_of_or_null_(void *member_ptr, size_t offset)
|
||||
*
|
||||
*/
|
||||
#if HAVE_TYPEOF
|
||||
#define container_off_var(var, member) \
|
||||
container_off(typeof(*var), member)
|
||||
#define container_off_var(var, member) \
|
||||
container_off(typeof(*var), member)
|
||||
#else
|
||||
#define container_off_var(var, member) \
|
||||
((const char *)&(var)->member - (const char *)(var))
|
||||
#define container_off_var(var, member) \
|
||||
((const char *)&(var)->member - (const char *)(var))
|
||||
#endif
|
||||
|
||||
#endif /* CCAN_CONTAINER_OF_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/cppmagic/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/cppmagic/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
||||
30
nostrdb/ccan/ccan/cppmagic/_info
Normal file
30
nostrdb/ccan/ccan/cppmagic/_info
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* cppmagic - Abuse of the C preprocessor
|
||||
*
|
||||
* This contains a bunch of fancy macro techniques such as
|
||||
* preprocessor-time evaluated conditionals and (quasi) recursion and
|
||||
* iteration.
|
||||
*
|
||||
* It's based on these articles:
|
||||
* - http://jhnet.co.uk/articles/cpp_magic
|
||||
* - https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
|
||||
* and code from the Boost C++ library.
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -10,93 +10,93 @@
|
||||
/**
|
||||
* CPPMAGIC_STRINGIFY - convert arguments to a string literal
|
||||
*/
|
||||
#define _CPPMAGIC_STRINGIFY(...) #__VA_ARGS__
|
||||
#define CPPMAGIC_STRINGIFY(...) _CPPMAGIC_STRINGIFY(__VA_ARGS__)
|
||||
#define _CPPMAGIC_STRINGIFY(...) #__VA_ARGS__
|
||||
#define CPPMAGIC_STRINGIFY(...) _CPPMAGIC_STRINGIFY(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* CPPMAGIC_GLUE2 - glue arguments together
|
||||
*
|
||||
* CPPMAGIC_GLUE2(@a_, @b_)
|
||||
* expands to the expansion of @a_ followed immediately
|
||||
* (combining tokens) by the expansion of @b_
|
||||
* expands to the expansion of @a_ followed immediately
|
||||
* (combining tokens) by the expansion of @b_
|
||||
*/
|
||||
#define _CPPMAGIC_GLUE2(a_, b_) a_##b_
|
||||
#define CPPMAGIC_GLUE2(a_, b_) _CPPMAGIC_GLUE2(a_, b_)
|
||||
#define _CPPMAGIC_GLUE2(a_, b_) a_##b_
|
||||
#define CPPMAGIC_GLUE2(a_, b_) _CPPMAGIC_GLUE2(a_, b_)
|
||||
|
||||
/**
|
||||
* CPPMAGIC_1ST - return 1st argument
|
||||
*
|
||||
* CPPMAGIC_1ST(@a_, ...)
|
||||
* expands to the expansion of @a_
|
||||
* expands to the expansion of @a_
|
||||
*/
|
||||
#define CPPMAGIC_1ST(a_, ...) a_
|
||||
#define CPPMAGIC_1ST(a_, ...) a_
|
||||
|
||||
/**
|
||||
* CPPMAGIC_2ND - return 2nd argument
|
||||
*
|
||||
* CPPMAGIC_2ST(@a_, @b_, ...)
|
||||
* expands to the expansion of @b_
|
||||
* expands to the expansion of @b_
|
||||
*/
|
||||
#define CPPMAGIC_2ND(a_, b_, ...) b_
|
||||
#define CPPMAGIC_2ND(a_, b_, ...) b_
|
||||
|
||||
/**
|
||||
* CPPMAGIC_ISZERO - is argument '0'
|
||||
*
|
||||
* CPPMAGIC_ISZERO(@a)
|
||||
* expands to '1' if @a is '0', otherwise expands to '0'.
|
||||
* expands to '1' if @a is '0', otherwise expands to '0'.
|
||||
*/
|
||||
#define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0)
|
||||
#define _CPPMAGIC_PROBE() $, 1
|
||||
#define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE()
|
||||
#define CPPMAGIC_ISZERO(a_) \
|
||||
_CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_))
|
||||
#define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0)
|
||||
#define _CPPMAGIC_PROBE() $, 1
|
||||
#define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE()
|
||||
#define CPPMAGIC_ISZERO(a_) \
|
||||
_CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_))
|
||||
|
||||
/**
|
||||
* CPPMAGIC_NONZERO - is argument not '0'
|
||||
*
|
||||
* CPPMAGIC_NONZERO(@a)
|
||||
* expands to '0' if @a is '0', otherwise expands to '1'.
|
||||
* expands to '0' if @a is '0', otherwise expands to '1'.
|
||||
*/
|
||||
#define CPPMAGIC_NONZERO(a_) CPPMAGIC_ISZERO(CPPMAGIC_ISZERO(a_))
|
||||
#define CPPMAGIC_NONZERO(a_) CPPMAGIC_ISZERO(CPPMAGIC_ISZERO(a_))
|
||||
|
||||
/**
|
||||
* CPPMAGIC_NONEMPTY - does the macro have any arguments?
|
||||
*
|
||||
* CPPMAGIC_NONEMPTY()
|
||||
* expands to '0'
|
||||
* expands to '0'
|
||||
* CPPMAGIC_NONEMPTY(@a)
|
||||
* CPPMAGIC_NONEMPTY(@a, ...)
|
||||
* expand to '1'
|
||||
* expand to '1'
|
||||
*/
|
||||
#define _CPPMAGIC_EOA() 0
|
||||
#define CPPMAGIC_NONEMPTY(...) \
|
||||
CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)())
|
||||
#define _CPPMAGIC_EOA() 0
|
||||
#define CPPMAGIC_NONEMPTY(...) \
|
||||
CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)())
|
||||
|
||||
/**
|
||||
* CPPMAGIC_ISEMPTY - does the macro have no arguments?
|
||||
*
|
||||
* CPPMAGIC_ISEMPTY()
|
||||
* expands to '1'
|
||||
* expands to '1'
|
||||
* CPPMAGIC_ISEMPTY(@a)
|
||||
* CPPMAGIC_ISEMPTY(@a, ...)
|
||||
* expand to '0'
|
||||
* expand to '0'
|
||||
*/
|
||||
#define CPPMAGIC_ISEMPTY(...) \
|
||||
CPPMAGIC_ISZERO(CPPMAGIC_NONEMPTY(__VA_ARGS__))
|
||||
#define CPPMAGIC_ISEMPTY(...) \
|
||||
CPPMAGIC_ISZERO(CPPMAGIC_NONEMPTY(__VA_ARGS__))
|
||||
|
||||
/*
|
||||
* CPPMAGIC_IFELSE - preprocessor conditional
|
||||
*
|
||||
* CPPMAGIC_IFELSE(@cond)(@if)(@else)
|
||||
* expands to @else if @cond is '0', otherwise expands to @if
|
||||
* expands to @else if @cond is '0', otherwise expands to @if
|
||||
*/
|
||||
#define _CPPMAGIC_IF_0(...) _CPPMAGIC_IF_0_ELSE
|
||||
#define _CPPMAGIC_IF_1(...) __VA_ARGS__ _CPPMAGIC_IF_1_ELSE
|
||||
#define _CPPMAGIC_IF_0_ELSE(...) __VA_ARGS__
|
||||
#define _CPPMAGIC_IF_0(...) _CPPMAGIC_IF_0_ELSE
|
||||
#define _CPPMAGIC_IF_1(...) __VA_ARGS__ _CPPMAGIC_IF_1_ELSE
|
||||
#define _CPPMAGIC_IF_0_ELSE(...) __VA_ARGS__
|
||||
#define _CPPMAGIC_IF_1_ELSE(...)
|
||||
#define _CPPMAGIC_IFELSE(cond_) CPPMAGIC_GLUE2(_CPPMAGIC_IF_, cond_)
|
||||
#define CPPMAGIC_IFELSE(cond_) \
|
||||
_CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_))
|
||||
#define _CPPMAGIC_IFELSE(cond_) CPPMAGIC_GLUE2(_CPPMAGIC_IF_, cond_)
|
||||
#define CPPMAGIC_IFELSE(cond_) \
|
||||
_CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_))
|
||||
|
||||
/**
|
||||
* CPPMAGIC_EVAL - force multiple expansion passes
|
||||
@@ -104,88 +104,88 @@
|
||||
* Forces macros in the arguments to be expanded repeatedly (up to
|
||||
* 1024 times) even when CPP would usually stop expanding.
|
||||
*/
|
||||
#define CPPMAGIC_EVAL1(...) __VA_ARGS__
|
||||
#define CPPMAGIC_EVAL2(...) \
|
||||
CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL4(...) \
|
||||
CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL8(...) \
|
||||
CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL16(...) \
|
||||
CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL32(...) \
|
||||
CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL64(...) \
|
||||
CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL128(...) \
|
||||
CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL256(...) \
|
||||
CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL512(...) \
|
||||
CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL1024(...) \
|
||||
CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__)
|
||||
#define CPPMAGIC_EVAL1(...) __VA_ARGS__
|
||||
#define CPPMAGIC_EVAL2(...) \
|
||||
CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL4(...) \
|
||||
CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL8(...) \
|
||||
CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL16(...) \
|
||||
CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL32(...) \
|
||||
CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL64(...) \
|
||||
CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL128(...) \
|
||||
CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL256(...) \
|
||||
CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL512(...) \
|
||||
CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL1024(...) \
|
||||
CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__))
|
||||
#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* CPPMAGIC_DEFER1, CPPMAGIC_DEFER2 - defer expansion
|
||||
*/
|
||||
#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING()
|
||||
#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()()
|
||||
#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING()
|
||||
#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()()
|
||||
|
||||
/**
|
||||
* CPPMAGIC_MAP - iterate another macro across arguments
|
||||
* @m: name of a one argument macro
|
||||
*
|
||||
* CPPMAGIC_MAP(@m, @a1, @a2, ... @an)
|
||||
* expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an)
|
||||
* expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an)
|
||||
*/
|
||||
#define _CPPMAGIC_MAP_() _CPPMAGIC_MAP
|
||||
#define _CPPMAGIC_MAP(m_, a_, ...) \
|
||||
m_(a_) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_)()(m_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_MAP(m_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_MAP(m_, __VA_ARGS__))) \
|
||||
()
|
||||
#define _CPPMAGIC_MAP_() _CPPMAGIC_MAP
|
||||
#define _CPPMAGIC_MAP(m_, a_, ...) \
|
||||
m_(a_) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_)()(m_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_MAP(m_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_MAP(m_, __VA_ARGS__))) \
|
||||
()
|
||||
|
||||
/**
|
||||
* CPPMAGIC_2MAP - iterate another macro across pairs of arguments
|
||||
* @m: name of a two argument macro
|
||||
*
|
||||
* CPPMAGIC_2MAP(@m, @a1, @b1, @a2, @b2, ..., @an, @bn)
|
||||
* expands to the expansion of
|
||||
* @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn)
|
||||
* expands to the expansion of
|
||||
* @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn)
|
||||
*/
|
||||
#define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP
|
||||
#define _CPPMAGIC_2MAP(m_, a_, b_, ...) \
|
||||
m_(a_, b_) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(, CPPMAGIC_DEFER2(_CPPMAGIC_2MAP_)()(m_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_2MAP(m_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_2MAP(m_, __VA_ARGS__))) \
|
||||
()
|
||||
#define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP
|
||||
#define _CPPMAGIC_2MAP(m_, a_, b_, ...) \
|
||||
m_(a_, b_) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(, CPPMAGIC_DEFER2(_CPPMAGIC_2MAP_)()(m_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_2MAP(m_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_2MAP(m_, __VA_ARGS__))) \
|
||||
()
|
||||
|
||||
/**
|
||||
* CPPMAGIC_JOIN - separate arguments with given delimiter
|
||||
* @d: delimiter
|
||||
*
|
||||
* CPPMAGIC_JOIN(@d, @a1, @a2, ..., @an)
|
||||
* expands to the expansion of @a1 @d @a2 @d ... @d @an
|
||||
* expands to the expansion of @a1 @d @a2 @d ... @d @an
|
||||
*/
|
||||
#define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN
|
||||
#define _CPPMAGIC_JOIN(d_, a_, ...) \
|
||||
a_ \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(d_ CPPMAGIC_DEFER2(_CPPMAGIC_JOIN_)()(d_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_JOIN(d_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \
|
||||
()
|
||||
#define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN
|
||||
#define _CPPMAGIC_JOIN(d_, a_, ...) \
|
||||
a_ \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(d_ CPPMAGIC_DEFER2(_CPPMAGIC_JOIN_)()(d_, __VA_ARGS__)) \
|
||||
()
|
||||
#define CPPMAGIC_JOIN(d_, ...) \
|
||||
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
|
||||
(CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \
|
||||
()
|
||||
|
||||
#endif /* CCAN_CPPMAGIC_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/crypto/sha256/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/crypto/sha256/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../licenses/BSD-MIT
|
||||
61
nostrdb/ccan/ccan/crypto/sha256/_info
Normal file
61
nostrdb/ccan/ccan/crypto/sha256/_info
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* crypto/sha256 - implementation of SHA-2 with 256 bit digest.
|
||||
*
|
||||
* This code is either a wrapper for openssl (if CCAN_CRYPTO_SHA256_USE_OPENSSL
|
||||
* is defined) or an open-coded implementation based on Bitcoin's.
|
||||
*
|
||||
* License: BSD-MIT
|
||||
* Maintainer: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/crypto/sha256/sha256.h>
|
||||
* #include <err.h>
|
||||
* #include <stdio.h>
|
||||
* #include <string.h>
|
||||
*
|
||||
* // Simple demonstration: idential strings will have the same hash, but
|
||||
* // two different strings will not.
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct sha256 hash1, hash2;
|
||||
*
|
||||
* if (argc != 3)
|
||||
* errx(1, "Usage: %s <string1> <string2>", argv[0]);
|
||||
*
|
||||
* sha256(&hash1, argv[1], strlen(argv[1]));
|
||||
* sha256(&hash2, argv[2], strlen(argv[2]));
|
||||
* printf("Hash is %s\n", memcmp(&hash1, &hash2, sizeof(hash1))
|
||||
* ? "different" : "same");
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/compiler\n");
|
||||
printf("ccan/endian\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "testdepends") == 0) {
|
||||
printf("ccan/str/hex\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "libs") == 0) {
|
||||
#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
|
||||
printf("crypto\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
20
nostrdb/ccan/ccan/crypto/sha256/benchmarks/Makefile
Normal file
20
nostrdb/ccan/ccan/crypto/sha256/benchmarks/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
CCANDIR := ../../../../
|
||||
CFLAGS := -Wall -I$(CCANDIR) -O3 -flto -DCCAN_USE_ORIGINAL=1
|
||||
LDFLAGS := -O3 -flto
|
||||
|
||||
INTEL_OBJS := sha256_avx1.o sha256_avx2_rorx2.o sha256_avx2_rorx8.o sha256_sse4.o
|
||||
|
||||
double-sha-bench: double-sha-bench.o ccan-time.o $(INTEL_OBJS) #ccan-crypto-sha256.o
|
||||
|
||||
$(INTEL_OBJS): %.o : %.asm
|
||||
|
||||
%.o : %.asm
|
||||
yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
||||
ccan-crypto-sha256.o: $(CCANDIR)/ccan/crypto/sha256/sha256.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-time.o: $(CCANDIR)/ccan/time/time.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
122
nostrdb/ccan/ccan/crypto/sha256/benchmarks/double-sha-bench.c
Normal file
122
nostrdb/ccan/ccan/crypto/sha256/benchmarks/double-sha-bench.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/* Bitcoin does a lot of SHA of SHA. Benchmark that. */
|
||||
#include <ccan/crypto/sha256/sha256.c>
|
||||
#include <ccan/time/time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void sha256_avx(void *input_data, uint32_t digest[8], uint64_t num_blks);
|
||||
void sha256_rorx(void *input_data, uint32_t digest[8], uint64_t num_blks);
|
||||
void sha256_rorx_x8ms(void *input_data, uint32_t digest[8], uint64_t num_blks);
|
||||
void sha256_sse4(void *input_data, uint32_t digest[8], uint64_t num_blks);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct timeabs start;
|
||||
struct timerel diff;
|
||||
size_t i, n;
|
||||
union {
|
||||
struct sha256 h;
|
||||
uint32_t u32[16];
|
||||
uint8_t u8[64];
|
||||
} block;
|
||||
|
||||
n = atoi(argv[1] ? argv[1] : "1000000");
|
||||
memset(&block, 0, sizeof(block));
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
sha256(&block.h, &block.h, sizeof(block.h));
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Normal gave %02x%02x%02x%02x%02x%02x... in %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
/* Now, don't re-initialize every time; use Transform */
|
||||
memset(&block, 0, sizeof(block));
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
block.u8[sizeof(block.h)] = 0x80;
|
||||
/* Size is 256 bits */
|
||||
block.u8[sizeof(block)-2] = 1;
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sha256_ctx ctx = SHA256_INIT;
|
||||
size_t j;
|
||||
Transform(ctx.s, block.u32);
|
||||
for (j = 0; j < sizeof(ctx.s) / sizeof(ctx.s[0]); j++)
|
||||
block.h.u.u32[j] = cpu_to_be32(ctx.s[j]);
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Transform gave %02x%02x%02x%02x%02x%02x... in %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
/* Now, assembler variants */
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sha256_ctx ctx = SHA256_INIT;
|
||||
size_t j;
|
||||
sha256_rorx(block.u32, ctx.s, 1);
|
||||
for (j = 0; j < sizeof(ctx.s) / sizeof(ctx.s[0]); j++)
|
||||
block.h.u.u32[j] = cpu_to_be32(ctx.s[j]);
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Asm rorx for %02x%02x%02x%02x%02x%02x... is %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sha256_ctx ctx = SHA256_INIT;
|
||||
size_t j;
|
||||
sha256_sse4(block.u32, ctx.s, 1);
|
||||
for (j = 0; j < sizeof(ctx.s) / sizeof(ctx.s[0]); j++)
|
||||
block.h.u.u32[j] = cpu_to_be32(ctx.s[j]);
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Asm SSE4 for %02x%02x%02x%02x%02x%02x... is %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sha256_ctx ctx = SHA256_INIT;
|
||||
size_t j;
|
||||
sha256_rorx_x8ms(block.u32, ctx.s, 1);
|
||||
for (j = 0; j < sizeof(ctx.s) / sizeof(ctx.s[0]); j++)
|
||||
block.h.u.u32[j] = cpu_to_be32(ctx.s[j]);
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Asm RORx-x8ms for %02x%02x%02x%02x%02x%02x... is %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
sha256(&block.h, &n, sizeof(n));
|
||||
start = time_now();
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sha256_ctx ctx = SHA256_INIT;
|
||||
size_t j;
|
||||
sha256_avx(block.u32, ctx.s, 1);
|
||||
for (j = 0; j < sizeof(ctx.s) / sizeof(ctx.s[0]); j++)
|
||||
block.h.u.u32[j] = cpu_to_be32(ctx.s[j]);
|
||||
}
|
||||
diff = time_divide(time_between(time_now(), start), n);
|
||||
printf("Asm AVX for %02x%02x%02x%02x%02x%02x... is %llu nsec\n",
|
||||
block.h.u.u8[0], block.h.u.u8[1], block.h.u.u8[2],
|
||||
block.h.u.u8[3], block.h.u.u8[4], block.h.u.u8[5],
|
||||
(unsigned long long)time_to_nsec(diff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
Copyright (c) 2012, Intel Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of the Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
586
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx1.asm
Normal file
586
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx1.asm
Normal file
@@ -0,0 +1,586 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Copyright (c) 2012, Intel Corporation
|
||||
;
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are
|
||||
; met:
|
||||
;
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
;
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the
|
||||
; distribution.
|
||||
;
|
||||
; * Neither the name of the Intel Corporation nor the names of its
|
||||
; contributors may be used to endorse or promote products derived from
|
||||
; this software without specific prior written permission.
|
||||
;
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; Example YASM command lines:
|
||||
; Windows: yasm -Xvc -f x64 -rnasm -pnasm -o sha256_avx1.obj -g cv8 sha256_avx1.asm
|
||||
; Linux: yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o sha256_avx1.o sha256_avx1.asm
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; This code is described in an Intel White-Paper:
|
||||
; "Fast SHA-256 Implementations on Intel Architecture Processors"
|
||||
;
|
||||
; To find it, surf to http://www.intel.com/p/en_US/embedded
|
||||
; and search for that title.
|
||||
; The paper is expected to be released roughly at the end of April, 2012
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; This code schedules 1 blocks at a time, with 4 lanes per block
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define VMOVDQ vmovdqu ;; assume buffers not aligned
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Define Macros
|
||||
|
||||
; addm [mem], reg
|
||||
; Add reg to mem using reg-mem add and store
|
||||
%macro addm 2
|
||||
add %2, %1
|
||||
mov %1, %2
|
||||
%endm
|
||||
|
||||
%macro MY_ROR 2
|
||||
shld %1,%1,(32-(%2))
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; COPY_XMM_AND_BSWAP xmm, [mem], byte_flip_mask
|
||||
; Load xmm with mem and byte swap each dword
|
||||
%macro COPY_XMM_AND_BSWAP 3
|
||||
VMOVDQ %1, %2
|
||||
vpshufb %1, %1, %3
|
||||
%endmacro
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define X0 xmm4
|
||||
%define X1 xmm5
|
||||
%define X2 xmm6
|
||||
%define X3 xmm7
|
||||
|
||||
%define XTMP0 xmm0
|
||||
%define XTMP1 xmm1
|
||||
%define XTMP2 xmm2
|
||||
%define XTMP3 xmm3
|
||||
%define XTMP4 xmm8
|
||||
%define XFER xmm9
|
||||
%define XTMP5 xmm11
|
||||
|
||||
%define SHUF_00BA xmm10 ; shuffle xBxA -> 00BA
|
||||
%define SHUF_DC00 xmm12 ; shuffle xDxC -> DC00
|
||||
%define BYTE_FLIP_MASK xmm13
|
||||
|
||||
%ifdef LINUX
|
||||
%define NUM_BLKS rdx ; 3rd arg
|
||||
%define CTX rsi ; 2nd arg
|
||||
%define INP rdi ; 1st arg
|
||||
|
||||
%define SRND rdi ; clobbers INP
|
||||
%define c ecx
|
||||
%define d r8d
|
||||
%define e edx
|
||||
%else
|
||||
%define NUM_BLKS r8 ; 3rd arg
|
||||
%define CTX rdx ; 2nd arg
|
||||
%define INP rcx ; 1st arg
|
||||
|
||||
%define SRND rcx ; clobbers INP
|
||||
%define c edi
|
||||
%define d esi
|
||||
%define e r8d
|
||||
|
||||
%endif
|
||||
%define TBL rbp
|
||||
%define a eax
|
||||
%define b ebx
|
||||
|
||||
%define f r9d
|
||||
%define g r10d
|
||||
%define h r11d
|
||||
|
||||
%define y0 r13d
|
||||
%define y1 r14d
|
||||
%define y2 r15d
|
||||
|
||||
|
||||
_INP_END_SIZE equ 8
|
||||
_INP_SIZE equ 8
|
||||
_XFER_SIZE equ 8
|
||||
%ifdef LINUX
|
||||
_XMM_SAVE_SIZE equ 0
|
||||
%else
|
||||
_XMM_SAVE_SIZE equ 8*16
|
||||
%endif
|
||||
; STACK_SIZE plus pushes must be an odd multiple of 8
|
||||
_ALIGN_SIZE equ 8
|
||||
|
||||
_INP_END equ 0
|
||||
_INP equ _INP_END + _INP_END_SIZE
|
||||
_XFER equ _INP + _INP_SIZE
|
||||
_XMM_SAVE equ _XFER + _XFER_SIZE + _ALIGN_SIZE
|
||||
STACK_SIZE equ _XMM_SAVE + _XMM_SAVE_SIZE
|
||||
|
||||
; rotate_Xs
|
||||
; Rotate values of symbols X0...X3
|
||||
%macro rotate_Xs 0
|
||||
%xdefine X_ X0
|
||||
%xdefine X0 X1
|
||||
%xdefine X1 X2
|
||||
%xdefine X2 X3
|
||||
%xdefine X3 X_
|
||||
%endm
|
||||
|
||||
; ROTATE_ARGS
|
||||
; Rotate values of symbols a...h
|
||||
%macro ROTATE_ARGS 0
|
||||
%xdefine TMP_ h
|
||||
%xdefine h g
|
||||
%xdefine g f
|
||||
%xdefine f e
|
||||
%xdefine e d
|
||||
%xdefine d c
|
||||
%xdefine c b
|
||||
%xdefine b a
|
||||
%xdefine a TMP_
|
||||
%endm
|
||||
|
||||
%macro FOUR_ROUNDS_AND_SCHED 0
|
||||
;; compute s0 four at a time and s1 two at a time
|
||||
;; compute W[-16] + W[-7] 4 at a time
|
||||
;vmovdqa XTMP0, X3
|
||||
mov y0, e ; y0 = e
|
||||
MY_ROR y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
vpalignr XTMP0, X3, X2, 4 ; XTMP0 = W[-7]
|
||||
MY_ROR y1, (22-13) ; y1 = a >> (22-13)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
MY_ROR y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
;vmovdqa XTMP1, X1
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
xor y2, g ; y2 = f^g
|
||||
vpaddd XTMP0, XTMP0, X0 ; XTMP0 = W[-7] + W[-16]
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
MY_ROR y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
;; compute s0
|
||||
vpalignr XTMP1, X1, X0, 4 ; XTMP1 = W[-15]
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
MY_ROR y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
|
||||
|
||||
MY_ROR y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 0*4] ; y2 = k + w + S1 + CH
|
||||
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
|
||||
vpsrld XTMP2, XTMP1, 7
|
||||
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
|
||||
vpslld XTMP3, XTMP1, (32-7)
|
||||
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
|
||||
vpor XTMP3, XTMP3, XTMP2 ; XTMP1 = W[-15] nostrdb: MY_ROR 7
|
||||
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
mov y0, e ; y0 = e
|
||||
mov y1, a ; y1 = a
|
||||
|
||||
|
||||
MY_ROR y0, (25-11) ; y0 = e >> (25-11)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
MY_ROR y1, (22-13) ; y1 = a >> (22-13)
|
||||
|
||||
vpsrld XTMP2, XTMP1,18
|
||||
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
MY_ROR y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
xor y2, g ; y2 = f^g
|
||||
|
||||
vpsrld XTMP4, XTMP1, 3 ; XTMP4 = W[-15] nostrdb: >> 3
|
||||
|
||||
MY_ROR y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
MY_ROR y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
|
||||
vpslld XTMP1, XTMP1, (32-18)
|
||||
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
|
||||
vpxor XTMP3, XTMP3, XTMP1
|
||||
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 1*4] ; y2 = k + w + S1 + CH
|
||||
MY_ROR y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
|
||||
vpxor XTMP3, XTMP3, XTMP2 ; XTMP1 = W[-15] nostrdb: MY_ROR 7 ^ W[-15] MY_ROR 18
|
||||
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
|
||||
vpxor XTMP1, XTMP3, XTMP4 ; XTMP1 = s0
|
||||
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
;; compute low s1
|
||||
vpshufd XTMP2, X3, 11111010b ; XTMP2 = W[-2] {BBAA}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
vpaddd XTMP0, XTMP0, XTMP1 ; XTMP0 = W[-16] + W[-7] + s0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
;vmovdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {BBAA}
|
||||
|
||||
mov y0, e ; y0 = e
|
||||
mov y1, a ; y1 = a
|
||||
MY_ROR y0, (25-11) ; y0 = e >> (25-11)
|
||||
|
||||
;vmovdqa XTMP4, XTMP2 ; XTMP4 = W[-2] {BBAA}
|
||||
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
MY_ROR y1, (22-13) ; y1 = a >> (22-13)
|
||||
mov y2, f ; y2 = f
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
MY_ROR y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
|
||||
vpsrld XTMP4, XTMP2, 10 ; XTMP4 = W[-2] >> 10 {BBAA}
|
||||
|
||||
xor y2, g ; y2 = f^g
|
||||
|
||||
vpsrlq XTMP3, XTMP2, 19 ; XTMP3 = W[-2] MY_ROR 19 {xBxA}
|
||||
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
|
||||
vpsrlq XTMP2, XTMP2, 17 ; XTMP2 = W[-2] MY_ROR 17 {xBxA}
|
||||
|
||||
MY_ROR y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
MY_ROR y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
vpxor XTMP2, XTMP2, XTMP3
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
MY_ROR y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, [rsp + _XFER + 2*4] ; y2 = k + w + S1 + CH
|
||||
vpxor XTMP4, XTMP4, XTMP2 ; XTMP4 = s1 {xBxA}
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
vpshufb XTMP4, XTMP4, SHUF_00BA ; XTMP4 = s1 {00BA}
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
vpaddd XTMP0, XTMP0, XTMP4 ; XTMP0 = {..., ..., W[1], W[0]}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
;; compute high s1
|
||||
vpshufd XTMP2, XTMP0, 01010000b ; XTMP2 = W[-2] {DDCC}
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
;vmovdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {DDCC}
|
||||
mov y0, e ; y0 = e
|
||||
MY_ROR y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
;vmovdqa XTMP5, XTMP2 ; XTMP5 = W[-2] {DDCC}
|
||||
MY_ROR y1, (22-13) ; y1 = a >> (22-13)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
MY_ROR y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
|
||||
vpsrld XTMP5, XTMP2, 10 ; XTMP5 = W[-2] >> 10 {DDCC}
|
||||
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
xor y2, g ; y2 = f^g
|
||||
|
||||
vpsrlq XTMP3, XTMP2, 19 ; XTMP3 = W[-2] MY_ROR 19 {xDxC}
|
||||
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
MY_ROR y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
|
||||
vpsrlq XTMP2, XTMP2, 17 ; XTMP2 = W[-2] MY_ROR 17 {xDxC}
|
||||
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
MY_ROR y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
|
||||
vpxor XTMP2, XTMP2, XTMP3
|
||||
|
||||
MY_ROR y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 3*4] ; y2 = k + w + S1 + CH
|
||||
vpxor XTMP5, XTMP5, XTMP2 ; XTMP5 = s1 {xDxC}
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
vpshufb XTMP5, XTMP5, SHUF_DC00 ; XTMP5 = s1 {DC00}
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
vpaddd X0, XTMP5, XTMP0 ; X0 = {W[3], W[2], W[1], W[0]}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
rotate_Xs
|
||||
%endm
|
||||
|
||||
;; input is [rsp + _XFER + %1 * 4]
|
||||
%macro DO_ROUND 1
|
||||
mov y0, e ; y0 = e
|
||||
MY_ROR y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
MY_ROR y1, (22-13) ; y1 = a >> (22-13)
|
||||
mov y2, f ; y2 = f
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
MY_ROR y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
xor y2, g ; y2 = f^g
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
MY_ROR y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
MY_ROR y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
MY_ROR y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, [rsp + _XFER + %1 * 4] ; y2 = k + w + S1 + CH
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
ROTATE_ARGS
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; void sha256_avx(void *input_data, UINT32 digest[8], UINT64 num_blks)
|
||||
;; arg 1 : pointer to input data
|
||||
;; arg 2 : pointer to digest
|
||||
;; arg 3 : Num blocks
|
||||
section .text
|
||||
global sha256_avx
|
||||
align 32
|
||||
sha256_avx:
|
||||
push rbx
|
||||
%ifndef LINUX
|
||||
push rsi
|
||||
push rdi
|
||||
%endif
|
||||
push rbp
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sub rsp,STACK_SIZE
|
||||
%ifndef LINUX
|
||||
vmovdqa [rsp + _XMM_SAVE + 0*16],xmm6
|
||||
vmovdqa [rsp + _XMM_SAVE + 1*16],xmm7
|
||||
vmovdqa [rsp + _XMM_SAVE + 2*16],xmm8
|
||||
vmovdqa [rsp + _XMM_SAVE + 3*16],xmm9
|
||||
vmovdqa [rsp + _XMM_SAVE + 4*16],xmm10
|
||||
vmovdqa [rsp + _XMM_SAVE + 5*16],xmm11
|
||||
vmovdqa [rsp + _XMM_SAVE + 6*16],xmm12
|
||||
vmovdqa [rsp + _XMM_SAVE + 7*16],xmm13
|
||||
%endif
|
||||
|
||||
shl NUM_BLKS, 6 ; convert to bytes
|
||||
jz done_hash
|
||||
add NUM_BLKS, INP ; pointer to end of data
|
||||
mov [rsp + _INP_END], NUM_BLKS
|
||||
|
||||
;; load initial digest
|
||||
mov a,[4*0 + CTX]
|
||||
mov b,[4*1 + CTX]
|
||||
mov c,[4*2 + CTX]
|
||||
mov d,[4*3 + CTX]
|
||||
mov e,[4*4 + CTX]
|
||||
mov f,[4*5 + CTX]
|
||||
mov g,[4*6 + CTX]
|
||||
mov h,[4*7 + CTX]
|
||||
|
||||
vmovdqa BYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]
|
||||
vmovdqa SHUF_00BA, [_SHUF_00BA wrt rip]
|
||||
vmovdqa SHUF_DC00, [_SHUF_DC00 wrt rip]
|
||||
|
||||
loop0:
|
||||
lea TBL,[K256 wrt rip]
|
||||
|
||||
;; byte swap first 16 dwords
|
||||
COPY_XMM_AND_BSWAP X0, [INP + 0*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X1, [INP + 1*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X2, [INP + 2*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X3, [INP + 3*16], BYTE_FLIP_MASK
|
||||
|
||||
mov [rsp + _INP], INP
|
||||
|
||||
;; schedule 48 input dwords, by doing 3 rounds of 16 each
|
||||
mov SRND, 3
|
||||
align 16
|
||||
loop1:
|
||||
vpaddd XFER, X0, [TBL + 0*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
vpaddd XFER, X0, [TBL + 1*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
vpaddd XFER, X0, [TBL + 2*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
vpaddd XFER, X0, [TBL + 3*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
add TBL, 4*16
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
sub SRND, 1
|
||||
jne loop1
|
||||
|
||||
mov SRND, 2
|
||||
loop2:
|
||||
vpaddd XFER, X0, [TBL + 0*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
DO_ROUND 0
|
||||
DO_ROUND 1
|
||||
DO_ROUND 2
|
||||
DO_ROUND 3
|
||||
|
||||
vpaddd XFER, X1, [TBL + 1*16]
|
||||
vmovdqa [rsp + _XFER], XFER
|
||||
add TBL, 2*16
|
||||
DO_ROUND 0
|
||||
DO_ROUND 1
|
||||
DO_ROUND 2
|
||||
DO_ROUND 3
|
||||
|
||||
vmovdqa X0, X2
|
||||
vmovdqa X1, X3
|
||||
|
||||
sub SRND, 1
|
||||
jne loop2
|
||||
|
||||
|
||||
addm [4*0 + CTX],a
|
||||
addm [4*1 + CTX],b
|
||||
addm [4*2 + CTX],c
|
||||
addm [4*3 + CTX],d
|
||||
addm [4*4 + CTX],e
|
||||
addm [4*5 + CTX],f
|
||||
addm [4*6 + CTX],g
|
||||
addm [4*7 + CTX],h
|
||||
|
||||
mov INP, [rsp + _INP]
|
||||
add INP, 64
|
||||
cmp INP, [rsp + _INP_END]
|
||||
jne loop0
|
||||
|
||||
done_hash:
|
||||
%ifndef LINUX
|
||||
vmovdqa xmm6,[rsp + _XMM_SAVE + 0*16]
|
||||
vmovdqa xmm7,[rsp + _XMM_SAVE + 1*16]
|
||||
vmovdqa xmm8,[rsp + _XMM_SAVE + 2*16]
|
||||
vmovdqa xmm9,[rsp + _XMM_SAVE + 3*16]
|
||||
vmovdqa xmm10,[rsp + _XMM_SAVE + 4*16]
|
||||
vmovdqa xmm11,[rsp + _XMM_SAVE + 5*16]
|
||||
vmovdqa xmm12,[rsp + _XMM_SAVE + 6*16]
|
||||
vmovdqa xmm13,[rsp + _XMM_SAVE + 7*16]
|
||||
%endif
|
||||
|
||||
|
||||
add rsp, STACK_SIZE
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop rbp
|
||||
%ifndef LINUX
|
||||
pop rdi
|
||||
pop rsi
|
||||
%endif
|
||||
pop rbx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
section .data
|
||||
align 64
|
||||
K256:
|
||||
dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
dd 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
dd 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
dd 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
dd 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
dd 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
dd 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
dd 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
dd 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
dd 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
dd 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
dd 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
dd 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
dd 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
dd 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
dd 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
|
||||
PSHUFFLE_BYTE_FLIP_MASK: ddq 0x0c0d0e0f08090a0b0405060700010203
|
||||
|
||||
; shuffle xBxA -> 00BA
|
||||
_SHUF_00BA: ddq 0xFFFFFFFFFFFFFFFF0b0a090803020100
|
||||
|
||||
; shuffle xDxC -> DC00
|
||||
_SHUF_DC00: ddq 0x0b0a090803020100FFFFFFFFFFFFFFFF
|
||||
826
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx2_rorx2.asm
Normal file
826
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx2_rorx2.asm
Normal file
@@ -0,0 +1,826 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Copyright (c) 2012, Intel Corporation
|
||||
;
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are
|
||||
; met:
|
||||
;
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
;
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the
|
||||
; distribution.
|
||||
;
|
||||
; * Neither the name of the Intel Corporation nor the names of its
|
||||
; contributors may be used to endorse or promote products derived from
|
||||
; this software without specific prior written permission.
|
||||
;
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; Example YASM command lines:
|
||||
; Windows: yasm -Xvc -f x64 -rnasm -pnasm -o sha256_avx2_rorx2.obj -g cv8 sha256_avx2_rorx2.asm
|
||||
; Linux: yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o sha256_avx2_rorx2.o sha256_avx2_rorx2.asm
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; This code is described in an Intel White-Paper:
|
||||
; "Fast SHA-256 Implementations on Intel Architecture Processors"
|
||||
;
|
||||
; To find it, surf to http://www.intel.com/p/en_US/embedded
|
||||
; and search for that title.
|
||||
; The paper is expected to be released roughly at the end of April, 2012
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; This code schedules 2 blocks at a time, with 4 lanes per block
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define VMOVDQ vmovdqu ;; assume buffers not aligned
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Define Macros
|
||||
|
||||
; addm [mem], reg
|
||||
; Add reg to mem using reg-mem add and store
|
||||
%macro addm 2
|
||||
add %2, %1
|
||||
mov %1, %2
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define X0 ymm4
|
||||
%define X1 ymm5
|
||||
%define X2 ymm6
|
||||
%define X3 ymm7
|
||||
|
||||
; XMM versions of above
|
||||
%define XWORD0 xmm4
|
||||
%define XWORD1 xmm5
|
||||
%define XWORD2 xmm6
|
||||
%define XWORD3 xmm7
|
||||
|
||||
%define XTMP0 ymm0
|
||||
%define XTMP1 ymm1
|
||||
%define XTMP2 ymm2
|
||||
%define XTMP3 ymm3
|
||||
%define XTMP4 ymm8
|
||||
%define XFER ymm9
|
||||
%define XTMP5 ymm11
|
||||
|
||||
%define SHUF_00BA ymm10 ; shuffle xBxA -> 00BA
|
||||
%define SHUF_DC00 ymm12 ; shuffle xDxC -> DC00
|
||||
%define BYTE_FLIP_MASK ymm13
|
||||
|
||||
%define X_BYTE_FLIP_MASK xmm13 ; XMM version of BYTE_FLIP_MASK
|
||||
|
||||
%ifdef LINUX
|
||||
%define NUM_BLKS rdx ; 3rd arg
|
||||
%define CTX rsi ; 2nd arg
|
||||
%define INP rdi ; 1st arg
|
||||
%define c ecx
|
||||
%define d r8d
|
||||
%define e edx ; clobbers NUM_BLKS
|
||||
%define y3 edi ; clobbers INP
|
||||
%else
|
||||
%define NUM_BLKS r8 ; 3rd arg
|
||||
%define CTX rdx ; 2nd arg
|
||||
%define INP rcx ; 1st arg
|
||||
%define c edi
|
||||
%define d esi
|
||||
%define e r8d ; clobbers NUM_BLKS
|
||||
%define y3 ecx ; clobbers INP
|
||||
|
||||
%endif
|
||||
|
||||
|
||||
%define TBL rbp
|
||||
%define SRND CTX ; SRND is same register as CTX
|
||||
|
||||
%define a eax
|
||||
%define b ebx
|
||||
%define f r9d
|
||||
%define g r10d
|
||||
%define h r11d
|
||||
%define old_h r11d
|
||||
|
||||
%define T1 r12d
|
||||
%define y0 r13d
|
||||
%define y1 r14d
|
||||
%define y2 r15d
|
||||
|
||||
|
||||
_XFER_SIZE equ 2*64*4 ; 2 blocks, 64 rounds, 4 bytes/round
|
||||
%ifdef LINUX
|
||||
_XMM_SAVE_SIZE equ 0
|
||||
%else
|
||||
_XMM_SAVE_SIZE equ 8*16
|
||||
%endif
|
||||
_INP_END_SIZE equ 8
|
||||
_INP_SIZE equ 8
|
||||
_CTX_SIZE equ 8
|
||||
_RSP_SIZE equ 8
|
||||
|
||||
_XFER equ 0
|
||||
_XMM_SAVE equ _XFER + _XFER_SIZE
|
||||
_INP_END equ _XMM_SAVE + _XMM_SAVE_SIZE
|
||||
_INP equ _INP_END + _INP_END_SIZE
|
||||
_CTX equ _INP + _INP_SIZE
|
||||
_RSP equ _CTX + _CTX_SIZE
|
||||
STACK_SIZE equ _RSP + _RSP_SIZE
|
||||
|
||||
; rotate_Xs
|
||||
; Rotate values of symbols X0...X3
|
||||
%macro rotate_Xs 0
|
||||
%xdefine X_ X0
|
||||
%xdefine X0 X1
|
||||
%xdefine X1 X2
|
||||
%xdefine X2 X3
|
||||
%xdefine X3 X_
|
||||
%endm
|
||||
|
||||
; ROTATE_ARGS
|
||||
; Rotate values of symbols a...h
|
||||
%macro ROTATE_ARGS 0
|
||||
%xdefine old_h h
|
||||
%xdefine TMP_ h
|
||||
%xdefine h g
|
||||
%xdefine g f
|
||||
%xdefine f e
|
||||
%xdefine e d
|
||||
%xdefine d c
|
||||
%xdefine c b
|
||||
%xdefine b a
|
||||
%xdefine a TMP_
|
||||
%endm
|
||||
|
||||
%macro FOUR_ROUNDS_AND_SCHED 1
|
||||
%define %%XFER %1
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
|
||||
add h, dword[%%XFER+0*4] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
vpalignr XTMP0, X3, X2, 4 ; XTMP0 = W[-7]
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
vpaddd XTMP0, XTMP0, X0 ; XTMP0 = W[-7] + W[-16]; y1 = (e >> 6) ; S1
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
vpalignr XTMP1, X1, X0, 4 ; XTMP1 = W[-15]
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
vpsrld XTMP2, XTMP1, 7
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
vpslld XTMP3, XTMP1, (32-7)
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
vpor XTMP3, XTMP3, XTMP2 ; XTMP3 = W[-15] nostrdb: ror 7
|
||||
|
||||
vpsrld XTMP2, XTMP1,18
|
||||
add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
add h, dword[%%XFER+1*4] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
|
||||
vpsrld XTMP4, XTMP1, 3 ; XTMP4 = W[-15] nostrdb: >> 3
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
|
||||
vpslld XTMP1, XTMP1, (32-18)
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
|
||||
vpxor XTMP3, XTMP3, XTMP1
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
|
||||
vpxor XTMP3, XTMP3, XTMP2 ; XTMP3 = W[-15] nostrdb: ror 7 ^ W[-15] ror 18
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
vpxor XTMP1, XTMP3, XTMP4 ; XTMP1 = s0
|
||||
vpshufd XTMP2, X3, 11111010b ; XTMP2 = W[-2] {BBAA}
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
vpaddd XTMP0, XTMP0, XTMP1 ; XTMP0 = W[-16] + W[-7] + s0
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
vpsrld XTMP4, XTMP2, 10 ; XTMP4 = W[-2] >> 10 {BBAA}
|
||||
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
add h, [%%XFER+2*4] ; h = k + w + h ; --
|
||||
|
||||
vpsrlq XTMP3, XTMP2, 19 ; XTMP3 = W[-2] ror 19 {xBxA}
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
mov y2, f ; y2 = f ; CH
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
vpsrlq XTMP2, XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xBxA}
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
vpxor XTMP2, XTMP2, XTMP3
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
vpxor XTMP4, XTMP4, XTMP2 ; XTMP4 = s1 {xBxA}
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
|
||||
vpshufb XTMP4, XTMP4, SHUF_00BA ; XTMP4 = s1 {00BA}
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
vpaddd XTMP0, XTMP0, XTMP4 ; XTMP0 = {..., ..., W[1], W[0]}
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
vpshufd XTMP2, XTMP0, 01010000b ; XTMP2 = W[-2] {DDCC}
|
||||
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
|
||||
add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
add h, dword[%%XFER+3*4] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
|
||||
vpsrld XTMP5, XTMP2, 10 ; XTMP5 = W[-2] >> 10 {DDCC}
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
|
||||
vpsrlq XTMP3, XTMP2, 19 ; XTMP3 = W[-2] ror 19 {xDxC}
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
|
||||
vpsrlq XTMP2, XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xDxC}
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
|
||||
vpxor XTMP2, XTMP2, XTMP3
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
vpxor XTMP5, XTMP5, XTMP2 ; XTMP5 = s1 {xDxC}
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
vpshufb XTMP5, XTMP5, SHUF_DC00 ; XTMP5 = s1 {DC00}
|
||||
|
||||
vpaddd X0, XTMP5, XTMP0 ; X0 = {W[3], W[2], W[1], W[0]}
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
ROTATE_ARGS
|
||||
rotate_Xs
|
||||
%endm
|
||||
|
||||
%macro DO_4ROUNDS 1
|
||||
%define %%XFER %1
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
add h, dword[%%XFER + 4*0] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
|
||||
|
||||
;add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
|
||||
;add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
add old_h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
add old_h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
add h, dword[%%XFER + 4*1] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
|
||||
|
||||
;add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
|
||||
;add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 2 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
add old_h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
add old_h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
add h, dword[%%XFER + 4*2] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
|
||||
|
||||
;add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
|
||||
;add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RND N + 3 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
add old_h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
mov y2, f ; y2 = f ; CH
|
||||
rorx y0, e, 25 ; y0 = e >> 25 ; S1A
|
||||
rorx y1, e, 11 ; y1 = e >> 11 ; S1B
|
||||
xor y2, g ; y2 = f^g ; CH
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ; S1
|
||||
rorx y1, e, 6 ; y1 = (e >> 6) ; S1
|
||||
and y2, e ; y2 = (f^g)&e ; CH
|
||||
add old_h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
xor y0, y1 ; y0 = (e>>25) ^ (e>>11) ^ (e>>6) ; S1
|
||||
rorx T1, a, 13 ; T1 = a >> 13 ; S0B
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g ; CH
|
||||
rorx y1, a, 22 ; y1 = a >> 22 ; S0A
|
||||
mov y3, a ; y3 = a ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ; S0
|
||||
rorx T1, a, 2 ; T1 = (a >> 2) ; S0
|
||||
add h, dword[%%XFER + 4*3] ; h = k + w + h ; --
|
||||
or y3, c ; y3 = a|c ; MAJA
|
||||
|
||||
xor y1, T1 ; y1 = (a>>22) ^ (a>>13) ^ (a>>2) ; S0
|
||||
mov T1, a ; T1 = a ; MAJB
|
||||
and y3, b ; y3 = (a|c)&b ; MAJA
|
||||
and T1, c ; T1 = a&c ; MAJB
|
||||
add y2, y0 ; y2 = S1 + CH ; --
|
||||
|
||||
|
||||
add d, h ; d = k + w + h + d ; --
|
||||
or y3, T1 ; y3 = MAJ = (a|c)&b)|(a&c) ; MAJ
|
||||
add h, y1 ; h = k + w + h + S0 ; --
|
||||
|
||||
add d, y2 ; d = k + w + h + d + S1 + CH = d + t1 ; --
|
||||
|
||||
|
||||
add h, y2 ; h = k + w + h + S0 + S1 + CH = t1 + S0; --
|
||||
|
||||
add h, y3 ; h = t1 + S0 + MAJ ; --
|
||||
|
||||
ROTATE_ARGS
|
||||
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; void sha256_rorx(void *input_data, UINT32 digest[8], UINT64 num_blks)
|
||||
;; arg 1 : pointer to input data
|
||||
;; arg 2 : pointer to digest
|
||||
;; arg 3 : Num blocks
|
||||
section .text
|
||||
global sha256_rorx
|
||||
align 32
|
||||
sha256_rorx:
|
||||
push rbx
|
||||
%ifndef LINUX
|
||||
push rsi
|
||||
push rdi
|
||||
%endif
|
||||
push rbp
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
mov rax, rsp
|
||||
sub rsp,STACK_SIZE
|
||||
and rsp, -32
|
||||
mov [rsp + _RSP], rax
|
||||
|
||||
%ifndef LINUX
|
||||
vmovdqa [rsp + _XMM_SAVE + 0*16],xmm6
|
||||
vmovdqa [rsp + _XMM_SAVE + 1*16],xmm7
|
||||
vmovdqa [rsp + _XMM_SAVE + 2*16],xmm8
|
||||
vmovdqa [rsp + _XMM_SAVE + 3*16],xmm9
|
||||
vmovdqa [rsp + _XMM_SAVE + 4*16],xmm10
|
||||
vmovdqa [rsp + _XMM_SAVE + 5*16],xmm11
|
||||
vmovdqa [rsp + _XMM_SAVE + 6*16],xmm12
|
||||
vmovdqa [rsp + _XMM_SAVE + 7*16],xmm13
|
||||
%endif
|
||||
|
||||
shl NUM_BLKS, 6 ; convert to bytes
|
||||
jz done_hash
|
||||
lea NUM_BLKS, [NUM_BLKS + INP - 64] ; pointer to last block
|
||||
mov [rsp + _INP_END], NUM_BLKS
|
||||
|
||||
cmp INP, NUM_BLKS
|
||||
je only_one_block
|
||||
|
||||
;; load initial digest
|
||||
mov a,[4*0 + CTX]
|
||||
mov b,[4*1 + CTX]
|
||||
mov c,[4*2 + CTX]
|
||||
mov d,[4*3 + CTX]
|
||||
mov e,[4*4 + CTX]
|
||||
mov f,[4*5 + CTX]
|
||||
mov g,[4*6 + CTX]
|
||||
mov h,[4*7 + CTX]
|
||||
|
||||
vmovdqa BYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]
|
||||
vmovdqa SHUF_00BA, [_SHUF_00BA wrt rip]
|
||||
vmovdqa SHUF_DC00, [_SHUF_DC00 wrt rip]
|
||||
|
||||
mov [rsp + _CTX], CTX
|
||||
|
||||
loop0:
|
||||
lea TBL,[K256 wrt rip]
|
||||
|
||||
;; Load first 16 dwords from two blocks
|
||||
VMOVDQ XTMP0, [INP + 0*32]
|
||||
VMOVDQ XTMP1, [INP + 1*32]
|
||||
VMOVDQ XTMP2, [INP + 2*32]
|
||||
VMOVDQ XTMP3, [INP + 3*32]
|
||||
|
||||
;; byte swap data
|
||||
vpshufb XTMP0, XTMP0, BYTE_FLIP_MASK
|
||||
vpshufb XTMP1, XTMP1, BYTE_FLIP_MASK
|
||||
vpshufb XTMP2, XTMP2, BYTE_FLIP_MASK
|
||||
vpshufb XTMP3, XTMP3, BYTE_FLIP_MASK
|
||||
|
||||
;; transpose data into high/low halves
|
||||
vperm2i128 X0, XTMP0, XTMP2, 0x20
|
||||
vperm2i128 X1, XTMP0, XTMP2, 0x31
|
||||
vperm2i128 X2, XTMP1, XTMP3, 0x20
|
||||
vperm2i128 X3, XTMP1, XTMP3, 0x31
|
||||
|
||||
last_block_enter:
|
||||
add INP, 64
|
||||
mov [rsp + _INP], INP
|
||||
|
||||
;; schedule 48 input dwords, by doing 3 rounds of 12 each
|
||||
xor SRND, SRND
|
||||
|
||||
align 16
|
||||
loop1:
|
||||
vpaddd XFER, X0, [TBL + SRND + 0*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 0*32], XFER
|
||||
FOUR_ROUNDS_AND_SCHED rsp + _XFER + SRND + 0*32
|
||||
|
||||
vpaddd XFER, X0, [TBL + SRND + 1*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 1*32], XFER
|
||||
FOUR_ROUNDS_AND_SCHED rsp + _XFER + SRND + 1*32
|
||||
|
||||
vpaddd XFER, X0, [TBL + SRND + 2*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 2*32], XFER
|
||||
FOUR_ROUNDS_AND_SCHED rsp + _XFER + SRND + 2*32
|
||||
|
||||
vpaddd XFER, X0, [TBL + SRND + 3*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 3*32], XFER
|
||||
FOUR_ROUNDS_AND_SCHED rsp + _XFER + SRND + 3*32
|
||||
|
||||
add SRND, 4*32
|
||||
cmp SRND, 3 * 4*32
|
||||
jb loop1
|
||||
|
||||
loop2:
|
||||
;; Do last 16 rounds with no scheduling
|
||||
vpaddd XFER, X0, [TBL + SRND + 0*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 0*32], XFER
|
||||
DO_4ROUNDS rsp + _XFER + SRND + 0*32
|
||||
vpaddd XFER, X1, [TBL + SRND + 1*32]
|
||||
vmovdqa [rsp + _XFER + SRND + 1*32], XFER
|
||||
DO_4ROUNDS rsp + _XFER + SRND + 1*32
|
||||
add SRND, 2*32
|
||||
|
||||
vmovdqa X0, X2
|
||||
vmovdqa X1, X3
|
||||
|
||||
cmp SRND, 4 * 4*32
|
||||
jb loop2
|
||||
|
||||
mov CTX, [rsp + _CTX]
|
||||
mov INP, [rsp + _INP]
|
||||
|
||||
addm [4*0 + CTX],a
|
||||
addm [4*1 + CTX],b
|
||||
addm [4*2 + CTX],c
|
||||
addm [4*3 + CTX],d
|
||||
addm [4*4 + CTX],e
|
||||
addm [4*5 + CTX],f
|
||||
addm [4*6 + CTX],g
|
||||
addm [4*7 + CTX],h
|
||||
|
||||
cmp INP, [rsp + _INP_END]
|
||||
ja done_hash
|
||||
|
||||
;;;; Do second block using previously scheduled results
|
||||
xor SRND, SRND
|
||||
align 16
|
||||
loop3:
|
||||
DO_4ROUNDS rsp + _XFER + SRND + 0*32 + 16
|
||||
DO_4ROUNDS rsp + _XFER + SRND + 1*32 + 16
|
||||
add SRND, 2*32
|
||||
cmp SRND, 4 * 4*32
|
||||
jb loop3
|
||||
|
||||
mov CTX, [rsp + _CTX]
|
||||
mov INP, [rsp + _INP]
|
||||
add INP, 64
|
||||
|
||||
addm [4*0 + CTX],a
|
||||
addm [4*1 + CTX],b
|
||||
addm [4*2 + CTX],c
|
||||
addm [4*3 + CTX],d
|
||||
addm [4*4 + CTX],e
|
||||
addm [4*5 + CTX],f
|
||||
addm [4*6 + CTX],g
|
||||
addm [4*7 + CTX],h
|
||||
|
||||
cmp INP, [rsp + _INP_END]
|
||||
jb loop0
|
||||
ja done_hash
|
||||
|
||||
do_last_block:
|
||||
;;;; do last block
|
||||
lea TBL,[K256 wrt rip]
|
||||
|
||||
VMOVDQ XWORD0, [INP + 0*16]
|
||||
VMOVDQ XWORD1, [INP + 1*16]
|
||||
VMOVDQ XWORD2, [INP + 2*16]
|
||||
VMOVDQ XWORD3, [INP + 3*16]
|
||||
|
||||
vpshufb XWORD0, XWORD0, X_BYTE_FLIP_MASK
|
||||
vpshufb XWORD1, XWORD1, X_BYTE_FLIP_MASK
|
||||
vpshufb XWORD2, XWORD2, X_BYTE_FLIP_MASK
|
||||
vpshufb XWORD3, XWORD3, X_BYTE_FLIP_MASK
|
||||
|
||||
jmp last_block_enter
|
||||
|
||||
only_one_block:
|
||||
|
||||
;; load initial digest
|
||||
mov a,[4*0 + CTX]
|
||||
mov b,[4*1 + CTX]
|
||||
mov c,[4*2 + CTX]
|
||||
mov d,[4*3 + CTX]
|
||||
mov e,[4*4 + CTX]
|
||||
mov f,[4*5 + CTX]
|
||||
mov g,[4*6 + CTX]
|
||||
mov h,[4*7 + CTX]
|
||||
|
||||
vmovdqa BYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]
|
||||
vmovdqa SHUF_00BA, [_SHUF_00BA wrt rip]
|
||||
vmovdqa SHUF_DC00, [_SHUF_DC00 wrt rip]
|
||||
|
||||
mov [rsp + _CTX], CTX
|
||||
jmp do_last_block
|
||||
|
||||
done_hash:
|
||||
%ifndef LINUX
|
||||
vmovdqa xmm6,[rsp + _XMM_SAVE + 0*16]
|
||||
vmovdqa xmm7,[rsp + _XMM_SAVE + 1*16]
|
||||
vmovdqa xmm8,[rsp + _XMM_SAVE + 2*16]
|
||||
vmovdqa xmm9,[rsp + _XMM_SAVE + 3*16]
|
||||
vmovdqa xmm10,[rsp + _XMM_SAVE + 4*16]
|
||||
vmovdqa xmm11,[rsp + _XMM_SAVE + 5*16]
|
||||
vmovdqa xmm12,[rsp + _XMM_SAVE + 6*16]
|
||||
vmovdqa xmm13,[rsp + _XMM_SAVE + 7*16]
|
||||
%endif
|
||||
|
||||
mov rsp, [rsp + _RSP]
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop r12
|
||||
pop rbp
|
||||
%ifndef LINUX
|
||||
pop rdi
|
||||
pop rsi
|
||||
%endif
|
||||
pop rbx
|
||||
|
||||
ret
|
||||
|
||||
section .data
|
||||
align 64
|
||||
K256:
|
||||
dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
dd 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
dd 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
dd 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
dd 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
dd 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
dd 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
dd 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
dd 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
dd 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
dd 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
dd 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
dd 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
dd 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
dd 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
dd 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
dd 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
dd 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
dd 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
dd 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
dd 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
dd 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
dd 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
dd 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
dd 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
dd 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
dd 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
dd 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
dd 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
dd 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
dd 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
|
||||
PSHUFFLE_BYTE_FLIP_MASK:
|
||||
ddq 0x0c0d0e0f08090a0b0405060700010203,0x0c0d0e0f08090a0b0405060700010203
|
||||
|
||||
; shuffle xBxA -> 00BA
|
||||
_SHUF_00BA:
|
||||
ddq 0xFFFFFFFFFFFFFFFF0b0a090803020100,0xFFFFFFFFFFFFFFFF0b0a090803020100
|
||||
|
||||
; shuffle xDxC -> DC00
|
||||
_SHUF_DC00:
|
||||
ddq 0x0b0a090803020100FFFFFFFFFFFFFFFF,0x0b0a090803020100FFFFFFFFFFFFFFFF
|
||||
1507
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx2_rorx8.asm
Normal file
1507
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_avx2_rorx8.asm
Normal file
File diff suppressed because it is too large
Load Diff
544
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_sse4.asm
Normal file
544
nostrdb/ccan/ccan/crypto/sha256/benchmarks/sha256_sse4.asm
Normal file
@@ -0,0 +1,544 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Copyright (c) 2012, Intel Corporation
|
||||
;
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are
|
||||
; met:
|
||||
;
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
;
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the
|
||||
; distribution.
|
||||
;
|
||||
; * Neither the name of the Intel Corporation nor the names of its
|
||||
; contributors may be used to endorse or promote products derived from
|
||||
; this software without specific prior written permission.
|
||||
;
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS" AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
|
||||
; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; Example YASM command lines:
|
||||
; Windows: yasm -Xvc -f x64 -rnasm -pnasm -o sha256_sse4.obj -g cv8 sha256_sse4.asm
|
||||
; Linux: yasm -f x64 -f elf64 -X gnu -g dwarf2 -D LINUX -o sha256_sse4.o sha256_sse4.asm
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; This code is described in an Intel White-Paper:
|
||||
; "Fast SHA-256 Implementations on Intel Architecture Processors"
|
||||
;
|
||||
; To find it, surf to http://www.intel.com/p/en_US/embedded
|
||||
; and search for that title.
|
||||
; The paper is expected to be released roughly at the end of April, 2012
|
||||
;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; This code schedules 1 blocks at a time, with 4 lanes per block
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define MOVDQ movdqu ;; assume buffers not aligned
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Define Macros
|
||||
|
||||
; addm [mem], reg
|
||||
; Add reg to mem using reg-mem add and store
|
||||
%macro addm 2
|
||||
add %2, %1
|
||||
mov %1, %2
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; COPY_XMM_AND_BSWAP xmm, [mem], byte_flip_mask
|
||||
; Load xmm with mem and byte swap each dword
|
||||
%macro COPY_XMM_AND_BSWAP 3
|
||||
MOVDQ %1, %2
|
||||
pshufb %1, %3
|
||||
%endmacro
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
%define X0 xmm4
|
||||
%define X1 xmm5
|
||||
%define X2 xmm6
|
||||
%define X3 xmm7
|
||||
|
||||
%define XTMP0 xmm0
|
||||
%define XTMP1 xmm1
|
||||
%define XTMP2 xmm2
|
||||
%define XTMP3 xmm3
|
||||
%define XTMP4 xmm8
|
||||
%define XFER xmm9
|
||||
|
||||
%define SHUF_00BA xmm10 ; shuffle xBxA -> 00BA
|
||||
%define SHUF_DC00 xmm11 ; shuffle xDxC -> DC00
|
||||
%define BYTE_FLIP_MASK xmm12
|
||||
|
||||
%ifdef LINUX
|
||||
%define NUM_BLKS rdx ; 3rd arg
|
||||
%define CTX rsi ; 2nd arg
|
||||
%define INP rdi ; 1st arg
|
||||
|
||||
%define SRND rdi ; clobbers INP
|
||||
%define c ecx
|
||||
%define d r8d
|
||||
%define e edx
|
||||
%else
|
||||
%define NUM_BLKS r8 ; 3rd arg
|
||||
%define CTX rdx ; 2nd arg
|
||||
%define INP rcx ; 1st arg
|
||||
|
||||
%define SRND rcx ; clobbers INP
|
||||
%define c edi
|
||||
%define d esi
|
||||
%define e r8d
|
||||
|
||||
%endif
|
||||
%define TBL rbp
|
||||
%define a eax
|
||||
%define b ebx
|
||||
|
||||
%define f r9d
|
||||
%define g r10d
|
||||
%define h r11d
|
||||
|
||||
%define y0 r13d
|
||||
%define y1 r14d
|
||||
%define y2 r15d
|
||||
|
||||
|
||||
|
||||
_INP_END_SIZE equ 8
|
||||
_INP_SIZE equ 8
|
||||
_XFER_SIZE equ 8
|
||||
%ifdef LINUX
|
||||
_XMM_SAVE_SIZE equ 0
|
||||
%else
|
||||
_XMM_SAVE_SIZE equ 7*16
|
||||
%endif
|
||||
; STACK_SIZE plus pushes must be an odd multiple of 8
|
||||
_ALIGN_SIZE equ 8
|
||||
|
||||
_INP_END equ 0
|
||||
_INP equ _INP_END + _INP_END_SIZE
|
||||
_XFER equ _INP + _INP_SIZE
|
||||
_XMM_SAVE equ _XFER + _XFER_SIZE + _ALIGN_SIZE
|
||||
STACK_SIZE equ _XMM_SAVE + _XMM_SAVE_SIZE
|
||||
|
||||
; rotate_Xs
|
||||
; Rotate values of symbols X0...X3
|
||||
%macro rotate_Xs 0
|
||||
%xdefine X_ X0
|
||||
%xdefine X0 X1
|
||||
%xdefine X1 X2
|
||||
%xdefine X2 X3
|
||||
%xdefine X3 X_
|
||||
%endm
|
||||
|
||||
; ROTATE_ARGS
|
||||
; Rotate values of symbols a...h
|
||||
%macro ROTATE_ARGS 0
|
||||
%xdefine TMP_ h
|
||||
%xdefine h g
|
||||
%xdefine g f
|
||||
%xdefine f e
|
||||
%xdefine e d
|
||||
%xdefine d c
|
||||
%xdefine c b
|
||||
%xdefine b a
|
||||
%xdefine a TMP_
|
||||
%endm
|
||||
|
||||
%macro FOUR_ROUNDS_AND_SCHED 0
|
||||
;; compute s0 four at a time and s1 two at a time
|
||||
;; compute W[-16] + W[-7] 4 at a time
|
||||
movdqa XTMP0, X3
|
||||
mov y0, e ; y0 = e
|
||||
ror y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
palignr XTMP0, X2, 4 ; XTMP0 = W[-7]
|
||||
ror y1, (22-13) ; y1 = a >> (22-13)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
movdqa XTMP1, X1
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
xor y2, g ; y2 = f^g
|
||||
paddd XTMP0, X0 ; XTMP0 = W[-7] + W[-16]
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
;; compute s0
|
||||
palignr XTMP1, X0, 4 ; XTMP1 = W[-15]
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
movdqa XTMP2, XTMP1 ; XTMP2 = W[-15]
|
||||
ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 0*4] ; y2 = k + w + S1 + CH
|
||||
movdqa XTMP3, XTMP1 ; XTMP3 = W[-15]
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
pslld XTMP1, (32-7)
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
psrld XTMP2, 7
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
por XTMP1, XTMP2 ; XTMP1 = W[-15] nostrdb: ror 7
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
movdqa XTMP2, XTMP3 ; XTMP2 = W[-15]
|
||||
mov y0, e ; y0 = e
|
||||
mov y1, a ; y1 = a
|
||||
movdqa XTMP4, XTMP3 ; XTMP4 = W[-15]
|
||||
ror y0, (25-11) ; y0 = e >> (25-11)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
ror y1, (22-13) ; y1 = a >> (22-13)
|
||||
pslld XTMP3, (32-18)
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
xor y2, g ; y2 = f^g
|
||||
psrld XTMP2, 18
|
||||
ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
pxor XTMP1, XTMP3
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
psrld XTMP4, 3 ; XTMP4 = W[-15] nostrdb: >> 3
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 1*4] ; y2 = k + w + S1 + CH
|
||||
ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
pxor XTMP1, XTMP2 ; XTMP1 = W[-15] nostrdb: ror 7 ^ W[-15] ror 18
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
pxor XTMP1, XTMP4 ; XTMP1 = s0
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
;; compute low s1
|
||||
pshufd XTMP2, X3, 11111010b ; XTMP2 = W[-2] {BBAA}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
paddd XTMP0, XTMP1 ; XTMP0 = W[-16] + W[-7] + s0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
movdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {BBAA}
|
||||
mov y0, e ; y0 = e
|
||||
mov y1, a ; y1 = a
|
||||
ror y0, (25-11) ; y0 = e >> (25-11)
|
||||
movdqa XTMP4, XTMP2 ; XTMP4 = W[-2] {BBAA}
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
ror y1, (22-13) ; y1 = a >> (22-13)
|
||||
mov y2, f ; y2 = f
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
psrlq XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xBxA}
|
||||
xor y2, g ; y2 = f^g
|
||||
psrlq XTMP3, 19 ; XTMP3 = W[-2] ror 19 {xBxA}
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
psrld XTMP4, 10 ; XTMP4 = W[-2] >> 10 {BBAA}
|
||||
ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
pxor XTMP2, XTMP3
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, [rsp + _XFER + 2*4] ; y2 = k + w + S1 + CH
|
||||
pxor XTMP4, XTMP2 ; XTMP4 = s1 {xBxA}
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
pshufb XTMP4, SHUF_00BA ; XTMP4 = s1 {00BA}
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
paddd XTMP0, XTMP4 ; XTMP0 = {..., ..., W[1], W[0]}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
;; compute high s1
|
||||
pshufd XTMP2, XTMP0, 01010000b ; XTMP2 = W[-2] {DDCC}
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
movdqa XTMP3, XTMP2 ; XTMP3 = W[-2] {DDCC}
|
||||
mov y0, e ; y0 = e
|
||||
ror y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
movdqa X0, XTMP2 ; X0 = W[-2] {DDCC}
|
||||
ror y1, (22-13) ; y1 = a >> (22-13)
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
mov y2, f ; y2 = f
|
||||
ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
psrlq XTMP2, 17 ; XTMP2 = W[-2] ror 17 {xDxC}
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
xor y2, g ; y2 = f^g
|
||||
psrlq XTMP3, 19 ; XTMP3 = W[-2] ror 19 {xDxC}
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
psrld X0, 10 ; X0 = W[-2] >> 10 {DDCC}
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
pxor XTMP2, XTMP3
|
||||
ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
add y2, [rsp + _XFER + 3*4] ; y2 = k + w + S1 + CH
|
||||
pxor X0, XTMP2 ; X0 = s1 {xDxC}
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
pshufb X0, SHUF_DC00 ; X0 = s1 {DC00}
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
paddd X0, XTMP0 ; X0 = {W[3], W[2], W[1], W[0]}
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
|
||||
ROTATE_ARGS
|
||||
rotate_Xs
|
||||
%endm
|
||||
|
||||
;; input is [rsp + _XFER + %1 * 4]
|
||||
%macro DO_ROUND 1
|
||||
mov y0, e ; y0 = e
|
||||
ror y0, (25-11) ; y0 = e >> (25-11)
|
||||
mov y1, a ; y1 = a
|
||||
xor y0, e ; y0 = e ^ (e >> (25-11))
|
||||
ror y1, (22-13) ; y1 = a >> (22-13)
|
||||
mov y2, f ; y2 = f
|
||||
xor y1, a ; y1 = a ^ (a >> (22-13)
|
||||
ror y0, (11-6) ; y0 = (e >> (11-6)) ^ (e >> (25-6))
|
||||
xor y2, g ; y2 = f^g
|
||||
xor y0, e ; y0 = e ^ (e >> (11-6)) ^ (e >> (25-6))
|
||||
ror y1, (13-2) ; y1 = (a >> (13-2)) ^ (a >> (22-2))
|
||||
and y2, e ; y2 = (f^g)&e
|
||||
xor y1, a ; y1 = a ^ (a >> (13-2)) ^ (a >> (22-2))
|
||||
ror y0, 6 ; y0 = S1 = (e>>6) & (e>>11) ^ (e>>25)
|
||||
xor y2, g ; y2 = CH = ((f^g)&e)^g
|
||||
add y2, y0 ; y2 = S1 + CH
|
||||
ror y1, 2 ; y1 = S0 = (a>>2) ^ (a>>13) ^ (a>>22)
|
||||
add y2, [rsp + _XFER + %1 * 4] ; y2 = k + w + S1 + CH
|
||||
mov y0, a ; y0 = a
|
||||
add h, y2 ; h = h + S1 + CH + k + w
|
||||
mov y2, a ; y2 = a
|
||||
or y0, c ; y0 = a|c
|
||||
add d, h ; d = d + h + S1 + CH + k + w
|
||||
and y2, c ; y2 = a&c
|
||||
and y0, b ; y0 = (a|c)&b
|
||||
add h, y1 ; h = h + S1 + CH + k + w + S0
|
||||
or y0, y2 ; y0 = MAJ = (a|c)&b)|(a&c)
|
||||
add h, y0 ; h = h + S1 + CH + k + w + S0 + MAJ
|
||||
ROTATE_ARGS
|
||||
%endm
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; void sha256_sse4(void *input_data, UINT32 digest[8], UINT64 num_blks)
|
||||
;; arg 1 : pointer to input data
|
||||
;; arg 2 : pointer to digest
|
||||
;; arg 3 : Num blocks
|
||||
section .text
|
||||
global sha256_sse4
|
||||
align 32
|
||||
sha256_sse4:
|
||||
push rbx
|
||||
%ifndef LINUX
|
||||
push rsi
|
||||
push rdi
|
||||
%endif
|
||||
push rbp
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
|
||||
sub rsp,STACK_SIZE
|
||||
%ifndef LINUX
|
||||
movdqa [rsp + _XMM_SAVE + 0*16],xmm6
|
||||
movdqa [rsp + _XMM_SAVE + 1*16],xmm7
|
||||
movdqa [rsp + _XMM_SAVE + 2*16],xmm8
|
||||
movdqa [rsp + _XMM_SAVE + 3*16],xmm9
|
||||
movdqa [rsp + _XMM_SAVE + 4*16],xmm10
|
||||
movdqa [rsp + _XMM_SAVE + 5*16],xmm11
|
||||
movdqa [rsp + _XMM_SAVE + 6*16],xmm12
|
||||
%endif
|
||||
|
||||
shl NUM_BLKS, 6 ; convert to bytes
|
||||
jz done_hash
|
||||
add NUM_BLKS, INP ; pointer to end of data
|
||||
mov [rsp + _INP_END], NUM_BLKS
|
||||
|
||||
;; load initial digest
|
||||
mov a,[4*0 + CTX]
|
||||
mov b,[4*1 + CTX]
|
||||
mov c,[4*2 + CTX]
|
||||
mov d,[4*3 + CTX]
|
||||
mov e,[4*4 + CTX]
|
||||
mov f,[4*5 + CTX]
|
||||
mov g,[4*6 + CTX]
|
||||
mov h,[4*7 + CTX]
|
||||
|
||||
movdqa BYTE_FLIP_MASK, [PSHUFFLE_BYTE_FLIP_MASK wrt rip]
|
||||
movdqa SHUF_00BA, [_SHUF_00BA wrt rip]
|
||||
movdqa SHUF_DC00, [_SHUF_DC00 wrt rip]
|
||||
|
||||
loop0:
|
||||
lea TBL,[K256 wrt rip]
|
||||
|
||||
;; byte swap first 16 dwords
|
||||
COPY_XMM_AND_BSWAP X0, [INP + 0*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X1, [INP + 1*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X2, [INP + 2*16], BYTE_FLIP_MASK
|
||||
COPY_XMM_AND_BSWAP X3, [INP + 3*16], BYTE_FLIP_MASK
|
||||
|
||||
mov [rsp + _INP], INP
|
||||
|
||||
;; schedule 48 input dwords, by doing 3 rounds of 16 each
|
||||
mov SRND, 3
|
||||
align 16
|
||||
loop1:
|
||||
movdqa XFER, [TBL + 0*16]
|
||||
paddd XFER, X0
|
||||
movdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
movdqa XFER, [TBL + 1*16]
|
||||
paddd XFER, X0
|
||||
movdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
movdqa XFER, [TBL + 2*16]
|
||||
paddd XFER, X0
|
||||
movdqa [rsp + _XFER], XFER
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
movdqa XFER, [TBL + 3*16]
|
||||
paddd XFER, X0
|
||||
movdqa [rsp + _XFER], XFER
|
||||
add TBL, 4*16
|
||||
FOUR_ROUNDS_AND_SCHED
|
||||
|
||||
sub SRND, 1
|
||||
jne loop1
|
||||
|
||||
mov SRND, 2
|
||||
loop2:
|
||||
paddd X0, [TBL + 0*16]
|
||||
movdqa [rsp + _XFER], X0
|
||||
DO_ROUND 0
|
||||
DO_ROUND 1
|
||||
DO_ROUND 2
|
||||
DO_ROUND 3
|
||||
paddd X1, [TBL + 1*16]
|
||||
movdqa [rsp + _XFER], X1
|
||||
add TBL, 2*16
|
||||
DO_ROUND 0
|
||||
DO_ROUND 1
|
||||
DO_ROUND 2
|
||||
DO_ROUND 3
|
||||
|
||||
movdqa X0, X2
|
||||
movdqa X1, X3
|
||||
|
||||
sub SRND, 1
|
||||
jne loop2
|
||||
|
||||
addm [4*0 + CTX],a
|
||||
addm [4*1 + CTX],b
|
||||
addm [4*2 + CTX],c
|
||||
addm [4*3 + CTX],d
|
||||
addm [4*4 + CTX],e
|
||||
addm [4*5 + CTX],f
|
||||
addm [4*6 + CTX],g
|
||||
addm [4*7 + CTX],h
|
||||
|
||||
mov INP, [rsp + _INP]
|
||||
add INP, 64
|
||||
cmp INP, [rsp + _INP_END]
|
||||
jne loop0
|
||||
|
||||
done_hash:
|
||||
%ifndef LINUX
|
||||
movdqa xmm6,[rsp + _XMM_SAVE + 0*16]
|
||||
movdqa xmm7,[rsp + _XMM_SAVE + 1*16]
|
||||
movdqa xmm8,[rsp + _XMM_SAVE + 2*16]
|
||||
movdqa xmm9,[rsp + _XMM_SAVE + 3*16]
|
||||
movdqa xmm10,[rsp + _XMM_SAVE + 4*16]
|
||||
movdqa xmm11,[rsp + _XMM_SAVE + 5*16]
|
||||
movdqa xmm12,[rsp + _XMM_SAVE + 6*16]
|
||||
%endif
|
||||
|
||||
add rsp, STACK_SIZE
|
||||
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
pop rbp
|
||||
%ifndef LINUX
|
||||
pop rdi
|
||||
pop rsi
|
||||
%endif
|
||||
pop rbx
|
||||
|
||||
ret
|
||||
|
||||
|
||||
section .data
|
||||
align 64
|
||||
K256:
|
||||
dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
dd 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
dd 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
dd 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
dd 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
dd 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
dd 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
dd 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
dd 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
dd 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
dd 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
dd 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
dd 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
dd 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
dd 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
dd 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
|
||||
PSHUFFLE_BYTE_FLIP_MASK: ddq 0x0c0d0e0f08090a0b0405060700010203
|
||||
|
||||
; shuffle xBxA -> 00BA
|
||||
_SHUF_00BA: ddq 0xFFFFFFFFFFFFFFFF0b0a090803020100
|
||||
|
||||
; shuffle xDxC -> DC00
|
||||
_SHUF_DC00: ddq 0x0b0a090803020100FFFFFFFFFFFFFFFF
|
||||
@@ -6,9 +6,9 @@
|
||||
* Distributed under the MIT software license, see the accompanying
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
*/
|
||||
#include "sha256.h"
|
||||
#include "ccan/endian/endian.h"
|
||||
#include "ccan/compiler/compiler.h"
|
||||
#include <ccan/crypto/sha256/sha256.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
@@ -22,7 +22,7 @@ static void invalidate_sha256(struct sha256_ctx *ctx)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void check_sha256(struct sha256_ctx *ctx)
|
||||
static void check_sha256(struct sha256_ctx *ctx UNUSED)
|
||||
{
|
||||
#ifdef CCAN_CRYPTO_SHA256_USE_OPENSSL
|
||||
assert(ctx->c.md_len != 0);
|
||||
@@ -167,6 +167,14 @@ static void Transform(uint32_t *s, const uint32_t *chunk)
|
||||
s[7] += h;
|
||||
}
|
||||
|
||||
static bool alignment_ok(const void *p UNUSED, size_t n UNUSED)
|
||||
{
|
||||
#if HAVE_UNALIGNED_ACCESS
|
||||
return true;
|
||||
#else
|
||||
return ((size_t)p % n == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void add(struct sha256_ctx *ctx, const void *p, size_t len)
|
||||
{
|
||||
@@ -195,7 +203,7 @@ static void add(struct sha256_ctx *ctx, const void *p, size_t len)
|
||||
data += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
|
||||
if (len) {
|
||||
/* Fill the buffer with what remains. */
|
||||
memcpy(ctx->buf.u8 + bufsize, data, len);
|
||||
@@ -240,7 +248,7 @@ void sha256(struct sha256 *sha, const void *p, size_t size)
|
||||
sha256_update(&ctx, p, size);
|
||||
sha256_done(&ctx, sha);
|
||||
}
|
||||
|
||||
|
||||
void sha256_u8(struct sha256_ctx *ctx, uint8_t v)
|
||||
{
|
||||
sha256_update(ctx, &v, sizeof(v));
|
||||
@@ -267,13 +275,13 @@ void sha256_le16(struct sha256_ctx *ctx, uint16_t v)
|
||||
leint16_t lev = cpu_to_le16(v);
|
||||
sha256_update(ctx, &lev, sizeof(lev));
|
||||
}
|
||||
|
||||
|
||||
void sha256_le32(struct sha256_ctx *ctx, uint32_t v)
|
||||
{
|
||||
leint32_t lev = cpu_to_le32(v);
|
||||
sha256_update(ctx, &lev, sizeof(lev));
|
||||
}
|
||||
|
||||
|
||||
void sha256_le64(struct sha256_ctx *ctx, uint64_t v)
|
||||
{
|
||||
leint64_t lev = cpu_to_le64(v);
|
||||
@@ -286,17 +294,15 @@ void sha256_be16(struct sha256_ctx *ctx, uint16_t v)
|
||||
beint16_t bev = cpu_to_be16(v);
|
||||
sha256_update(ctx, &bev, sizeof(bev));
|
||||
}
|
||||
|
||||
|
||||
void sha256_be32(struct sha256_ctx *ctx, uint32_t v)
|
||||
{
|
||||
beint32_t bev = cpu_to_be32(v);
|
||||
sha256_update(ctx, &bev, sizeof(bev));
|
||||
}
|
||||
|
||||
|
||||
void sha256_be64(struct sha256_ctx *ctx, uint64_t v)
|
||||
{
|
||||
beint64_t bev = cpu_to_be64(v);
|
||||
sha256_update(ctx, &bev, sizeof(bev));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
|
||||
#ifndef CCAN_CRYPTO_SHA256_H
|
||||
#define CCAN_CRYPTO_SHA256_H
|
||||
|
||||
|
||||
/** Output length for `wally_sha256` */
|
||||
#define SHA256_LEN 32
|
||||
|
||||
|
||||
/* BSD-MIT - see LICENSE file for details */
|
||||
/* #include "config.h" */
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -151,5 +144,4 @@ void sha256_le64(struct sha256_ctx *ctx, uint64_t v);
|
||||
void sha256_be16(struct sha256_ctx *ctx, uint16_t v);
|
||||
void sha256_be32(struct sha256_ctx *ctx, uint32_t v);
|
||||
void sha256_be64(struct sha256_ctx *ctx, uint64_t v);
|
||||
|
||||
#endif /* CCAN_CRYPTO_SHA256_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/endian/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/endian/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
55
nostrdb/ccan/ccan/endian/_info
Normal file
55
nostrdb/ccan/ccan/endian/_info
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* endian - endian conversion macros for simple types
|
||||
*
|
||||
* Portable protocols (such as on-disk formats, or network protocols)
|
||||
* are often defined to be a particular endian: little-endian (least
|
||||
* significant bytes first) or big-endian (most significant bytes
|
||||
* first).
|
||||
*
|
||||
* Similarly, some CPUs lay out values in memory in little-endian
|
||||
* order (most commonly, Intel's 8086 and derivatives), or big-endian
|
||||
* order (almost everyone else).
|
||||
*
|
||||
* This module provides conversion routines, inspired by the linux kernel.
|
||||
* It also provides leint32_t, beint32_t etc typedefs, which are annotated for
|
||||
* the sparse checker.
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <err.h>
|
||||
* #include <ccan/endian/endian.h>
|
||||
*
|
||||
* //
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* uint32_t value;
|
||||
*
|
||||
* if (argc != 2)
|
||||
* errx(1, "Usage: %s <value>", argv[0]);
|
||||
*
|
||||
* value = atoi(argv[1]);
|
||||
* printf("native: %08x\n", value);
|
||||
* printf("little-endian: %08x\n", cpu_to_le32(value));
|
||||
* printf("big-endian: %08x\n", cpu_to_be32(value));
|
||||
* printf("byte-reversed: %08x\n", bswap_32(value));
|
||||
* exit(0);
|
||||
* }
|
||||
*
|
||||
* License: License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0)
|
||||
/* Nothing */
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
/* CC0 (Public domain) */
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_ENDIAN_H
|
||||
#define CCAN_ENDIAN_H
|
||||
#include <stdint.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "cursor.h"
|
||||
|
||||
/**
|
||||
* BSWAP_16 - reverse bytes in a constant uint16_t value.
|
||||
@@ -346,6 +344,8 @@ static inline uint16_t be16_to_cpu(beint16_t be_val)
|
||||
return BE16_TO_CPU(be_val);
|
||||
}
|
||||
|
||||
/* Whichever they include first, they get these definitions. */
|
||||
#ifdef CCAN_SHORT_TYPES_H
|
||||
/**
|
||||
* be64/be32/be16 - 64/32/16 bit big-endian representation.
|
||||
*/
|
||||
@@ -359,7 +359,5 @@ typedef beint16_t be16;
|
||||
typedef leint64_t le64;
|
||||
typedef leint32_t le32;
|
||||
typedef leint16_t le16;
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* CCAN_ENDIAN_H */
|
||||
|
||||
|
||||
1
nostrdb/ccan/ccan/htable/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/htable/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/LGPL-2.1
|
||||
118
nostrdb/ccan/ccan/htable/_info
Normal file
118
nostrdb/ccan/ccan/htable/_info
Normal file
@@ -0,0 +1,118 @@
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* htable - hash table routines
|
||||
*
|
||||
* A hash table is an efficient structure for looking up keys. This version
|
||||
* grows with usage and allows efficient deletion.
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/htable/htable.h>
|
||||
* #include <ccan/hash/hash.h>
|
||||
* #include <stdio.h>
|
||||
* #include <err.h>
|
||||
* #include <string.h>
|
||||
*
|
||||
* struct name_to_digit {
|
||||
* const char *name;
|
||||
* unsigned int val;
|
||||
* };
|
||||
*
|
||||
* static struct name_to_digit map[] = {
|
||||
* { "zero", 0},
|
||||
* { "one", 1 },
|
||||
* { "two", 2 },
|
||||
* { "three", 3 },
|
||||
* { "four", 4 },
|
||||
* { "five", 5 },
|
||||
* { "six", 6 },
|
||||
* { "seven", 7 },
|
||||
* { "eight", 8 },
|
||||
* { "nine", 9 }
|
||||
* };
|
||||
*
|
||||
* // Wrapper for rehash function pointer.
|
||||
* static size_t rehash(const void *e, void *unused)
|
||||
* {
|
||||
* (void)unused;
|
||||
* return hash_string(((struct name_to_digit *)e)->name);
|
||||
* }
|
||||
*
|
||||
* // Comparison function.
|
||||
* static bool nameeq(const void *e, void *string)
|
||||
* {
|
||||
* return strcmp(((struct name_to_digit *)e)->name, string) == 0;
|
||||
* }
|
||||
*
|
||||
* // We let them add their own aliases, eg. --alias=v=5
|
||||
* static void add_alias(struct htable *ht, const char *alias)
|
||||
* {
|
||||
* char *eq, *name;
|
||||
* struct name_to_digit *n;
|
||||
*
|
||||
* n = malloc(sizeof(*n));
|
||||
* n->name = name = strdup(alias);
|
||||
*
|
||||
* eq = strchr(name, '=');
|
||||
* if (!eq || ((n->val = atoi(eq+1)) == 0 && !strcmp(eq+1, "0")))
|
||||
* errx(1, "Usage: --alias=<name>=<value>");
|
||||
* *eq = '\0';
|
||||
* htable_add(ht, hash_string(n->name), n);
|
||||
* }
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct htable ht;
|
||||
* int i;
|
||||
* unsigned long val;
|
||||
*
|
||||
* if (argc < 2)
|
||||
* errx(1, "Usage: %s [--alias=<name>=<val>]... <str>...",
|
||||
* argv[0]);
|
||||
*
|
||||
* // Create and populate hash table.
|
||||
* htable_init(&ht, rehash, NULL);
|
||||
* for (i = 0; i < (int)(sizeof(map)/sizeof(map[0])); i++)
|
||||
* htable_add(&ht, hash_string(map[i].name), &map[i]);
|
||||
*
|
||||
* // Add any aliases to the hash table.
|
||||
* for (i = 1; i < argc; i++) {
|
||||
* if (!strncmp(argv[i], "--alias=", strlen("--alias=")))
|
||||
* add_alias(&ht, argv[i] + strlen("--alias="));
|
||||
* else
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* // Find the other args in the hash table.
|
||||
* for (val = 0; i < argc; i++) {
|
||||
* struct name_to_digit *n;
|
||||
* n = htable_get(&ht, hash_string(argv[i]),
|
||||
* nameeq, argv[i]);
|
||||
* if (!n)
|
||||
* errx(1, "Invalid digit name %s", argv[i]);
|
||||
* // Append it to the value we are building up.
|
||||
* val *= 10;
|
||||
* val += n->val;
|
||||
* }
|
||||
* printf("%lu\n", val);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: LGPL (v2.1 or any later version)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/compiler\n");
|
||||
printf("ccan/str\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
491
nostrdb/ccan/ccan/htable/htable.c
Normal file
491
nostrdb/ccan/ccan/htable/htable.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/* Licensed under LGPLv2+ - see LICENSE file for details */
|
||||
#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>
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return e & ht->common_mask;
|
||||
}
|
||||
|
||||
static inline void *get_raw_ptr(const struct htable *ht, uintptr_t e)
|
||||
{
|
||||
return (void *)((e & ~ht->common_mask) | ht->common_bits);
|
||||
}
|
||||
|
||||
static inline uintptr_t make_hval(const struct htable *ht,
|
||||
const void *p, uintptr_t bits)
|
||||
{
|
||||
return ((uintptr_t)p & ~ht->common_mask) | bits;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* Shuffling the extra bits (as specified in mask) down the
|
||||
* 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);
|
||||
}
|
||||
|
||||
void htable_init(struct htable *ht,
|
||||
size_t (*rehash)(const void *elem, void *priv), void *priv)
|
||||
{
|
||||
struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL);
|
||||
*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;
|
||||
}
|
||||
|
||||
void htable_clear(struct htable *ht)
|
||||
{
|
||||
if (ht->table != &ht->common_bits)
|
||||
htable_free(ht, (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);
|
||||
}
|
||||
|
||||
static void *htable_val(const struct htable *ht,
|
||||
struct htable_iter *i, size_t hash, uintptr_t perfect)
|
||||
{
|
||||
uintptr_t h2 = get_hash_ptr_bits(ht, hash) | perfect;
|
||||
|
||||
while (ht->table[i->off]) {
|
||||
if (ht->table[i->off] != HTABLE_DELETED) {
|
||||
if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2)
|
||||
return get_raw_ptr(ht, ht->table[i->off]);
|
||||
}
|
||||
i->off = (i->off + 1) & ((1 << ht->bits)-1);
|
||||
h2 &= ~perfect;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) {
|
||||
if (entry_is_valid(ht->table[i->off]))
|
||||
return get_raw_ptr(ht, ht->table[i->off]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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]))
|
||||
return get_raw_ptr(ht, ht->table[i->off]);
|
||||
}
|
||||
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);
|
||||
|
||||
i = hash_bucket(ht, h);
|
||||
|
||||
while (entry_is_valid(ht->table[i])) {
|
||||
perfect = 0;
|
||||
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)
|
||||
{
|
||||
unsigned int i;
|
||||
size_t oldnum = (size_t)1 << ht->bits;
|
||||
uintptr_t *oldtable, e;
|
||||
|
||||
oldtable = ht->table;
|
||||
ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1));
|
||||
if (!ht->table) {
|
||||
ht->table = oldtable;
|
||||
return false;
|
||||
}
|
||||
ht->bits++;
|
||||
|
||||
/* If we lost our "perfect bit", get it back now. */
|
||||
if (ht->perfect_bitnum == NO_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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldtable != &ht->common_bits) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
|
||||
/* Beware wrap cases: we need to start from first empty bucket. */
|
||||
for (start = 0; ht->table[start]; start++);
|
||||
|
||||
for (i = 0; i < (size_t)1 << ht->bits; i++) {
|
||||
size_t h = (i + start) & ((1 << ht->bits)-1);
|
||||
e = ht->table[h];
|
||||
if (!e)
|
||||
continue;
|
||||
if (e == HTABLE_DELETED)
|
||||
ht->table[h] = 0;
|
||||
else if (!(e & perfect)) {
|
||||
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;
|
||||
|
||||
if (ht->elems == 0) {
|
||||
ht->common_mask = -1;
|
||||
ht->common_bits = ((uintptr_t)p & ht->common_mask);
|
||||
ht->perfect_bitnum = 0;
|
||||
(void)htable_debug(ht, HTABLE_LOC);
|
||||
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);
|
||||
}
|
||||
|
||||
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))
|
||||
return false;
|
||||
}
|
||||
if (((uintptr_t)p & ht->common_mask) != ht->common_bits)
|
||||
update_common(ht, p);
|
||||
|
||||
ht_add(ht, p, hash);
|
||||
ht->elems++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool htable_del_(struct htable *ht, size_t h, const void *p)
|
||||
{
|
||||
struct htable_iter i;
|
||||
void *c;
|
||||
|
||||
for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
|
||||
if (c == p) {
|
||||
htable_delval(ht, &i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
290
nostrdb/ccan/ccan/htable/htable.h
Normal file
290
nostrdb/ccan/ccan/htable/htable.h
Normal file
@@ -0,0 +1,290 @@
|
||||
/* 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 <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.
|
||||
*
|
||||
* It's exposed here so you can put it in your structures and so we can
|
||||
* supply inline functions.
|
||||
*/
|
||||
struct htable {
|
||||
size_t (*rehash)(const void *elem, void *priv);
|
||||
void *priv;
|
||||
unsigned int bits, perfect_bitnum;
|
||||
size_t elems, deleted;
|
||||
/* These are the bits which are the same in all pointers. */
|
||||
uintptr_t common_mask, common_bits;
|
||||
uintptr_t *table;
|
||||
};
|
||||
|
||||
/**
|
||||
* HTABLE_INITIALIZER - static initialization for a hash table.
|
||||
* @name: name of this htable.
|
||||
* @rehash: hash function to use for rehashing.
|
||||
* @priv: private argument to @rehash function.
|
||||
*
|
||||
* This is useful for setting up static and global hash tables.
|
||||
*
|
||||
* Example:
|
||||
* // 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 }
|
||||
|
||||
/**
|
||||
* htable_init - initialize an empty hash table.
|
||||
* @ht: the hash table to initialize
|
||||
* @rehash: hash function to use for rehashing.
|
||||
* @priv: private argument to @rehash function.
|
||||
*/
|
||||
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
|
||||
*
|
||||
* This doesn't do anything to any pointers left in it.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* htable_del - remove a pointer from a hash table
|
||||
* @ht: the htable
|
||||
* @hash: the hash value of the object
|
||||
* @p: the pointer
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* struct htable_iter - iterator or htable_first or htable_firstval etc.
|
||||
*
|
||||
* This refers to a location inside the hashtable.
|
||||
*/
|
||||
struct htable_iter {
|
||||
size_t off;
|
||||
};
|
||||
|
||||
/**
|
||||
* htable_firstval - find a candidate for a given hash value
|
||||
* @htable: the hashtable
|
||||
* @i: the struct htable_iter to initialize
|
||||
* @hash: the hash value
|
||||
*
|
||||
* You'll need to check the value is what you want; returns NULL if none.
|
||||
* 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,
|
||||
struct htable_iter *i, size_t hash);
|
||||
|
||||
/**
|
||||
* htable_nextval - find another candidate for a given hash value
|
||||
* @htable: the hashtable
|
||||
* @i: the struct htable_iter to initialize
|
||||
* @hash: the hash value
|
||||
*
|
||||
* 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,
|
||||
struct htable_iter *i, size_t hash);
|
||||
|
||||
/**
|
||||
* htable_get - find an entry in the hash table
|
||||
* @ht: the hashtable
|
||||
* @h: the hash value of the entry
|
||||
* @cmp: the comparison function
|
||||
* @ptr: the pointer to hand to the comparison function.
|
||||
*
|
||||
* Convenient inline wrapper for htable_firstval/htable_nextval loop.
|
||||
*/
|
||||
static inline void *htable_get(const struct htable *ht,
|
||||
size_t h,
|
||||
bool (*cmp)(const void *candidate, void *ptr),
|
||||
const void *ptr)
|
||||
{
|
||||
struct htable_iter i;
|
||||
void *c;
|
||||
|
||||
for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
|
||||
if (cmp(c, (void *)ptr))
|
||||
return c;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* htable_first - find an entry in the hash table
|
||||
* @ht: the hashtable
|
||||
* @i: the struct htable_iter to initialize
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* htable_next - find another entry in the hash table
|
||||
* @ht: the hashtable
|
||||
* @i: the struct htable_iter to use
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* htable_delval - remove an iterated pointer from a hash table
|
||||
* @ht: the htable
|
||||
* @i: the htable_iter
|
||||
*
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
188
nostrdb/ccan/ccan/htable/htable_type.h
Normal file
188
nostrdb/ccan/ccan/htable/htable_type.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/* Licensed under LGPLv2+ - see LICENSE file for details */
|
||||
#ifndef CCAN_HTABLE_TYPE_H
|
||||
#define CCAN_HTABLE_TYPE_H
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* HTABLE_DEFINE_TYPE - create a set of htable ops for a type
|
||||
* @type: a type whose pointers will be values in the hash.
|
||||
* @keyof: a function/macro to extract a key: <keytype> @keyof(const type *elem)
|
||||
* @hashfn: a hash function for a @key: size_t @hashfn(const <keytype> *)
|
||||
* @eqfn: an equality function keys: bool @eqfn(const type *, const <keytype> *)
|
||||
* @prefix: a prefix for all the functions to define (of form <name>_*)
|
||||
*
|
||||
* NULL values may not be placed into the hash table.
|
||||
*
|
||||
* This defines the type hashtable type and an iterator type:
|
||||
* struct <name>;
|
||||
* struct <name>_iter;
|
||||
*
|
||||
* 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);
|
||||
*
|
||||
* Delete and delete-by key return true if it was in the set:
|
||||
* 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:
|
||||
* 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.
|
||||
*
|
||||
* You can use HTABLE_INITIALIZER like so:
|
||||
* struct <name> ht = { HTABLE_INITIALIZER(ht.raw, <name>_hash, NULL) };
|
||||
*/
|
||||
#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \
|
||||
struct name { struct htable raw; }; \
|
||||
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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
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; \
|
||||
} \
|
||||
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) \
|
||||
{ \
|
||||
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) \
|
||||
{ \
|
||||
return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \
|
||||
} \
|
||||
static inline UNNEEDED 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, \
|
||||
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))
|
||||
#else
|
||||
/* Assumes keys are a pointer: if not, override. */
|
||||
#ifndef HTABLE_KTYPE
|
||||
#define HTABLE_KTYPE(keyof, type) void *
|
||||
#endif
|
||||
#endif
|
||||
#endif /* CCAN_HTABLE_TYPE_H */
|
||||
41
nostrdb/ccan/ccan/htable/tools/Makefile
Normal file
41
nostrdb/ccan/ccan/htable/tools/Makefile
Normal file
@@ -0,0 +1,41 @@
|
||||
CCANDIR=../../..
|
||||
CFLAGS=-Wall -Werror -O3 -I$(CCANDIR)
|
||||
#CFLAGS=-Wall -Werror -g -I$(CCANDIR)
|
||||
|
||||
CCAN_OBJS:=ccan-tal.o ccan-tal-str.o ccan-tal-grab_file.o ccan-take.o ccan-time.o ccan-str.o ccan-noerr.o ccan-list.o
|
||||
|
||||
all: speed stringspeed hsearchspeed density
|
||||
|
||||
speed: speed.o hash.o $(CCAN_OBJS)
|
||||
density: density.o hash.o $(CCAN_OBJS)
|
||||
|
||||
speed.o: speed.c ../htable.h ../htable.c
|
||||
|
||||
hash.o: ../../hash/hash.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
stringspeed: stringspeed.o hash.o $(CCAN_OBJS)
|
||||
|
||||
stringspeed.o: speed.c ../htable.h ../htable.c
|
||||
|
||||
hsearchspeed: hsearchspeed.o $(CCAN_OBJS)
|
||||
|
||||
clean:
|
||||
rm -f stringspeed speed hsearchspeed *.o
|
||||
|
||||
ccan-tal.o: $(CCANDIR)/ccan/tal/tal.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-tal-str.o: $(CCANDIR)/ccan/tal/str/str.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-take.o: $(CCANDIR)/ccan/take/take.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-tal-grab_file.o: $(CCANDIR)/ccan/tal/grab_file/grab_file.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-time.o: $(CCANDIR)/ccan/time/time.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-list.o: $(CCANDIR)/ccan/list/list.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-str.o: $(CCANDIR)/ccan/str/str.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-noerr.o: $(CCANDIR)/ccan/noerr/noerr.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
107
nostrdb/ccan/ccan/htable/tools/density.c
Normal file
107
nostrdb/ccan/ccan/htable/tools/density.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* Density measurements for hashtables. */
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/htable/htable.c>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/ptrint/ptrint.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* We don't actually hash objects: we put values in as if they were ptrs */
|
||||
static uintptr_t key(const ptrint_t *obj)
|
||||
{
|
||||
return ptr2int(obj);
|
||||
}
|
||||
|
||||
static size_t hash_uintptr(uintptr_t key)
|
||||
{
|
||||
return hashl(&key, 1, 0);
|
||||
}
|
||||
|
||||
static bool cmp(const ptrint_t *p, uintptr_t k)
|
||||
{
|
||||
return key(p) == k;
|
||||
}
|
||||
|
||||
HTABLE_DEFINE_TYPE(ptrint_t, key, hash_uintptr, cmp, htable_ptrint);
|
||||
|
||||
/* Nanoseconds per operation */
|
||||
static size_t normalize(const struct timeabs *start,
|
||||
const struct timeabs *stop,
|
||||
unsigned int num)
|
||||
{
|
||||
return time_to_nsec(time_divide(time_between(*stop, *start), num));
|
||||
}
|
||||
|
||||
static size_t average_run(const struct htable_ptrint *ht, size_t count, size_t *longest)
|
||||
{
|
||||
size_t i, total = 0;
|
||||
|
||||
*longest = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
size_t h = hash_uintptr(i + 2);
|
||||
size_t run = 1;
|
||||
|
||||
while (get_raw_ptr(&ht->raw, ht->raw.table[h % ((size_t)1 << ht->raw.bits)]) != int2ptr(i + 2)) {
|
||||
h++;
|
||||
run++;
|
||||
}
|
||||
total += run;
|
||||
if (run > *longest)
|
||||
*longest = run;
|
||||
}
|
||||
return total / count;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned int i;
|
||||
size_t num;
|
||||
struct timeabs start, stop;
|
||||
struct htable_ptrint ht;
|
||||
|
||||
if (argc != 2)
|
||||
errx(1, "Usage: density <power-of-2-tablesize>");
|
||||
|
||||
num = atoi(argv[1]);
|
||||
|
||||
printf("Total buckets, buckets used, nanoseconds search time per element, avg run, longest run\n");
|
||||
for (i = 1; i <= 99; i++) {
|
||||
uintptr_t j;
|
||||
struct htable_ptrint_iter it;
|
||||
size_t count, avg_run, longest_run;
|
||||
ptrint_t *p;
|
||||
|
||||
htable_ptrint_init_sized(&ht, num * 3 / 4);
|
||||
assert((1 << ht.raw.bits) == num);
|
||||
|
||||
/* Can't put 0 or 1 in the hash table: multiply by a prime. */
|
||||
for (j = 0; j < num * i / 100; j++) {
|
||||
htable_ptrint_add(&ht, int2ptr(j + 2));
|
||||
/* stop it from doubling! */
|
||||
ht.raw.elems = num / 2;
|
||||
}
|
||||
/* Must not have changed! */
|
||||
assert((1 << ht.raw.bits) == num);
|
||||
|
||||
/* Clean cache */
|
||||
count = 0;
|
||||
for (p = htable_ptrint_first(&ht, &it); p; p = htable_ptrint_next(&ht, &it))
|
||||
count++;
|
||||
assert(count == num * i / 100);
|
||||
start = time_now();
|
||||
for (j = 0; j < count; j++)
|
||||
assert(htable_ptrint_get(&ht, j + 2));
|
||||
stop = time_now();
|
||||
avg_run = average_run(&ht, count, &longest_run);
|
||||
printf("%zu,%zu,%zu,%zu,%zu\n",
|
||||
num, count, normalize(&start, &stop, count), avg_run, longest_run);
|
||||
fflush(stdout);
|
||||
htable_ptrint_clear(&ht);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
95
nostrdb/ccan/ccan/htable/tools/hsearchspeed.c
Normal file
95
nostrdb/ccan/ccan/htable/tools/hsearchspeed.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/* Simple speed tests for a hash of strings using hsearch */
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/htable/htable.c>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/tal/grab_file/grab_file.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <search.h>
|
||||
|
||||
/* Nanoseconds per operation */
|
||||
static size_t normalize(const struct timeabs *start,
|
||||
const struct timeabs *stop,
|
||||
unsigned int num)
|
||||
{
|
||||
return time_to_nsec(time_divide(time_between(*stop, *start), num));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
size_t i, j, num;
|
||||
struct timeabs start, stop;
|
||||
char **w;
|
||||
ENTRY *words, *misswords;
|
||||
|
||||
w = tal_strsplit(NULL, grab_file(NULL,
|
||||
argv[1] ? argv[1] : "/usr/share/dict/words"), "\n", STR_NO_EMPTY);
|
||||
num = tal_count(w) - 1;
|
||||
printf("%zu words\n", num);
|
||||
|
||||
hcreate(num+num/3);
|
||||
|
||||
words = tal_arr(w, ENTRY, num);
|
||||
for (i = 0; i < num; i++) {
|
||||
words[i].key = w[i];
|
||||
words[i].data = words[i].key;
|
||||
}
|
||||
|
||||
/* Append and prepend last char for miss testing. */
|
||||
misswords = tal_arr(w, ENTRY, num);
|
||||
for (i = 0; i < num; i++) {
|
||||
char lastc;
|
||||
if (strlen(w[i]))
|
||||
lastc = w[i][strlen(w[i])-1];
|
||||
else
|
||||
lastc = 'z';
|
||||
misswords[i].key = tal_fmt(misswords, "%c%s%c%c",
|
||||
lastc, w[i], lastc, lastc);
|
||||
}
|
||||
|
||||
printf("#01: Initial insert: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
hsearch(words[i], ENTER);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#02: Initial lookup (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (hsearch(words[i], FIND)->data != words[i].data)
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#03: Initial lookup (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
if (hsearch(misswords[i], FIND))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Lookups in order are very cache-friendly for judy; try random */
|
||||
printf("#04: Initial lookup (random): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num)
|
||||
if (hsearch(words[i], FIND)->data != words[i].data)
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
return 0;
|
||||
}
|
||||
370
nostrdb/ccan/ccan/htable/tools/speed.c
Normal file
370
nostrdb/ccan/ccan/htable/tools/speed.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/* Simple speed tests for hashtables. */
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/htable/htable.c>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static size_t hashcount;
|
||||
struct object {
|
||||
/* The key. */
|
||||
unsigned int key;
|
||||
|
||||
/* Some contents. Doubles as consistency check. */
|
||||
struct object *self;
|
||||
};
|
||||
|
||||
static const unsigned int *objkey(const struct object *obj)
|
||||
{
|
||||
return &obj->key;
|
||||
}
|
||||
|
||||
static size_t hash_obj(const unsigned int *key)
|
||||
{
|
||||
hashcount++;
|
||||
return hashl(key, 1, 0);
|
||||
}
|
||||
|
||||
static bool cmp(const struct object *object, const unsigned int *key)
|
||||
{
|
||||
return object->key == *key;
|
||||
}
|
||||
|
||||
HTABLE_DEFINE_TYPE(struct object, objkey, hash_obj, cmp, htable_obj);
|
||||
|
||||
static unsigned int popcount(unsigned long val)
|
||||
{
|
||||
#if HAVE_BUILTIN_POPCOUNTL
|
||||
return __builtin_popcountl(val);
|
||||
#else
|
||||
if (sizeof(long) == sizeof(u64)) {
|
||||
u64 v = val;
|
||||
v = (v & 0x5555555555555555ULL)
|
||||
+ ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL)
|
||||
+ ((v >> 1) & 0x3333333333333333ULL);
|
||||
v = (v & 0x0F0F0F0F0F0F0F0FULL)
|
||||
+ ((v >> 1) & 0x0F0F0F0F0F0F0F0FULL);
|
||||
v = (v & 0x00FF00FF00FF00FFULL)
|
||||
+ ((v >> 1) & 0x00FF00FF00FF00FFULL);
|
||||
v = (v & 0x0000FFFF0000FFFFULL)
|
||||
+ ((v >> 1) & 0x0000FFFF0000FFFFULL);
|
||||
v = (v & 0x00000000FFFFFFFFULL)
|
||||
+ ((v >> 1) & 0x00000000FFFFFFFFULL);
|
||||
return v;
|
||||
}
|
||||
val = (val & 0x55555555ULL) + ((val >> 1) & 0x55555555ULL);
|
||||
val = (val & 0x33333333ULL) + ((val >> 1) & 0x33333333ULL);
|
||||
val = (val & 0x0F0F0F0FULL) + ((val >> 1) & 0x0F0F0F0FULL);
|
||||
val = (val & 0x00FF00FFULL) + ((val >> 1) & 0x00FF00FFULL);
|
||||
val = (val & 0x0000FFFFULL) + ((val >> 1) & 0x0000FFFFULL);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t perfect(const struct htable *ht)
|
||||
{
|
||||
size_t i, placed_perfect = 0;
|
||||
|
||||
for (i = 0; i < ((size_t)1 << ht->bits); i++) {
|
||||
if (!entry_is_valid(ht->table[i]))
|
||||
continue;
|
||||
if (hash_bucket(ht, ht->rehash(get_raw_ptr(ht, ht->table[i]),
|
||||
ht->priv)) == i) {
|
||||
assert((ht->table[i] & ht_perfect_mask(ht))
|
||||
== ht_perfect_mask(ht));
|
||||
placed_perfect++;
|
||||
}
|
||||
}
|
||||
return placed_perfect;
|
||||
}
|
||||
|
||||
static size_t count_deleted(const struct htable *ht)
|
||||
{
|
||||
size_t i, delete_markers = 0;
|
||||
|
||||
for (i = 0; i < ((size_t)1 << ht->bits); i++) {
|
||||
if (ht->table[i] == HTABLE_DELETED)
|
||||
delete_markers++;
|
||||
}
|
||||
return delete_markers;
|
||||
}
|
||||
|
||||
/* Nanoseconds per operation */
|
||||
static size_t normalize(const struct timeabs *start,
|
||||
const struct timeabs *stop,
|
||||
unsigned int num)
|
||||
{
|
||||
return time_to_nsec(time_divide(time_between(*stop, *start), num));
|
||||
}
|
||||
|
||||
static size_t worst_run(struct htable *ht, size_t *deleted)
|
||||
{
|
||||
size_t longest = 0, len = 0, this_del = 0, i;
|
||||
|
||||
*deleted = 0;
|
||||
/* This doesn't take into account end-wrap, but gives an idea. */
|
||||
for (i = 0; i < ((size_t)1 << ht->bits); i++) {
|
||||
if (ht->table[i]) {
|
||||
len++;
|
||||
if (ht->table[i] == HTABLE_DELETED)
|
||||
this_del++;
|
||||
} else {
|
||||
if (len > longest) {
|
||||
longest = len;
|
||||
*deleted = this_del;
|
||||
}
|
||||
len = 0;
|
||||
this_del = 0;
|
||||
}
|
||||
}
|
||||
return longest;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct object *objs;
|
||||
unsigned int i, j;
|
||||
size_t num, deleted;
|
||||
struct timeabs start, stop;
|
||||
struct htable_obj ht;
|
||||
bool make_dumb = false;
|
||||
|
||||
if (argv[1] && strcmp(argv[1], "--dumb") == 0) {
|
||||
argv++;
|
||||
make_dumb = true;
|
||||
}
|
||||
num = argv[1] ? atoi(argv[1]) : 1000000;
|
||||
objs = calloc(num, sizeof(objs[0]));
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
objs[i].key = i;
|
||||
objs[i].self = &objs[i];
|
||||
}
|
||||
|
||||
htable_obj_init(&ht);
|
||||
|
||||
printf("Initial insert: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
htable_obj_add(&ht, objs[i].self);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
printf("Details: hash size %u, mask bits %u, perfect %.0f%%\n",
|
||||
1U << ht.raw.bits, popcount(ht.raw.common_mask),
|
||||
perfect(&ht.raw) * 100.0 / ht.raw.elems);
|
||||
|
||||
if (make_dumb) {
|
||||
/* Screw with mask, to hobble us. */
|
||||
update_common(&ht.raw, (void *)~ht.raw.common_bits);
|
||||
printf("Details: DUMB MODE: mask bits %u\n",
|
||||
popcount(ht.raw.common_mask));
|
||||
}
|
||||
|
||||
printf("Initial lookup (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (htable_obj_get(&ht, &i)->self != objs[i].self)
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Initial lookup (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
unsigned int n = i + num;
|
||||
if (htable_obj_get(&ht, &n))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Lookups in order are very cache-friendly for judy; try random */
|
||||
printf("Initial lookup (random): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num)
|
||||
if (htable_obj_get(&ht, &j)->self != &objs[j])
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
hashcount = 0;
|
||||
printf("Initial delete all: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (!htable_obj_del(&ht, objs[i].self))
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
printf("Details: rehashes %zu\n", hashcount);
|
||||
|
||||
printf("Initial re-inserting: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
htable_obj_add(&ht, objs[i].self);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
hashcount = 0;
|
||||
printf("Deleting first half: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
if (!htable_obj_del(&ht, objs[i].self))
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Details: rehashes %zu, delete markers %zu\n",
|
||||
hashcount, count_deleted(&ht.raw));
|
||||
|
||||
printf("Adding (a different) half: ");
|
||||
fflush(stdout);
|
||||
|
||||
for (i = 0; i < num; i+=2)
|
||||
objs[i].key = num+i;
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
htable_obj_add(&ht, objs[i].self);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Details: delete markers %zu, perfect %.0f%%\n",
|
||||
count_deleted(&ht.raw), perfect(&ht.raw) * 100.0 / ht.raw.elems);
|
||||
|
||||
printf("Lookup after half-change (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 1; i < num; i+=2)
|
||||
if (htable_obj_get(&ht, &i)->self != objs[i].self)
|
||||
abort();
|
||||
for (i = 0; i < num; i+=2) {
|
||||
unsigned int n = i + num;
|
||||
if (htable_obj_get(&ht, &n)->self != objs[i].self)
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Lookup after half-change (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
unsigned int n = i + num * 2;
|
||||
if (htable_obj_get(&ht, &n))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Hashtables with delete markers can fill with markers over time.
|
||||
* so do some changes to see how it operates in long-term. */
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (i == 0) {
|
||||
/* We don't measure this: jmap is different. */
|
||||
printf("Details: initial churn\n");
|
||||
} else {
|
||||
printf("Churning %s time: ",
|
||||
i == 1 ? "second"
|
||||
: i == 2 ? "third"
|
||||
: i == 3 ? "fourth"
|
||||
: "fifth");
|
||||
fflush(stdout);
|
||||
}
|
||||
start = time_now();
|
||||
for (j = 0; j < num; j++) {
|
||||
if (!htable_obj_del(&ht, &objs[j]))
|
||||
abort();
|
||||
objs[j].key = num*i+j;
|
||||
if (!htable_obj_add(&ht, &objs[j]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
if (i != 0)
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
}
|
||||
|
||||
/* Spread out the keys more to try to make it harder. */
|
||||
printf("Details: reinserting with spread\n");
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!htable_obj_del(&ht, objs[i].self))
|
||||
abort();
|
||||
objs[i].key = num * 5 + i * 9;
|
||||
if (!htable_obj_add(&ht, objs[i].self))
|
||||
abort();
|
||||
}
|
||||
printf("Details: delete markers %zu, perfect %.0f%%\n",
|
||||
count_deleted(&ht.raw), perfect(&ht.raw) * 100.0 / ht.raw.elems);
|
||||
i = worst_run(&ht.raw, &deleted);
|
||||
printf("Details: worst run %u (%zu deleted)\n", i, deleted);
|
||||
|
||||
printf("Lookup after churn & spread (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
unsigned int n = num * 5 + i * 9;
|
||||
if (htable_obj_get(&ht, &n)->self != objs[i].self)
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Lookup after churn & spread (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
unsigned int n = num * (5 + 9) + i * 9;
|
||||
if (htable_obj_get(&ht, &n))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Lookup after churn & spread (random): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num) {
|
||||
unsigned int n = num * 5 + j * 9;
|
||||
if (htable_obj_get(&ht, &n)->self != &objs[j])
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
hashcount = 0;
|
||||
printf("Deleting half after churn & spread: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
if (!htable_obj_del(&ht, objs[i].self))
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Adding (a different) half after churn & spread: ");
|
||||
fflush(stdout);
|
||||
|
||||
for (i = 0; i < num; i+=2)
|
||||
objs[i].key = num*6+i*9;
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
htable_obj_add(&ht, objs[i].self);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Details: delete markers %zu, perfect %.0f%%\n",
|
||||
count_deleted(&ht.raw), perfect(&ht.raw) * 100.0 / ht.raw.elems);
|
||||
|
||||
return 0;
|
||||
}
|
||||
240
nostrdb/ccan/ccan/htable/tools/stringspeed.c
Normal file
240
nostrdb/ccan/ccan/htable/tools/stringspeed.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/* Simple speed tests for a hash of strings. */
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/htable/htable.c>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/tal/grab_file/grab_file.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static size_t hashcount;
|
||||
|
||||
static const char *strkey(const char *str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
static size_t hash_str(const char *key)
|
||||
{
|
||||
hashcount++;
|
||||
return hash(key, strlen(key), 0);
|
||||
}
|
||||
|
||||
static bool cmp(const char *obj, const char *key)
|
||||
{
|
||||
return strcmp(obj, key) == 0;
|
||||
}
|
||||
|
||||
HTABLE_DEFINE_TYPE(char, strkey, hash_str, cmp, htable_str);
|
||||
|
||||
/* Nanoseconds per operation */
|
||||
static size_t normalize(const struct timeabs *start,
|
||||
const struct timeabs *stop,
|
||||
unsigned int num)
|
||||
{
|
||||
return time_to_nsec(time_divide(time_between(*stop, *start), num));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
size_t i, j, num;
|
||||
struct timeabs start, stop;
|
||||
struct htable_str ht;
|
||||
char **words, **misswords;
|
||||
|
||||
words = tal_strsplit(NULL, grab_file(NULL,
|
||||
argv[1] ? argv[1] : "/usr/share/dict/words"), "\n",
|
||||
STR_NO_EMPTY);
|
||||
htable_str_init(&ht);
|
||||
num = tal_count(words) - 1;
|
||||
/* Note that on my system, num is just > 98304, where we double! */
|
||||
printf("%zu words\n", num);
|
||||
|
||||
/* Append and prepend last char for miss testing. */
|
||||
misswords = tal_arr(words, char *, num);
|
||||
for (i = 0; i < num; i++) {
|
||||
char lastc;
|
||||
if (strlen(words[i]))
|
||||
lastc = words[i][strlen(words[i])-1];
|
||||
else
|
||||
lastc = 'z';
|
||||
misswords[i] = tal_fmt(misswords, "%c%s%c%c",
|
||||
lastc, words[i], lastc, lastc);
|
||||
}
|
||||
|
||||
printf("#01: Initial insert: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
htable_str_add(&ht, words[i]);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("Bytes allocated: %zu\n",
|
||||
sizeof(ht.raw.table[0]) << ht.raw.bits);
|
||||
|
||||
printf("#02: Initial lookup (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (htable_str_get(&ht, words[i]) != words[i])
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#03: Initial lookup (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
if (htable_str_get(&ht, misswords[i]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Lookups in order are very cache-friendly for judy; try random */
|
||||
printf("#04: Initial lookup (random): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num)
|
||||
if (htable_str_get(&ht, words[j]) != words[j])
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
hashcount = 0;
|
||||
printf("#05: Initial delete all: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (!htable_str_del(&ht, words[i]))
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#06: Initial re-inserting: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
htable_str_add(&ht, words[i]);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
hashcount = 0;
|
||||
printf("#07: Deleting first half: ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
if (!htable_str_del(&ht, words[i]))
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#08: Adding (a different) half: ");
|
||||
fflush(stdout);
|
||||
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
htable_str_add(&ht, misswords[i]);
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#09: Lookup after half-change (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 1; i < num; i+=2)
|
||||
if (htable_str_get(&ht, words[i]) != words[i])
|
||||
abort();
|
||||
for (i = 0; i < num; i+=2) {
|
||||
if (htable_str_get(&ht, misswords[i]) != misswords[i])
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#10: Lookup after half-change (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i+=2)
|
||||
if (htable_str_get(&ht, words[i]))
|
||||
abort();
|
||||
for (i = 1; i < num; i+=2) {
|
||||
if (htable_str_get(&ht, misswords[i]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Hashtables with delete markers can fill with markers over time.
|
||||
* so do some changes to see how it operates in long-term. */
|
||||
printf("#11: Churn 1: ");
|
||||
start = time_now();
|
||||
for (j = 0; j < num; j+=2) {
|
||||
if (!htable_str_del(&ht, misswords[j]))
|
||||
abort();
|
||||
if (!htable_str_add(&ht, words[j]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#12: Churn 2: ");
|
||||
start = time_now();
|
||||
for (j = 1; j < num; j+=2) {
|
||||
if (!htable_str_del(&ht, words[j]))
|
||||
abort();
|
||||
if (!htable_str_add(&ht, misswords[j]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#13: Churn 3: ");
|
||||
start = time_now();
|
||||
for (j = 1; j < num; j+=2) {
|
||||
if (!htable_str_del(&ht, misswords[j]))
|
||||
abort();
|
||||
if (!htable_str_add(&ht, words[j]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Now it's back to normal... */
|
||||
printf("#14: Post-Churn lookup (match): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++)
|
||||
if (htable_str_get(&ht, words[i]) != words[i])
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
printf("#15: Post-Churn lookup (miss): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0; i < num; i++) {
|
||||
if (htable_str_get(&ht, misswords[i]))
|
||||
abort();
|
||||
}
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
/* Lookups in order are very cache-friendly for judy; try random */
|
||||
printf("#16: Post-Churn lookup (random): ");
|
||||
fflush(stdout);
|
||||
start = time_now();
|
||||
for (i = 0, j = 0; i < num; i++, j = (j + 10007) % num)
|
||||
if (htable_str_get(&ht, words[j]) != words[j])
|
||||
abort();
|
||||
stop = time_now();
|
||||
printf(" %zu ns\n", normalize(&start, &stop, num));
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
nostrdb/ccan/ccan/likely/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/likely/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
57
nostrdb/ccan/ccan/likely/_info
Normal file
57
nostrdb/ccan/ccan/likely/_info
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* likely - macros for annotating likely/unlikely branches in the code
|
||||
*
|
||||
* Inspired by Andi Kleen's macros for the Linux Kernel, these macros
|
||||
* help you annotate rare paths in your code for the convenience of the
|
||||
* compiler and the reader.
|
||||
*
|
||||
* With CCAN_LIKELY_DEBUG defined, it provides statistics for each
|
||||
* likely()/unlikely() call (but note that this requires LGPL dependencies).
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/likely/likely.h>
|
||||
* #include <stdio.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* // This example is silly: the compiler knows exit() is unlikely.
|
||||
* if (unlikely(argc == 1)) {
|
||||
* fprintf(stderr, "Usage: %s <args>...\n", argv[0]);
|
||||
* return 1;
|
||||
* }
|
||||
* for (argc++; argv[argc]; argc++)
|
||||
* printf("%s\n", argv[argc]);
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
#ifdef CCAN_LIKELY_DEBUG
|
||||
printf("ccan/str\n");
|
||||
printf("ccan/htable\n");
|
||||
printf("ccan/hash\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[1], "testdepends") == 0) {
|
||||
#ifndef CCAN_LIKELY_DEBUG
|
||||
printf("ccan/str\n");
|
||||
printf("ccan/htable\n");
|
||||
printf("ccan/hash\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
136
nostrdb/ccan/ccan/likely/likely.c
Normal file
136
nostrdb/ccan/ccan/likely/likely.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details. */
|
||||
#ifdef CCAN_LIKELY_DEBUG
|
||||
#include <ccan/likely/likely.h>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
struct trace {
|
||||
const char *condstr;
|
||||
const char *file;
|
||||
unsigned int line;
|
||||
bool expect;
|
||||
unsigned long count, right;
|
||||
};
|
||||
|
||||
static size_t hash_trace(const struct trace *trace)
|
||||
{
|
||||
return hash(trace->condstr, strlen(trace->condstr),
|
||||
hash(trace->file, strlen(trace->file),
|
||||
trace->line + trace->expect));
|
||||
}
|
||||
|
||||
static bool trace_eq(const struct trace *t1, const struct trace *t2)
|
||||
{
|
||||
return t1->condstr == t2->condstr
|
||||
&& t1->file == t2->file
|
||||
&& t1->line == t2->line
|
||||
&& t1->expect == t2->expect;
|
||||
}
|
||||
|
||||
/* struct thash */
|
||||
HTABLE_DEFINE_TYPE(struct trace, (const struct trace *), hash_trace, trace_eq,
|
||||
thash);
|
||||
|
||||
static struct thash htable
|
||||
= { HTABLE_INITIALIZER(htable.raw, thash_hash, NULL) };
|
||||
|
||||
static void init_trace(struct trace *trace,
|
||||
const char *condstr, const char *file, unsigned int line,
|
||||
bool expect)
|
||||
{
|
||||
trace->condstr = condstr;
|
||||
trace->file = file;
|
||||
trace->line = line;
|
||||
trace->expect = expect;
|
||||
trace->count = trace->right = 0;
|
||||
}
|
||||
|
||||
static struct trace *add_trace(const struct trace *t)
|
||||
{
|
||||
struct trace *trace = malloc(sizeof(*trace));
|
||||
*trace = *t;
|
||||
thash_add(&htable, trace);
|
||||
return trace;
|
||||
}
|
||||
|
||||
long _likely_trace(bool cond, bool expect,
|
||||
const char *condstr,
|
||||
const char *file, unsigned int line)
|
||||
{
|
||||
struct trace *p, trace;
|
||||
|
||||
init_trace(&trace, condstr, file, line, expect);
|
||||
p = thash_get(&htable, &trace);
|
||||
if (!p)
|
||||
p = add_trace(&trace);
|
||||
|
||||
p->count++;
|
||||
if (cond == expect)
|
||||
p->right++;
|
||||
|
||||
return cond;
|
||||
}
|
||||
|
||||
static double right_ratio(const struct trace *t)
|
||||
{
|
||||
return (double)t->right / t->count;
|
||||
}
|
||||
|
||||
char *likely_stats(unsigned int min_hits, unsigned int percent)
|
||||
{
|
||||
struct trace *worst;
|
||||
double worst_ratio;
|
||||
struct thash_iter i;
|
||||
char *ret;
|
||||
struct trace *t;
|
||||
|
||||
worst = NULL;
|
||||
worst_ratio = 2;
|
||||
|
||||
/* This is O(n), but it's not likely called that often. */
|
||||
for (t = thash_first(&htable, &i); t; t = thash_next(&htable, &i)) {
|
||||
if (t->count >= min_hits) {
|
||||
if (right_ratio(t) < worst_ratio) {
|
||||
worst = t;
|
||||
worst_ratio = right_ratio(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (worst_ratio * 100 > percent)
|
||||
return NULL;
|
||||
|
||||
ret = malloc(strlen(worst->condstr) +
|
||||
strlen(worst->file) +
|
||||
sizeof(long int) * 8 +
|
||||
sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)"));
|
||||
sprintf(ret, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)",
|
||||
worst->file, worst->line,
|
||||
worst->expect ? "" : "un", worst->condstr,
|
||||
(unsigned)(worst_ratio * 100),
|
||||
worst->right, worst->count);
|
||||
|
||||
thash_del(&htable, worst);
|
||||
free(worst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void likely_stats_reset(void)
|
||||
{
|
||||
struct thash_iter i;
|
||||
struct trace *t;
|
||||
|
||||
/* This is a bit better than O(n^2), but we have to loop since
|
||||
* first/next during delete is unreliable. */
|
||||
while ((t = thash_first(&htable, &i)) != NULL) {
|
||||
for (; t; t = thash_next(&htable, &i)) {
|
||||
thash_del(&htable, t);
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
|
||||
thash_clear(&htable);
|
||||
}
|
||||
#endif /*CCAN_LIKELY_DEBUG*/
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_LIKELY_H
|
||||
#define CCAN_LIKELY_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef CCAN_LIKELY_DEBUG
|
||||
@@ -17,17 +17,17 @@
|
||||
* 99%; marginal cases should not be marked either way.
|
||||
*
|
||||
* See Also:
|
||||
* unlikely(), likely_stats()
|
||||
* unlikely(), likely_stats()
|
||||
*
|
||||
* Example:
|
||||
* // Returns false if we overflow.
|
||||
* static inline bool inc_int(unsigned int *val)
|
||||
* {
|
||||
* (*val)++;
|
||||
* if (likely(*val))
|
||||
* return true;
|
||||
* return false;
|
||||
* }
|
||||
* // Returns false if we overflow.
|
||||
* static inline bool inc_int(unsigned int *val)
|
||||
* {
|
||||
* (*val)++;
|
||||
* if (likely(*val))
|
||||
* return true;
|
||||
* return false;
|
||||
* }
|
||||
*/
|
||||
#define likely(cond) __builtin_expect(!!(cond), 1)
|
||||
|
||||
@@ -39,37 +39,33 @@
|
||||
* code path and optimize appropriately; see likely() above.
|
||||
*
|
||||
* See Also:
|
||||
* likely(), likely_stats(), COLD (compiler.h)
|
||||
* likely(), likely_stats(), COLD (compiler.h)
|
||||
*
|
||||
* Example:
|
||||
* // Prints a warning if we overflow.
|
||||
* static inline void inc_int(unsigned int *val)
|
||||
* {
|
||||
* (*val)++;
|
||||
* if (unlikely(*val == 0))
|
||||
* fprintf(stderr, "Overflow!");
|
||||
* }
|
||||
* // Prints a warning if we overflow.
|
||||
* static inline void inc_int(unsigned int *val)
|
||||
* {
|
||||
* (*val)++;
|
||||
* if (unlikely(*val == 0))
|
||||
* fprintf(stderr, "Overflow!");
|
||||
* }
|
||||
*/
|
||||
#define unlikely(cond) __builtin_expect(!!(cond), 0)
|
||||
#else
|
||||
#ifndef likely
|
||||
#define likely(cond) (!!(cond))
|
||||
#endif
|
||||
#ifndef unlikely
|
||||
#define unlikely(cond) (!!(cond))
|
||||
#endif
|
||||
#endif
|
||||
#else /* CCAN_LIKELY_DEBUG versions */
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
#define likely(cond) \
|
||||
(_likely_trace(!!(cond), 1, stringify(cond), __FILE__, __LINE__))
|
||||
(_likely_trace(!!(cond), 1, stringify(cond), __FILE__, __LINE__))
|
||||
#define unlikely(cond) \
|
||||
(_likely_trace(!!(cond), 0, stringify(cond), __FILE__, __LINE__))
|
||||
(_likely_trace(!!(cond), 0, stringify(cond), __FILE__, __LINE__))
|
||||
|
||||
long _likely_trace(bool cond, bool expect,
|
||||
const char *condstr,
|
||||
const char *file, unsigned int line);
|
||||
const char *condstr,
|
||||
const char *file, unsigned int line);
|
||||
/**
|
||||
* likely_stats - return description of abused likely()/unlikely()
|
||||
* @min_hits: minimum number of hits
|
||||
@@ -90,18 +86,18 @@ long _likely_trace(bool cond, bool expect,
|
||||
* return the next-worst likely()/unlikely() usage.
|
||||
*
|
||||
* Example:
|
||||
* // Print every place hit more than twice which was wrong > 5%.
|
||||
* static void report_stats(void)
|
||||
* {
|
||||
* #ifdef CCAN_LIKELY_DEBUG
|
||||
* const char *bad;
|
||||
* // Print every place hit more than twice which was wrong > 5%.
|
||||
* static void report_stats(void)
|
||||
* {
|
||||
* #ifdef CCAN_LIKELY_DEBUG
|
||||
* const char *bad;
|
||||
*
|
||||
* while ((bad = likely_stats(2, 95)) != NULL) {
|
||||
* printf("Suspicious likely: %s", bad);
|
||||
* free(bad);
|
||||
* }
|
||||
* #endif
|
||||
* }
|
||||
* while ((bad = likely_stats(2, 95)) != NULL) {
|
||||
* printf("Suspicious likely: %s", bad);
|
||||
* free(bad);
|
||||
* }
|
||||
* #endif
|
||||
* }
|
||||
*/
|
||||
char *likely_stats(unsigned int min_hits, unsigned int percent);
|
||||
|
||||
|
||||
1
nostrdb/ccan/ccan/list/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/list/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
||||
72
nostrdb/ccan/ccan/list/_info
Normal file
72
nostrdb/ccan/ccan/list/_info
Normal file
@@ -0,0 +1,72 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* list - double linked list routines
|
||||
*
|
||||
* The list header contains routines for manipulating double linked lists.
|
||||
* It defines two types: struct list_head used for anchoring lists, and
|
||||
* struct list_node which is usually embedded in the structure which is placed
|
||||
* in the list.
|
||||
*
|
||||
* Example:
|
||||
* #include <err.h>
|
||||
* #include <stdio.h>
|
||||
* #include <stdlib.h>
|
||||
* #include <ccan/list/list.h>
|
||||
*
|
||||
* struct parent {
|
||||
* const char *name;
|
||||
* struct list_head children;
|
||||
* unsigned int num_children;
|
||||
* };
|
||||
*
|
||||
* struct child {
|
||||
* const char *name;
|
||||
* struct list_node list;
|
||||
* };
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct parent p;
|
||||
* struct child *c;
|
||||
* int i;
|
||||
*
|
||||
* if (argc < 2)
|
||||
* errx(1, "Usage: %s parent children...", argv[0]);
|
||||
*
|
||||
* p.name = argv[1];
|
||||
* list_head_init(&p.children);
|
||||
* p.num_children = 0;
|
||||
* for (i = 2; i < argc; i++) {
|
||||
* c = malloc(sizeof(*c));
|
||||
* c->name = argv[i];
|
||||
* list_add(&p.children, &c->list);
|
||||
* p.num_children++;
|
||||
* }
|
||||
*
|
||||
* printf("%s has %u children:", p.name, p.num_children);
|
||||
* list_for_each(&p.children, c, list)
|
||||
* printf("%s ", c->name);
|
||||
* printf("\n");
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/str\n");
|
||||
printf("ccan/container_of\n");
|
||||
printf("ccan/check_type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -4,40 +4,40 @@
|
||||
#include "list.h"
|
||||
|
||||
static void *corrupt(const char *abortstr,
|
||||
const struct list_node *head,
|
||||
const struct list_node *node,
|
||||
unsigned int count)
|
||||
const struct list_node *head,
|
||||
const struct list_node *node,
|
||||
unsigned int count)
|
||||
{
|
||||
if (abortstr) {
|
||||
fprintf(stderr,
|
||||
"%s: prev corrupt in node %p (%u) of %p\n",
|
||||
abortstr, node, count, head);
|
||||
abort();
|
||||
}
|
||||
return NULL;
|
||||
if (abortstr) {
|
||||
fprintf(stderr,
|
||||
"%s: prev corrupt in node %p (%u) of %p\n",
|
||||
abortstr, node, count, head);
|
||||
abort();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct list_node *list_check_node(const struct list_node *node,
|
||||
const char *abortstr)
|
||||
const char *abortstr)
|
||||
{
|
||||
const struct list_node *p, *n;
|
||||
int count = 0;
|
||||
const struct list_node *p, *n;
|
||||
int count = 0;
|
||||
|
||||
for (p = node, n = node->next; n != node; p = n, n = n->next) {
|
||||
count++;
|
||||
if (n->prev != p)
|
||||
return corrupt(abortstr, node, n, count);
|
||||
}
|
||||
/* Check prev on head node. */
|
||||
if (node->prev != p)
|
||||
return corrupt(abortstr, node, node, 0);
|
||||
for (p = node, n = node->next; n != node; p = n, n = n->next) {
|
||||
count++;
|
||||
if (n->prev != p)
|
||||
return corrupt(abortstr, node, n, count);
|
||||
}
|
||||
/* Check prev on head node. */
|
||||
if (node->prev != p)
|
||||
return corrupt(abortstr, node, node, 0);
|
||||
|
||||
return (struct list_node *)node;
|
||||
return (struct list_node *)node;
|
||||
}
|
||||
|
||||
struct list_head *list_check(const struct list_head *h, const char *abortstr)
|
||||
{
|
||||
if (!list_check_node(&h->n, abortstr))
|
||||
return NULL;
|
||||
return (struct list_head *)h;
|
||||
if (!list_check_node(&h->n, abortstr))
|
||||
return NULL;
|
||||
return (struct list_head *)h;
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
//#define CCAN_LIST_DEBUG 1
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include "str.h"
|
||||
#include "ccan/container_of/container_of.h"
|
||||
#include "ccan/check_type/check_type.h"
|
||||
#include <ccan/str/str.h>
|
||||
#include <ccan/container_of/container_of.h>
|
||||
#include <ccan/check_type/check_type.h>
|
||||
|
||||
/**
|
||||
* struct list_node - an entry in a doubly-linked list
|
||||
@@ -15,15 +15,15 @@
|
||||
*
|
||||
* This is used as an entry in a linked list.
|
||||
* Example:
|
||||
* struct child {
|
||||
* const char *name;
|
||||
* // Linked list of all us children.
|
||||
* struct list_node list;
|
||||
* };
|
||||
* struct child {
|
||||
* const char *name;
|
||||
* // Linked list of all us children.
|
||||
* struct list_node list;
|
||||
* };
|
||||
*/
|
||||
struct list_node
|
||||
{
|
||||
struct list_node *next, *prev;
|
||||
struct list_node *next, *prev;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -32,15 +32,15 @@ struct list_node
|
||||
*
|
||||
* This is used as the head of a linked list.
|
||||
* Example:
|
||||
* struct parent {
|
||||
* const char *name;
|
||||
* struct list_head children;
|
||||
* unsigned int num_children;
|
||||
* };
|
||||
* struct parent {
|
||||
* const char *name;
|
||||
* struct list_head children;
|
||||
* unsigned int num_children;
|
||||
* };
|
||||
*/
|
||||
struct list_head
|
||||
{
|
||||
struct list_node n;
|
||||
struct list_node n;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -59,15 +59,15 @@ struct list_head
|
||||
* See also: list_check_node()
|
||||
*
|
||||
* Example:
|
||||
* static void dump_parent(struct parent *p)
|
||||
* {
|
||||
* struct child *c;
|
||||
* static void dump_parent(struct parent *p)
|
||||
* {
|
||||
* struct child *c;
|
||||
*
|
||||
* printf("%s (%u children):\n", p->name, p->num_children);
|
||||
* list_check(&p->children, "bad child list");
|
||||
* list_for_each(&p->children, c, list)
|
||||
* printf(" -> %s\n", c->name);
|
||||
* }
|
||||
* printf("%s (%u children):\n", p->name, p->num_children);
|
||||
* list_check(&p->children, "bad child list");
|
||||
* list_for_each(&p->children, c, list)
|
||||
* printf(" -> %s\n", c->name);
|
||||
* }
|
||||
*/
|
||||
struct list_head *list_check(const struct list_head *h, const char *abortstr);
|
||||
|
||||
@@ -81,14 +81,14 @@ struct list_head *list_check(const struct list_head *h, const char *abortstr);
|
||||
* See also: list_check()
|
||||
*
|
||||
* Example:
|
||||
* static void dump_child(const struct child *c)
|
||||
* {
|
||||
* list_check_node(&c->list, "bad child list");
|
||||
* printf("%s\n", c->name);
|
||||
* }
|
||||
* static void dump_child(const struct child *c)
|
||||
* {
|
||||
* list_check_node(&c->list, "bad child list");
|
||||
* printf("%s\n", c->name);
|
||||
* }
|
||||
*/
|
||||
struct list_node *list_check_node(const struct list_node *n,
|
||||
const char *abortstr);
|
||||
const char *abortstr);
|
||||
|
||||
#define LIST_LOC __FILE__ ":" stringify(__LINE__)
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
@@ -106,10 +106,10 @@ struct list_node *list_check_node(const struct list_node *n,
|
||||
* Explicit initializer for an empty list.
|
||||
*
|
||||
* See also:
|
||||
* LIST_HEAD, list_head_init()
|
||||
* LIST_HEAD, list_head_init()
|
||||
*
|
||||
* Example:
|
||||
* static struct list_head my_list = LIST_HEAD_INIT(my_list);
|
||||
* static struct list_head my_list = LIST_HEAD_INIT(my_list);
|
||||
*/
|
||||
#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }
|
||||
|
||||
@@ -121,28 +121,28 @@ struct list_node *list_check_node(const struct list_node *n,
|
||||
* list. It can be prepended by "static" to define a static list_head.
|
||||
*
|
||||
* See also:
|
||||
* LIST_HEAD_INIT, list_head_init()
|
||||
* LIST_HEAD_INIT, list_head_init()
|
||||
*
|
||||
* Example:
|
||||
* static LIST_HEAD(my_global_list);
|
||||
* static LIST_HEAD(my_global_list);
|
||||
*/
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
/**
|
||||
* list_head_init - initialize a list_head
|
||||
* @h: the list_head to set to the empty list
|
||||
*
|
||||
* Example:
|
||||
* ...
|
||||
* struct parent *parent = malloc(sizeof(*parent));
|
||||
* ...
|
||||
* struct parent *parent = malloc(sizeof(*parent));
|
||||
*
|
||||
* list_head_init(&parent->children);
|
||||
* parent->num_children = 0;
|
||||
* list_head_init(&parent->children);
|
||||
* parent->num_children = 0;
|
||||
*/
|
||||
static inline void list_head_init(struct list_head *h)
|
||||
{
|
||||
h->n.next = h->n.prev = &h->n;
|
||||
h->n.next = h->n.prev = &h->n;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,7 +154,7 @@ static inline void list_head_init(struct list_head *h)
|
||||
*/
|
||||
static inline void list_node_init(struct list_node *n)
|
||||
{
|
||||
n->next = n->prev = n;
|
||||
n->next = n->prev = n;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,24 +167,24 @@ static inline void list_node_init(struct list_node *n)
|
||||
* The new list_node does not need to be initialized; it will be overwritten.
|
||||
*
|
||||
* Example:
|
||||
* struct child c1, c2, c3;
|
||||
* LIST_HEAD(h);
|
||||
* 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);
|
||||
* 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)
|
||||
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);
|
||||
n->next = p->next;
|
||||
n->prev = p;
|
||||
p->next->prev = n;
|
||||
p->next = n;
|
||||
(void)list_debug(h, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,18 +194,18 @@ static inline void list_add_after_(struct list_head *h,
|
||||
*
|
||||
* The list_node does not need to be initialized; it will be overwritten.
|
||||
* Example:
|
||||
* struct child *child = malloc(sizeof(*child));
|
||||
* struct child *child = malloc(sizeof(*child));
|
||||
*
|
||||
* child->name = "marvin";
|
||||
* list_add(&parent->children, &child->list);
|
||||
* parent->num_children++;
|
||||
* child->name = "marvin";
|
||||
* 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)
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
{
|
||||
list_add_after_(h, &h->n, n, abortstr);
|
||||
list_add_after_(h, &h->n, n, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,22 +218,22 @@ static inline void list_add_(struct list_head *h,
|
||||
* 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);
|
||||
* 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)
|
||||
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 = p;
|
||||
n->prev = p->prev;
|
||||
p->prev->next = n;
|
||||
p->prev = n;
|
||||
(void)list_debug(h, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,15 +243,15 @@ static inline void list_add_before_(struct list_head *h,
|
||||
*
|
||||
* The list_node does not need to be initialized; it will be overwritten.
|
||||
* Example:
|
||||
* list_add_tail(&parent->children, &child->list);
|
||||
* parent->num_children++;
|
||||
* 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)
|
||||
struct list_node *n,
|
||||
const char *abortstr)
|
||||
{
|
||||
list_add_before_(h, &h->n, n, abortstr);
|
||||
list_add_before_(h, &h->n, n, abortstr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,13 +261,13 @@ static inline void list_add_tail_(struct list_head *h,
|
||||
* If the list is empty, returns true.
|
||||
*
|
||||
* Example:
|
||||
* assert(list_empty(&parent->children) == (parent->num_children == 0));
|
||||
* 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;
|
||||
(void)list_debug(h, abortstr);
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,14 +280,14 @@ static inline bool list_empty_(const struct list_head *h, const char* abortstr)
|
||||
* know what you're doing.
|
||||
*
|
||||
* Example:
|
||||
* assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
|
||||
* 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;
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -303,7 +303,7 @@ static inline bool list_empty_nodebug(const struct list_head *h)
|
||||
*/
|
||||
static inline bool list_empty_nocheck(const struct list_head *h)
|
||||
{
|
||||
return h->n.next == &h->n;
|
||||
return h->n.next == &h->n;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -314,21 +314,21 @@ 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(), list_del_init()
|
||||
*
|
||||
* Example:
|
||||
* list_del(&child->list);
|
||||
* parent->num_children--;
|
||||
* 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)
|
||||
{
|
||||
(void)list_debug_node(n, abortstr);
|
||||
n->next->prev = n->prev;
|
||||
n->prev->next = n->next;
|
||||
(void)list_debug_node(n, abortstr);
|
||||
n->next->prev = n->prev;
|
||||
n->prev->next = n->next;
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
/* Catch use-after-del. */
|
||||
n->next = n->prev = NULL;
|
||||
/* Catch use-after-del. */
|
||||
n->next = n->prev = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -340,17 +340,17 @@ static inline void list_del_(struct list_node *n, const char* abortstr)
|
||||
* which can be useful in some cases.
|
||||
*
|
||||
* See also:
|
||||
* list_del_from(), list_del()
|
||||
* list_del_from(), list_del()
|
||||
*
|
||||
* Example:
|
||||
* list_del_init(&child->list);
|
||||
* parent->num_children--;
|
||||
* 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_(n, abortstr);
|
||||
list_node_init(n);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,23 +364,23 @@ static inline void list_del_init_(struct list_node *n, const char *abortstr)
|
||||
* See also: list_del()
|
||||
*
|
||||
* Example:
|
||||
* list_del_from(&parent->children, &child->list);
|
||||
* parent->num_children--;
|
||||
* list_del_from(&parent->children, &child->list);
|
||||
* parent->num_children--;
|
||||
*/
|
||||
static inline void list_del_from(struct list_head *h, struct list_node *n)
|
||||
{
|
||||
#ifdef CCAN_LIST_DEBUG
|
||||
{
|
||||
/* Thorough check: make sure it was in list! */
|
||||
struct list_node *i;
|
||||
for (i = h->n.next; i != n; i = i->next)
|
||||
assert(i != &h->n);
|
||||
}
|
||||
{
|
||||
/* Thorough check: make sure it was in list! */
|
||||
struct list_node *i;
|
||||
for (i = h->n.next; i != n; i = i->next)
|
||||
assert(i != &h->n);
|
||||
}
|
||||
#endif /* CCAN_LIST_DEBUG */
|
||||
|
||||
/* Quick test that catches a surprising number of bugs. */
|
||||
assert(!list_empty(h));
|
||||
list_del(n);
|
||||
/* Quick test that catches a surprising number of bugs. */
|
||||
assert(!list_empty(h));
|
||||
list_del(n);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,27 +392,27 @@ static inline void list_del_from(struct list_head *h, struct list_node *n)
|
||||
* another list, but not deleted/swapped again.
|
||||
*
|
||||
* See also:
|
||||
* list_del()
|
||||
* list_del()
|
||||
*
|
||||
* Example:
|
||||
* struct child x1, x2;
|
||||
* LIST_HEAD(xh);
|
||||
* struct child x1, x2;
|
||||
* LIST_HEAD(xh);
|
||||
*
|
||||
* list_add(&xh, &x1.list);
|
||||
* list_swap(&x1.list, &x2.list);
|
||||
* 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)
|
||||
struct list_node *n,
|
||||
const char* abortstr)
|
||||
{
|
||||
(void)list_debug_node(o, abortstr);
|
||||
*n = *o;
|
||||
n->next->prev = n;
|
||||
n->prev->next = n;
|
||||
(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;
|
||||
/* Catch use-after-del. */
|
||||
o->next = o->prev = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -423,11 +423,11 @@ static inline void list_swap_(struct list_node *o,
|
||||
* @member: the list_node member of the type
|
||||
*
|
||||
* Example:
|
||||
* // First list entry is children.next; convert back to child.
|
||||
* child = list_entry(parent->children.n.next, struct child, list);
|
||||
* // First list entry is children.next; convert back to child.
|
||||
* child = list_entry(parent->children.n.next, struct child, list);
|
||||
*
|
||||
* See Also:
|
||||
* list_top(), list_for_each()
|
||||
* list_top(), list_for_each()
|
||||
*/
|
||||
#define list_entry(n, type, member) container_of(n, type, member)
|
||||
|
||||
@@ -440,19 +440,19 @@ static inline void list_swap_(struct list_node *o,
|
||||
* If the list is empty, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* struct child *first;
|
||||
* first = list_top(&parent->children, struct child, list);
|
||||
* if (!first)
|
||||
* printf("Empty list!\n");
|
||||
* struct child *first;
|
||||
* first = list_top(&parent->children, struct child, list);
|
||||
* if (!first)
|
||||
* printf("Empty list!\n");
|
||||
*/
|
||||
#define list_top(h, type, member) \
|
||||
((type *)list_top_((h), list_off_(type, member)))
|
||||
#define list_top(h, type, member) \
|
||||
((type *)list_top_((h), list_off_(type, member)))
|
||||
|
||||
static inline const void *list_top_(const struct list_head *h, size_t off)
|
||||
{
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
return (const char *)h->n.next - off;
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
return (const char *)h->n.next - off;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,23 +464,23 @@ static inline const void *list_top_(const struct list_head *h, size_t off)
|
||||
* 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");
|
||||
* 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)))
|
||||
#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;
|
||||
struct list_node *n;
|
||||
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
n = h->n.next;
|
||||
list_del(n);
|
||||
return (const char *)n - off;
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
n = h->n.next;
|
||||
list_del(n);
|
||||
return (const char *)n - off;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,19 +492,19 @@ static inline const void *list_pop_(const struct list_head *h, size_t off)
|
||||
* If the list is empty, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* struct child *last;
|
||||
* last = list_tail(&parent->children, struct child, list);
|
||||
* if (!last)
|
||||
* printf("Empty list!\n");
|
||||
* struct child *last;
|
||||
* last = list_tail(&parent->children, struct child, list);
|
||||
* if (!last)
|
||||
* printf("Empty list!\n");
|
||||
*/
|
||||
#define list_tail(h, type, member) \
|
||||
((type *)list_tail_((h), list_off_(type, member)))
|
||||
((type *)list_tail_((h), list_off_(type, member)))
|
||||
|
||||
static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
{
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
return (const char *)h->n.prev - off;
|
||||
if (list_empty(h))
|
||||
return NULL;
|
||||
return (const char *)h->n.prev - off;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -517,11 +517,11 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* a for loop, so you can break and continue as normal.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each(&parent->children, child, list)
|
||||
* printf("Name: %s\n", child->name);
|
||||
* list_for_each(&parent->children, child, list)
|
||||
* printf("Name: %s\n", child->name);
|
||||
*/
|
||||
#define list_for_each(h, i, member) \
|
||||
list_for_each_off(h, i, list_off_var_(i, member))
|
||||
#define list_for_each(h, i, member) \
|
||||
list_for_each_off(h, i, list_off_var_(i, member))
|
||||
|
||||
/**
|
||||
* list_for_each_rev - iterate through a list backwards.
|
||||
@@ -533,11 +533,11 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* a for loop, so you can break and continue as normal.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each_rev(&parent->children, child, list)
|
||||
* printf("Name: %s\n", child->name);
|
||||
* list_for_each_rev(&parent->children, child, list)
|
||||
* 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))
|
||||
#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,
|
||||
@@ -553,13 +553,13 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* from the list.
|
||||
*
|
||||
* Example:
|
||||
* struct child *next;
|
||||
* list_for_each_rev_safe(&parent->children, child, next, list) {
|
||||
* printf("Name: %s\n", child->name);
|
||||
* }
|
||||
* 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))
|
||||
#define list_for_each_rev_safe(h, i, nxt, member) \
|
||||
list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate through a list, maybe during deletion
|
||||
@@ -573,13 +573,13 @@ 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:
|
||||
* list_for_each_safe(&parent->children, child, next, list) {
|
||||
* list_del(&child->list);
|
||||
* parent->num_children--;
|
||||
* }
|
||||
* list_for_each_safe(&parent->children, child, next, list) {
|
||||
* list_del(&child->list);
|
||||
* parent->num_children--;
|
||||
* }
|
||||
*/
|
||||
#define list_for_each_safe(h, i, nxt, member) \
|
||||
list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
|
||||
#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
|
||||
@@ -590,16 +590,16 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* 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");
|
||||
* 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)))
|
||||
#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
|
||||
@@ -610,15 +610,15 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* 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");
|
||||
* 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)))
|
||||
#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.
|
||||
@@ -629,30 +629,30 @@ static inline const void *list_tail_(const struct list_head *h, size_t off)
|
||||
* @to. After this @from will be empty.
|
||||
*
|
||||
* Example:
|
||||
* struct list_head adopter;
|
||||
* struct list_head adopter;
|
||||
*
|
||||
* list_append_list(&adopter, &parent->children);
|
||||
* assert(list_empty(&parent->children));
|
||||
* parent->num_children = 0;
|
||||
* 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__))
|
||||
#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_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;
|
||||
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;
|
||||
/* 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);
|
||||
/* Now remove head. */
|
||||
list_del(&from->n);
|
||||
list_head_init(from);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -664,46 +664,46 @@ static inline void list_append_list_(struct list_head *to,
|
||||
* of @to. After this @from will be empty.
|
||||
*
|
||||
* Example:
|
||||
* list_prepend_list(&adopter, &parent->children);
|
||||
* assert(list_empty(&parent->children));
|
||||
* parent->num_children = 0;
|
||||
* 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_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;
|
||||
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;
|
||||
/* 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);
|
||||
/* 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_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)))
|
||||
#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.
|
||||
@@ -730,12 +730,12 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* @i.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each_off(&parent->children, child,
|
||||
* offsetof(struct child, list))
|
||||
* printf("Name: %s\n", child->name);
|
||||
* list_for_each_off(&parent->children, child,
|
||||
* offsetof(struct child, list))
|
||||
* 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_off_dir_((h),(i),(off),next)
|
||||
|
||||
/**
|
||||
* list_for_each_rev_off - iterate through a list of memory regions backwards
|
||||
@@ -746,7 +746,7 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* 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)
|
||||
list_for_each_off_dir_((h),(i),(off),prev)
|
||||
|
||||
/**
|
||||
* list_for_each_safe_off - iterate through a list of memory regions, maybe
|
||||
@@ -760,12 +760,12 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* descriptions.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each_safe_off(&parent->children, child,
|
||||
* next, offsetof(struct child, list))
|
||||
* printf("Name: %s\n", child->name);
|
||||
* list_for_each_safe_off(&parent->children, child,
|
||||
* next, offsetof(struct child, list))
|
||||
* 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)
|
||||
list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
|
||||
|
||||
/**
|
||||
* list_for_each_rev_safe_off - iterate backwards through a list of
|
||||
@@ -779,50 +779,50 @@ static inline void list_prepend_list_(struct list_head *to,
|
||||
* descriptions.
|
||||
*
|
||||
* Example:
|
||||
* list_for_each_rev_safe_off(&parent->children, child,
|
||||
* next, offsetof(struct child, list))
|
||||
* printf("Name: %s\n", child->name);
|
||||
* 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)
|
||||
list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
|
||||
|
||||
/* Other -off variants. */
|
||||
#define list_entry_off(n, type, off) \
|
||||
((type *)list_node_from_off_((n), (off)))
|
||||
#define list_entry_off(n, type, off) \
|
||||
((type *)list_node_from_off_((n), (off)))
|
||||
|
||||
#define list_head_off(h, type, off) \
|
||||
((type *)list_head_off((h), (off)))
|
||||
#define list_head_off(h, type, off) \
|
||||
((type *)list_head_off((h), (off)))
|
||||
|
||||
#define list_tail_off(h, type, off) \
|
||||
((type *)list_tail_((h), (off)))
|
||||
#define list_tail_off(h, type, off) \
|
||||
((type *)list_tail_((h), (off)))
|
||||
|
||||
#define list_add_off(h, n, off) \
|
||||
list_add((h), list_node_from_off_((n), (off)))
|
||||
list_add((h), list_node_from_off_((n), (off)))
|
||||
|
||||
#define list_del_off(n, off) \
|
||||
list_del(list_node_from_off_((n), (off)))
|
||||
list_del(list_node_from_off_((n), (off)))
|
||||
|
||||
#define list_del_from_off(h, n, off) \
|
||||
list_del_from(h, list_node_from_off_((n), (off)))
|
||||
#define list_del_from_off(h, n, off) \
|
||||
list_del_from(h, list_node_from_off_((n), (off)))
|
||||
|
||||
/* Offset helper functions so we only single-evaluate. */
|
||||
static inline void *list_node_to_off_(struct list_node *node, size_t off)
|
||||
{
|
||||
return (void *)((char *)node - off);
|
||||
return (void *)((char *)node - off);
|
||||
}
|
||||
static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
|
||||
{
|
||||
return (struct list_node *)((char *)ptr + off);
|
||||
return (struct list_node *)((char *)ptr + off);
|
||||
}
|
||||
|
||||
/* Get the offset of the member, but make sure it's a list_node. */
|
||||
#define list_off_(type, member) \
|
||||
(container_off(type, member) + \
|
||||
check_type(((type *)0)->member, struct list_node))
|
||||
#define list_off_(type, member) \
|
||||
(container_off(type, member) + \
|
||||
check_type(((type *)0)->member, struct list_node))
|
||||
|
||||
#define list_off_var_(var, member) \
|
||||
(container_off_var(var, member) + \
|
||||
check_type(var->member, struct list_node))
|
||||
#define list_off_var_(var, member) \
|
||||
(container_off_var(var, member) + \
|
||||
check_type(var->member, struct list_node))
|
||||
|
||||
#if HAVE_TYPEOF
|
||||
#define list_typeof(var) typeof(var)
|
||||
@@ -832,11 +832,11 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
|
||||
|
||||
/* 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)
|
||||
const struct list_node *n,
|
||||
size_t off)
|
||||
{
|
||||
if (n == &h->n)
|
||||
return NULL;
|
||||
return (char *)n - off;
|
||||
if (n == &h->n)
|
||||
return NULL;
|
||||
return (char *)n - off;
|
||||
}
|
||||
#endif /* CCAN_LIST_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/mem/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/mem/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
30
nostrdb/ccan/ccan/mem/_info
Normal file
30
nostrdb/ccan/ccan/mem/_info
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* mem - Provide mem*() functions if missing from C library
|
||||
*
|
||||
* This code implements some string.h mem*() functions if they're not
|
||||
* already available in the C library. Functions included are:
|
||||
* memmem()
|
||||
*
|
||||
* License: CC0
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/compiler");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "testdepends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -4,125 +4,125 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "mem.h"
|
||||
#include <ccan/mem/mem.h>
|
||||
|
||||
#if !HAVE_MEMMEM
|
||||
void *memmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen)
|
||||
const void *needle, size_t needlelen)
|
||||
{
|
||||
const char *p;
|
||||
const char *p;
|
||||
|
||||
if (needlelen > haystacklen)
|
||||
return NULL;
|
||||
if (needlelen > haystacklen)
|
||||
return NULL;
|
||||
|
||||
p = haystack;
|
||||
p = haystack;
|
||||
|
||||
for (p = haystack;
|
||||
(p + needlelen) <= ((const char *)haystack + haystacklen);
|
||||
p++)
|
||||
if (memcmp(p, needle, needlelen) == 0)
|
||||
return (void *)p;
|
||||
for (p = haystack;
|
||||
(p + needlelen) <= ((const char *)haystack + haystacklen);
|
||||
p++)
|
||||
if (memcmp(p, needle, needlelen) == 0)
|
||||
return (void *)p;
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_MEMRCHR
|
||||
void *memrchr(const void *s, int c, size_t n)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)s;
|
||||
unsigned char *p = (unsigned char *)s;
|
||||
|
||||
while (n) {
|
||||
if (p[n-1] == c)
|
||||
return p + n - 1;
|
||||
n--;
|
||||
}
|
||||
while (n) {
|
||||
if (p[n-1] == c)
|
||||
return p + n - 1;
|
||||
n--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *mempbrkm(const void *data_, size_t len, const void *accept_, size_t accept_len)
|
||||
{
|
||||
const char *data = data_, *accept = accept_;
|
||||
size_t i, j;
|
||||
const char *data = data_, *accept = accept_;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
for (j = 0; j < accept_len; j++)
|
||||
if (accept[j] == data[i])
|
||||
return (void *)&data[i];
|
||||
return NULL;
|
||||
for (i = 0; i < len; i++)
|
||||
for (j = 0; j < accept_len; j++)
|
||||
if (accept[j] == data[i])
|
||||
return (void *)&data[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *memcchr(void const *data, int c, size_t data_len)
|
||||
{
|
||||
char const *p = data;
|
||||
size_t i;
|
||||
char const *p = data;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < data_len; i++)
|
||||
if (p[i] != c)
|
||||
return (void *)&p[i];
|
||||
for (i = 0; i < data_len; i++)
|
||||
if (p[i] != c)
|
||||
return (void *)&p[i];
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MEMSWAP_TMP_SIZE 256
|
||||
#define MEMSWAP_TMP_SIZE 256
|
||||
|
||||
void memswap(void *a, void *b, size_t n)
|
||||
{
|
||||
char *ap = a;
|
||||
char *bp = b;
|
||||
char tmp[MEMSWAP_TMP_SIZE];
|
||||
char *ap = a;
|
||||
char *bp = b;
|
||||
char tmp[MEMSWAP_TMP_SIZE];
|
||||
|
||||
assert(!memoverlaps(a, n, b, n));
|
||||
assert(!memoverlaps(a, n, b, n));
|
||||
|
||||
while (n) {
|
||||
size_t m = n > MEMSWAP_TMP_SIZE ? MEMSWAP_TMP_SIZE : n;
|
||||
while (n) {
|
||||
size_t m = n > MEMSWAP_TMP_SIZE ? MEMSWAP_TMP_SIZE : n;
|
||||
|
||||
memcpy(tmp, bp, m);
|
||||
memcpy(bp, ap, m);
|
||||
memcpy(ap, tmp, m);
|
||||
memcpy(tmp, bp, m);
|
||||
memcpy(bp, ap, m);
|
||||
memcpy(ap, tmp, m);
|
||||
|
||||
ap += m;
|
||||
bp += m;
|
||||
n -= m;
|
||||
}
|
||||
ap += m;
|
||||
bp += m;
|
||||
n -= m;
|
||||
}
|
||||
}
|
||||
|
||||
bool memeqzero(const void *data, size_t length)
|
||||
{
|
||||
const unsigned char *p = data;
|
||||
size_t len;
|
||||
const unsigned char *p = data;
|
||||
size_t len;
|
||||
|
||||
/* Check first 16 bytes manually */
|
||||
for (len = 0; len < 16; len++) {
|
||||
if (!length)
|
||||
return true;
|
||||
if (*p)
|
||||
return false;
|
||||
p++;
|
||||
length--;
|
||||
}
|
||||
/* Check first 16 bytes manually */
|
||||
for (len = 0; len < 16; len++) {
|
||||
if (!length)
|
||||
return true;
|
||||
if (*p)
|
||||
return false;
|
||||
p++;
|
||||
length--;
|
||||
}
|
||||
|
||||
/* Now we know that's zero, memcmp with self. */
|
||||
return memcmp(data, p, length) == 0;
|
||||
/* Now we know that's zero, memcmp with self. */
|
||||
return memcmp(data, p, length) == 0;
|
||||
}
|
||||
|
||||
void memtaint(void *data, size_t len)
|
||||
{
|
||||
/* Using 16 bytes is a bit quicker than 4 */
|
||||
const unsigned tainter[]
|
||||
= { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
|
||||
char *p = data;
|
||||
/* Using 16 bytes is a bit quicker than 4 */
|
||||
const unsigned tainter[]
|
||||
= { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef };
|
||||
char *p = data;
|
||||
|
||||
while (len >= sizeof(tainter)) {
|
||||
memcpy(p, tainter, sizeof(tainter));
|
||||
p += sizeof(tainter);
|
||||
len -= sizeof(tainter);
|
||||
}
|
||||
memcpy(p, tainter, len);
|
||||
while (len >= sizeof(tainter)) {
|
||||
memcpy(p, tainter, sizeof(tainter));
|
||||
p += sizeof(tainter);
|
||||
len -= sizeof(tainter);
|
||||
}
|
||||
memcpy(p, tainter, len);
|
||||
|
||||
#if HAVE_VALGRIND_MEMCHECK_H
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(data, len);
|
||||
VALGRIND_MAKE_MEM_UNDEFINED(data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#ifndef CCAN_MEM_H
|
||||
#define CCAN_MEM_H
|
||||
|
||||
#include "../config.h"
|
||||
#include "ccan/compiler/compiler.h"
|
||||
#include "config.h"
|
||||
#include <ccan/compiler/compiler.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
@@ -11,7 +11,7 @@
|
||||
#if !HAVE_MEMMEM
|
||||
PURE_FUNCTION
|
||||
void *memmem(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen);
|
||||
const void *needle, size_t needlelen);
|
||||
#endif
|
||||
|
||||
#if !HAVE_MEMRCHR
|
||||
@@ -30,14 +30,14 @@ void *memrchr(const void *s, int c, size_t n);
|
||||
* @accept, or NULL if no such byte is found.
|
||||
*
|
||||
* Example:
|
||||
* char otherbytes[] = "Hello \0world";
|
||||
* size_t otherbytes_len = sizeof(otherbytes) - 1;
|
||||
* char *r = mempbrkm(otherbytes, otherbytes_len, "\0b", 2);
|
||||
* if (r) {
|
||||
* printf("Found %c\n", *r);
|
||||
* } else {
|
||||
* printf("Nada\n");
|
||||
* }
|
||||
* char otherbytes[] = "Hello \0world";
|
||||
* size_t otherbytes_len = sizeof(otherbytes) - 1;
|
||||
* char *r = mempbrkm(otherbytes, otherbytes_len, "\0b", 2);
|
||||
* if (r) {
|
||||
* printf("Found %c\n", *r);
|
||||
* } else {
|
||||
* printf("Nada\n");
|
||||
* }
|
||||
*
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
@@ -54,21 +54,21 @@ void *mempbrkm(const void *data, size_t len, const void *accept, size_t accept_l
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* r = mempbrk(otherbytes, otherbytes_len, "abcde");
|
||||
* if (r) {
|
||||
* printf("Found %c\n", *r);
|
||||
* } else {
|
||||
* printf("Nada\n");
|
||||
* }
|
||||
* r = mempbrk(otherbytes, otherbytes_len, "abcde");
|
||||
* if (r) {
|
||||
* printf("Found %c\n", *r);
|
||||
* } else {
|
||||
* printf("Nada\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline char *mempbrk(const void *data, size_t len, const char *accept)
|
||||
{
|
||||
return mempbrkm(data, len, accept, strlen(accept));
|
||||
return mempbrkm(data, len, accept, strlen(accept));
|
||||
}
|
||||
|
||||
/**
|
||||
* memcchr - scan memory until a character does _not_ match
|
||||
* memcchr - scan memory until a character does _not_ match @c
|
||||
* @data: pointer to memory to scan
|
||||
* @data_len: length of data
|
||||
* @c: character to scan for
|
||||
@@ -79,12 +79,12 @@ static inline char *mempbrk(const void *data, size_t len, const char *accept)
|
||||
* @data is @c, returns NULL.
|
||||
*
|
||||
* Example:
|
||||
* char somebytes[] = "HI By\0e";
|
||||
* size_t bytes_len = sizeof(somebytes) - 1;
|
||||
* r = memcchr(somebytes, ' ', bytes_len);
|
||||
* if (r) {
|
||||
* printf("Found %c after trimming spaces\n", *r);
|
||||
* }
|
||||
* char somebytes[] = "HI By\0e";
|
||||
* size_t bytes_len = sizeof(somebytes) - 1;
|
||||
* r = memcchr(somebytes, ' ', bytes_len);
|
||||
* if (r) {
|
||||
* printf("Found %c after trimming spaces\n", *r);
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
void *memcchr(void const *data, int c, size_t data_len);
|
||||
@@ -97,14 +97,14 @@ void *memcchr(void const *data, int c, size_t data_len);
|
||||
* @bl: bytes in second array
|
||||
*
|
||||
* Example:
|
||||
* if (memeq(somebytes, bytes_len, otherbytes, otherbytes_len)) {
|
||||
* printf("memory blocks are the same!\n");
|
||||
* }
|
||||
* if (memeq(somebytes, bytes_len, otherbytes, otherbytes_len)) {
|
||||
* printf("memory blocks are the same!\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline bool memeq(const void *a, size_t al, const void *b, size_t bl)
|
||||
{
|
||||
return al == bl && !memcmp(a, b, bl);
|
||||
return al == bl && (al == 0 || !memcmp(a, b, bl));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,17 +117,17 @@ static inline bool memeq(const void *a, size_t al, const void *b, size_t bl)
|
||||
* Returns true if @data starts with @prefix, otherwise return false.
|
||||
*
|
||||
* Example:
|
||||
* if (memstarts(somebytes, bytes_len, otherbytes, otherbytes_len)) {
|
||||
* printf("somebytes starts with otherbytes!\n");
|
||||
* }
|
||||
* if (memstarts(somebytes, bytes_len, otherbytes, otherbytes_len)) {
|
||||
* printf("somebytes starts with otherbytes!\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline bool memstarts(void const *data, size_t data_len,
|
||||
void const *prefix, size_t prefix_len)
|
||||
void const *prefix, size_t prefix_len)
|
||||
{
|
||||
if (prefix_len > data_len)
|
||||
return false;
|
||||
return memeq(data, prefix_len, prefix, prefix_len);
|
||||
if (prefix_len > data_len)
|
||||
return false;
|
||||
return memeq(data, prefix_len, prefix, prefix_len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,14 +139,14 @@ static inline bool memstarts(void const *data, size_t data_len,
|
||||
* The '\0' byte is ignored when checking if @bytes == @string.
|
||||
*
|
||||
* Example:
|
||||
* if (memeqstr(somebytes, bytes_len, "foo")) {
|
||||
* printf("somebytes == 'foo'!\n");
|
||||
* }
|
||||
* if (memeqstr(somebytes, bytes_len, "foo")) {
|
||||
* printf("somebytes == 'foo'!\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline bool memeqstr(const void *data, size_t length, const char *string)
|
||||
{
|
||||
return memeq(data, length, string, strlen(string));
|
||||
return memeq(data, length, string, strlen(string));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,9 +155,9 @@ static inline bool memeqstr(const void *data, size_t length, const char *string)
|
||||
* @length: length of @data in bytes
|
||||
*
|
||||
* Example:
|
||||
* if (memeqzero(somebytes, bytes_len)) {
|
||||
* printf("somebytes == 0!\n");
|
||||
* }
|
||||
* if (memeqzero(somebytes, bytes_len)) {
|
||||
* printf("somebytes == 0!\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
bool memeqzero(const void *data, size_t length);
|
||||
@@ -169,14 +169,14 @@ bool memeqzero(const void *data, size_t length);
|
||||
* @s: string prefix
|
||||
*
|
||||
* Example:
|
||||
* if (memstarts_str(somebytes, bytes_len, "It")) {
|
||||
* printf("somebytes starts with 'It'\n");
|
||||
* }
|
||||
* if (memstarts_str(somebytes, bytes_len, "It")) {
|
||||
* printf("somebytes starts with 'It'\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline bool memstarts_str(const void *a, size_t al, const char *s)
|
||||
{
|
||||
return memstarts(a, al, s, strlen(s));
|
||||
return memstarts(a, al, s, strlen(s));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,8 +192,8 @@ static inline bool memstarts_str(const void *a, size_t al, const char *s)
|
||||
PURE_FUNCTION
|
||||
static inline bool memends(const void *s, size_t s_len, const void *suffix, size_t suffix_len)
|
||||
{
|
||||
return (s_len >= suffix_len) && (memcmp((const char *)s + s_len - suffix_len,
|
||||
suffix, suffix_len) == 0);
|
||||
return (s_len >= suffix_len) && (memcmp((const char *)s + s_len - suffix_len,
|
||||
suffix, suffix_len) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,14 +203,14 @@ static inline bool memends(const void *s, size_t s_len, const void *suffix, size
|
||||
* @s: string suffix
|
||||
*
|
||||
* Example:
|
||||
* if (memends_str(somebytes, bytes_len, "It")) {
|
||||
* printf("somebytes ends with with 'It'\n");
|
||||
* }
|
||||
* if (memends_str(somebytes, bytes_len, "It")) {
|
||||
* printf("somebytes ends with with 'It'\n");
|
||||
* }
|
||||
*/
|
||||
PURE_FUNCTION
|
||||
static inline bool memends_str(const void *a, size_t al, const char *s)
|
||||
{
|
||||
return memends(a, al, s, strlen(s));
|
||||
return memends(a, al, s, strlen(s));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,12 +222,12 @@ static inline bool memends_str(const void *a, size_t al, const char *s)
|
||||
*/
|
||||
CONST_FUNCTION
|
||||
static inline bool memoverlaps(const void *a_, size_t al,
|
||||
const void *b_, size_t bl)
|
||||
const void *b_, size_t bl)
|
||||
{
|
||||
const char *a = a_;
|
||||
const char *b = b_;
|
||||
const char *a = a_;
|
||||
const char *b = b_;
|
||||
|
||||
return (a < (b + bl)) && (b < (a + al));
|
||||
return (a < (b + bl)) && (b < (a + al));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -244,14 +244,14 @@ void memswap(void *a, void *b, size_t n);
|
||||
#include <valgrind/memcheck.h>
|
||||
static inline void *memcheck_(const void *data, size_t len)
|
||||
{
|
||||
VALGRIND_CHECK_MEM_IS_DEFINED(data, len);
|
||||
return (void *)data;
|
||||
VALGRIND_CHECK_MEM_IS_DEFINED(data, len);
|
||||
return (void *)data;
|
||||
}
|
||||
#else
|
||||
static inline void *memcheck_(const void *data, size_t len)
|
||||
{
|
||||
(void)len;
|
||||
return (void *)data;
|
||||
(void)len;
|
||||
return (void *)data;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -267,10 +267,10 @@ static inline void *memcheck_(const void *data, size_t len)
|
||||
* written out.
|
||||
*
|
||||
* Example:
|
||||
* // Search for space, but make sure it's all initialized.
|
||||
* if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
|
||||
* printf("space was found!\n");
|
||||
* }
|
||||
* // Search for space, but make sure it's all initialized.
|
||||
* if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
|
||||
* printf("space was found!\n");
|
||||
* }
|
||||
*/
|
||||
#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len)))
|
||||
#else
|
||||
@@ -288,8 +288,8 @@ static inline void *memcheck_(const void *data, size_t len)
|
||||
* or written out (or passed to memcheck!) in future.
|
||||
*
|
||||
* Example:
|
||||
* // We'll reuse this buffer later, but be sure we don't access it.
|
||||
* memtaint(somebytes, bytes_len);
|
||||
* // We'll reuse this buffer later, but be sure we don't access it.
|
||||
* memtaint(somebytes, bytes_len);
|
||||
*/
|
||||
void memtaint(void *data, size_t len);
|
||||
#endif /* CCAN_MEM_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/short_types/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/short_types/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
87
nostrdb/ccan/ccan/short_types/_info
Normal file
87
nostrdb/ccan/ccan/short_types/_info
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* short_types - shorter names for standard integer types
|
||||
*
|
||||
* "C is a Spartan language, and so should your naming be."
|
||||
* -- Linus Torvalds
|
||||
*
|
||||
* The short_types header provides for convenient abbreviations for the
|
||||
* posixly-damned uint32_t types. If ccan/endian/endian.h is included,
|
||||
* it also provides be32/le32 for explicitly annotating types of specific
|
||||
* endian.
|
||||
*
|
||||
* Include this header, if only to stop people using these identifiers
|
||||
* for other things!
|
||||
*
|
||||
* Example:
|
||||
* #include <stdint.h>
|
||||
* #include <string.h>
|
||||
* #include <stdio.h>
|
||||
* #include <ccan/short_types/short_types.h>
|
||||
*
|
||||
* // Print nonsensical numerical comparison of POSIX vs. short_types.
|
||||
* #define stringify_1(x) #x
|
||||
* #define stringify(x) stringify_1(x)
|
||||
*
|
||||
* static void evaluate(size_t size, const char *posix, const char *sht,
|
||||
* unsigned int *posix_total, unsigned int *sht_total,
|
||||
* unsigned int *size_total)
|
||||
* {
|
||||
* printf("\t%ssigned %s: POSIX %zu%%, short %zu%%\n",
|
||||
* sht[0] == 'u' ? "un" : "",
|
||||
* sht+1,
|
||||
* strlen(posix)*100 / size,
|
||||
* strlen(sht)*100 / size);
|
||||
* *posix_total += strlen(posix);
|
||||
* *sht_total += strlen(sht);
|
||||
* *size_total += size;
|
||||
* }
|
||||
*
|
||||
* #define EVALUATE(psx, short, pt, st, t) \
|
||||
* evaluate(sizeof(psx), stringify(psx), stringify(sht), pt, st, t)
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* unsigned int posix_total = 0, sht_total = 0, size_total = 0;
|
||||
*
|
||||
* printf("Comparing size of type vs size of name:\n");
|
||||
*
|
||||
* EVALUATE(uint8_t, u8, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(int8_t, s8, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(uint16_t, u16, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(int16_t, s16, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(uint32_t, u32, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(int32_t, s32, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(uint64_t, u64, &posix_total, &sht_total, &size_total);
|
||||
* EVALUATE(int64_t, s64, &posix_total, &sht_total, &size_total);
|
||||
*
|
||||
* printf("Conclusion:\n"
|
||||
* "\tPOSIX is %u%% LESS efficient than binary.\n"
|
||||
* "\tshort_types.h is %u%% MORE efficient than binary.\n",
|
||||
* (posix_total - size_total) * 100 / size_total,
|
||||
* (size_total - sht_total) * 100 / size_total);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "testdepends") == 0) {
|
||||
printf("ccan/endian\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
1
nostrdb/ccan/ccan/str/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/str/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
52
nostrdb/ccan/ccan/str/_info
Normal file
52
nostrdb/ccan/ccan/str/_info
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* str - string helper routines
|
||||
*
|
||||
* This is a grab bag of functions for string operations, designed to enhance
|
||||
* the standard string.h.
|
||||
*
|
||||
* Note that if you define CCAN_STR_DEBUG, you will get extra compile
|
||||
* checks on common misuses of the following functions (they will now
|
||||
* be out-of-line, so there is a runtime penalty!).
|
||||
*
|
||||
* strstr, strchr, strrchr:
|
||||
* Return const char * if first argument is const (gcc only).
|
||||
*
|
||||
* isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph,
|
||||
* islower, isprint, ispunct, isspace, isupper, isxdigit:
|
||||
* Static and runtime check that input is EOF or an *unsigned*
|
||||
* char, as per C standard (really!).
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <ccan/str/str.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* if (argc > 1 && streq(argv[1], "--verbose"))
|
||||
* printf("verbose set\n");
|
||||
* if (argc > 1 && strstarts(argv[1], "--"))
|
||||
* printf("Some option set\n");
|
||||
* if (argc > 1 && strends(argv[1], "cow-powers"))
|
||||
* printf("Magic option set\n");
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/build_assert\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
108
nostrdb/ccan/ccan/str/debug.c
Normal file
108
nostrdb/ccan/ccan/str/debug.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#include "config.h"
|
||||
#include <ccan/str/str_debug.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CCAN_STR_DEBUG
|
||||
/* Because we mug the real ones with macros, we need our own wrappers. */
|
||||
int str_isalnum(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isalnum(i);
|
||||
}
|
||||
|
||||
int str_isalpha(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isalpha(i);
|
||||
}
|
||||
|
||||
int str_isascii(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isascii(i);
|
||||
}
|
||||
|
||||
#if HAVE_ISBLANK
|
||||
int str_isblank(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isblank(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
int str_iscntrl(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return iscntrl(i);
|
||||
}
|
||||
|
||||
int str_isdigit(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isdigit(i);
|
||||
}
|
||||
|
||||
int str_isgraph(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isgraph(i);
|
||||
}
|
||||
|
||||
int str_islower(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return islower(i);
|
||||
}
|
||||
|
||||
int str_isprint(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isprint(i);
|
||||
}
|
||||
|
||||
int str_ispunct(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return ispunct(i);
|
||||
}
|
||||
|
||||
int str_isspace(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isspace(i);
|
||||
}
|
||||
|
||||
int str_isupper(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isupper(i);
|
||||
}
|
||||
|
||||
int str_isxdigit(int i)
|
||||
{
|
||||
assert(i >= -1 && i < 256);
|
||||
return isxdigit(i);
|
||||
}
|
||||
|
||||
#undef strstr
|
||||
#undef strchr
|
||||
#undef strrchr
|
||||
|
||||
char *str_strstr(const char *haystack, const char *needle)
|
||||
{
|
||||
return strstr(haystack, needle);
|
||||
}
|
||||
|
||||
char *str_strchr(const char *haystack, int c)
|
||||
{
|
||||
return strchr(haystack, c);
|
||||
}
|
||||
|
||||
char *str_strrchr(const char *haystack, int c)
|
||||
{
|
||||
return strrchr(haystack, c);
|
||||
}
|
||||
#endif
|
||||
13
nostrdb/ccan/ccan/str/str.c
Normal file
13
nostrdb/ccan/ccan/str/str.c
Normal file
@@ -0,0 +1,13 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
size_t strcount(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t i = 0, nlen = strlen(needle);
|
||||
|
||||
while ((haystack = strstr(haystack, needle)) != NULL) {
|
||||
i++;
|
||||
haystack += nlen;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_STR_H
|
||||
#define CCAN_STR_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
@@ -15,8 +15,8 @@
|
||||
* This macro is arguably more readable than "!strcmp(a, b)".
|
||||
*
|
||||
* Example:
|
||||
* if (streq(somestring, ""))
|
||||
* printf("String is empty!\n");
|
||||
* if (streq(somestring, ""))
|
||||
* printf("String is empty!\n");
|
||||
*/
|
||||
#define streq(a,b) (strcmp((a),(b)) == 0)
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
* @prefix: prefix to look for at start of str
|
||||
*
|
||||
* Example:
|
||||
* if (strstarts(somestring, "foo"))
|
||||
* printf("String %s begins with 'foo'!\n", somestring);
|
||||
* if (strstarts(somestring, "foo"))
|
||||
* printf("String %s begins with 'foo'!\n", somestring);
|
||||
*/
|
||||
#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
|
||||
|
||||
@@ -37,15 +37,15 @@
|
||||
* @postfix: postfix to look for at end of str
|
||||
*
|
||||
* Example:
|
||||
* if (strends(somestring, "foo"))
|
||||
* printf("String %s end with 'foo'!\n", somestring);
|
||||
* 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;
|
||||
if (strlen(str) < strlen(postfix))
|
||||
return false;
|
||||
|
||||
return streq(str + strlen(str) - strlen(postfix), postfix);
|
||||
return streq(str + strlen(str) - strlen(postfix), postfix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,12 +53,12 @@ static inline bool strends(const char *str, const char *postfix)
|
||||
* @expr: any C expression
|
||||
*
|
||||
* Example:
|
||||
* #define PRINT_COND_IF_FALSE(cond) \
|
||||
* ((cond) || printf("%s is false!", stringify(cond)))
|
||||
* #define PRINT_COND_IF_FALSE(cond) \
|
||||
* ((cond) || printf("%s is false!", stringify(cond)))
|
||||
*/
|
||||
#define stringify(expr) stringify_1(expr)
|
||||
#define stringify(expr) stringify_1(expr)
|
||||
/* Double-indirection required to stringify expansions */
|
||||
#define stringify_1(expr) #expr
|
||||
#define stringify_1(expr) #expr
|
||||
|
||||
/**
|
||||
* strcount - Count number of (non-overlapping) occurrences of a substring.
|
||||
@@ -83,18 +83,18 @@ size_t strcount(const char *haystack, const char *needle);
|
||||
* values will fit (eg. sprintf(... "%p"). )
|
||||
*
|
||||
* Example:
|
||||
* char str[STR_MAX_CHARS(int)];
|
||||
* char str[STR_MAX_CHARS(int)];
|
||||
*
|
||||
* sprintf(str, "%i", 7);
|
||||
* 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))
|
||||
#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)
|
||||
#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
|
||||
@@ -109,60 +109,60 @@ size_t strcount(const char *haystack, const char *needle);
|
||||
*/
|
||||
static inline bool cisalnum(char c)
|
||||
{
|
||||
return isalnum((unsigned char)c);
|
||||
return isalnum((unsigned char)c);
|
||||
}
|
||||
static inline bool cisalpha(char c)
|
||||
{
|
||||
return isalpha((unsigned char)c);
|
||||
return isalpha((unsigned char)c);
|
||||
}
|
||||
static inline bool cisascii(char c)
|
||||
{
|
||||
return isascii((unsigned char)c);
|
||||
return isascii((unsigned char)c);
|
||||
}
|
||||
#if HAVE_ISBLANK
|
||||
static inline bool cisblank(char c)
|
||||
{
|
||||
return isblank((unsigned char)c);
|
||||
return isblank((unsigned char)c);
|
||||
}
|
||||
#endif
|
||||
static inline bool ciscntrl(char c)
|
||||
{
|
||||
return iscntrl((unsigned char)c);
|
||||
return iscntrl((unsigned char)c);
|
||||
}
|
||||
static inline bool cisdigit(char c)
|
||||
{
|
||||
return isdigit((unsigned char)c);
|
||||
return isdigit((unsigned char)c);
|
||||
}
|
||||
static inline bool cisgraph(char c)
|
||||
{
|
||||
return isgraph((unsigned char)c);
|
||||
return isgraph((unsigned char)c);
|
||||
}
|
||||
static inline bool cislower(char c)
|
||||
{
|
||||
return islower((unsigned char)c);
|
||||
return islower((unsigned char)c);
|
||||
}
|
||||
static inline bool cisprint(char c)
|
||||
{
|
||||
return isprint((unsigned char)c);
|
||||
return isprint((unsigned char)c);
|
||||
}
|
||||
static inline bool cispunct(char c)
|
||||
{
|
||||
return ispunct((unsigned char)c);
|
||||
return ispunct((unsigned char)c);
|
||||
}
|
||||
static inline bool cisspace(char c)
|
||||
{
|
||||
return isspace((unsigned char)c);
|
||||
return isspace((unsigned char)c);
|
||||
}
|
||||
static inline bool cisupper(char c)
|
||||
{
|
||||
return isupper((unsigned char)c);
|
||||
return isupper((unsigned char)c);
|
||||
}
|
||||
static inline bool cisxdigit(char c)
|
||||
{
|
||||
return isxdigit((unsigned char)c);
|
||||
return isxdigit((unsigned char)c);
|
||||
}
|
||||
|
||||
#include "str_debug.h"
|
||||
#include <ccan/str/str_debug.h>
|
||||
|
||||
/* These checks force things out of line, hence they are under DEBUG. */
|
||||
#ifdef CCAN_STR_DEBUG
|
||||
@@ -185,10 +185,10 @@ static inline bool cisxdigit(char c)
|
||||
|
||||
/* 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))
|
||||
#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
|
||||
@@ -216,12 +216,12 @@ static inline bool cisxdigit(char c)
|
||||
#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)))
|
||||
#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 */
|
||||
|
||||
|
||||
30
nostrdb/ccan/ccan/str/str_debug.h
Normal file
30
nostrdb/ccan/ccan/str/str_debug.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/* 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 */
|
||||
1
nostrdb/ccan/ccan/structeq/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/structeq/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
||||
57
nostrdb/ccan/ccan/structeq/_info
Normal file
57
nostrdb/ccan/ccan/structeq/_info
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* structeq - bitwise comparison of structs.
|
||||
*
|
||||
* This is a replacement for memcmp, which checks the argument types are the
|
||||
* same, and takes into account padding in the structure. When there is no
|
||||
* padding, it becomes a memcmp at compile time (assuming a
|
||||
* constant-optimizing compiler).
|
||||
*
|
||||
* License: BSD-MIT
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/structeq/structeq.h>
|
||||
* #include <ccan/build_assert/build_assert.h>
|
||||
* #include <assert.h>
|
||||
*
|
||||
* struct mydata {
|
||||
* int start, end;
|
||||
* };
|
||||
* // Defines mydata_eq(a, b)
|
||||
* STRUCTEQ_DEF(mydata, 0, start, end);
|
||||
*
|
||||
* int main(void)
|
||||
* {
|
||||
* struct mydata a, b;
|
||||
*
|
||||
* a.start = 100;
|
||||
* a.end = 101;
|
||||
*
|
||||
* // They are equal.
|
||||
* assert(mydata_eq(&a, &b));
|
||||
*
|
||||
* b.end++;
|
||||
* // Now they are not.
|
||||
* assert(!mydata_eq(&a, &b));
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/build_assert\n");
|
||||
printf("ccan/cppmagic\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
#ifndef CCAN_STRUCTEQ_H
|
||||
#define CCAN_STRUCTEQ_H
|
||||
#include "ccan/build_assert/build_assert.h"
|
||||
#include "ccan/cppmagic/cppmagic.h"
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/cppmagic/cppmagic.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
@@ -19,24 +19,24 @@
|
||||
* "up to or equal to that amount of padding", as padding can be
|
||||
* platform dependent.
|
||||
*/
|
||||
#define STRUCTEQ_DEF(sname, padbytes, ...) \
|
||||
#define STRUCTEQ_DEF(sname, padbytes, ...) \
|
||||
static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \
|
||||
const struct sname *_b) \
|
||||
{ \
|
||||
BUILD_ASSERT(((padbytes) < 0 && \
|
||||
CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
|
||||
__VA_ARGS__)) \
|
||||
- (padbytes) >= sizeof(*_a)) \
|
||||
|| CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
|
||||
__VA_ARGS__)) \
|
||||
+ (padbytes) == sizeof(*_a)); \
|
||||
if (CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, __VA_ARGS__)) \
|
||||
== sizeof(*_a)) \
|
||||
return memcmp(_a, _b, sizeof(*_a)) == 0; \
|
||||
else \
|
||||
return CPPMAGIC_JOIN(&&, \
|
||||
CPPMAGIC_MAP(STRUCTEQ_MEMBER_CMP_, \
|
||||
__VA_ARGS__)); \
|
||||
const struct sname *_b) \
|
||||
{ \
|
||||
BUILD_ASSERT(((padbytes) < 0 && \
|
||||
CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
|
||||
__VA_ARGS__)) \
|
||||
- (padbytes) >= sizeof(*_a)) \
|
||||
|| CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \
|
||||
__VA_ARGS__)) \
|
||||
+ (padbytes) == sizeof(*_a)); \
|
||||
if (CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, __VA_ARGS__)) \
|
||||
== sizeof(*_a)) \
|
||||
return memcmp(_a, _b, sizeof(*_a)) == 0; \
|
||||
else \
|
||||
return CPPMAGIC_JOIN(&&, \
|
||||
CPPMAGIC_MAP(STRUCTEQ_MEMBER_CMP_, \
|
||||
__VA_ARGS__)); \
|
||||
}
|
||||
|
||||
/* Helpers */
|
||||
|
||||
1
nostrdb/ccan/ccan/take/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/take/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
61
nostrdb/ccan/ccan/take/_info
Normal file
61
nostrdb/ccan/ccan/take/_info
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* take - routines to mark pointers to be consumed by called functions.
|
||||
*
|
||||
* This code helps to implement ownership transfer on a per-arg basis:
|
||||
* the caller wraps the pointer argument in take() and the callee checks
|
||||
* taken() to see if it should consume it.
|
||||
*
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
* License: CC0 (Public domain)
|
||||
*
|
||||
* Example:
|
||||
* // Given "foo/bar.c" outputs basename is bar.c
|
||||
* #include <ccan/take/take.h>
|
||||
* #include <string.h>
|
||||
*
|
||||
* // Dumb basename program and driver.
|
||||
* static char *base(const char *file TAKES)
|
||||
* {
|
||||
* const char *p = strrchr(file, '/');
|
||||
* if (!p)
|
||||
* p = file;
|
||||
* else
|
||||
* p++;
|
||||
*
|
||||
* // Use arg in place if we're allowed.
|
||||
* if (taken(file))
|
||||
* return memmove((char *)file, p, strlen(p)+1);
|
||||
* else
|
||||
* return strdup(p);
|
||||
* }
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *b;
|
||||
*
|
||||
* if (argc > 1) // Mangle in place.
|
||||
* b = base(take(argv[1]));
|
||||
* else
|
||||
* b = base("test/string");
|
||||
*
|
||||
* printf("basename is %s\n", b);
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/likely\n");
|
||||
printf("ccan/str\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#include "take.h"
|
||||
#include "ccan/likely/likely.h"
|
||||
#include <ccan/take/take.h>
|
||||
#include <ccan/likely/likely.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -13,29 +13,29 @@ static void (*allocfailfn)(const void *p);
|
||||
|
||||
void *take_(const void *p, const char *label)
|
||||
{
|
||||
/* Overallocate: it's better than risking calloc returning NULL! */
|
||||
if (unlikely(label && !labelarr))
|
||||
labelarr = calloc(max_taken+1, sizeof(*labelarr));
|
||||
/* Overallocate: it's better than risking calloc returning NULL! */
|
||||
if (unlikely(label && !labelarr))
|
||||
labelarr = calloc(max_taken+1, sizeof(*labelarr));
|
||||
|
||||
if (unlikely(num_taken == max_taken)) {
|
||||
const void **new;
|
||||
if (unlikely(num_taken == max_taken)) {
|
||||
const void **new;
|
||||
|
||||
new = realloc(takenarr, sizeof(*takenarr) * (max_taken+1));
|
||||
if (unlikely(!new)) {
|
||||
if (allocfailfn) {
|
||||
allocfail++;
|
||||
allocfailfn(p);
|
||||
return NULL;
|
||||
}
|
||||
/* Otherwise we leak p. */
|
||||
return (void *)p;
|
||||
}
|
||||
takenarr = new;
|
||||
/* Once labelarr is set, we maintain it. */
|
||||
if (labelarr) {
|
||||
new = realloc(takenarr, sizeof(*takenarr) * (max_taken+1));
|
||||
if (unlikely(!new)) {
|
||||
if (allocfailfn) {
|
||||
allocfail++;
|
||||
allocfailfn(p);
|
||||
return NULL;
|
||||
}
|
||||
/* Otherwise we leak p. */
|
||||
return (void *)p;
|
||||
}
|
||||
takenarr = new;
|
||||
/* Once labelarr is set, we maintain it. */
|
||||
if (labelarr) {
|
||||
const char **labelarr_new;
|
||||
labelarr_new = realloc(labelarr,
|
||||
sizeof(*labelarr) * (max_taken+1));
|
||||
labelarr_new = realloc(labelarr,
|
||||
sizeof(*labelarr) * (max_taken+1));
|
||||
if (labelarr_new) {
|
||||
labelarr = labelarr_new;
|
||||
} else {
|
||||
@@ -46,81 +46,81 @@ void *take_(const void *p, const char *label)
|
||||
labelarr = NULL;
|
||||
}
|
||||
}
|
||||
max_taken++;
|
||||
}
|
||||
if (unlikely(labelarr))
|
||||
labelarr[num_taken] = label;
|
||||
takenarr[num_taken++] = p;
|
||||
max_taken++;
|
||||
}
|
||||
if (unlikely(labelarr))
|
||||
labelarr[num_taken] = label;
|
||||
takenarr[num_taken++] = p;
|
||||
|
||||
return (void *)p;
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
static size_t find_taken(const void *p)
|
||||
{
|
||||
size_t i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < num_taken; i++) {
|
||||
if (takenarr[i] == p)
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
for (i = 0; i < num_taken; i++) {
|
||||
if (takenarr[i] == p)
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool taken(const void *p)
|
||||
{
|
||||
size_t i;
|
||||
size_t i;
|
||||
|
||||
if (!p && unlikely(allocfail)) {
|
||||
allocfail--;
|
||||
return true;
|
||||
}
|
||||
if (!p && unlikely(allocfail)) {
|
||||
allocfail--;
|
||||
return true;
|
||||
}
|
||||
|
||||
i = find_taken(p);
|
||||
if (!i)
|
||||
return false;
|
||||
i = find_taken(p);
|
||||
if (!i)
|
||||
return false;
|
||||
|
||||
memmove(&takenarr[i-1], &takenarr[i],
|
||||
(--num_taken - (i - 1))*sizeof(takenarr[0]));
|
||||
return true;
|
||||
memmove(&takenarr[i-1], &takenarr[i],
|
||||
(--num_taken - (i - 1))*sizeof(takenarr[0]));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_taken(const void *p)
|
||||
{
|
||||
if (!p && unlikely(allocfail))
|
||||
return true;
|
||||
if (!p && unlikely(allocfail))
|
||||
return true;
|
||||
|
||||
return find_taken(p) > 0;
|
||||
return find_taken(p) > 0;
|
||||
}
|
||||
|
||||
const char *taken_any(void)
|
||||
{
|
||||
static char pointer_buf[32];
|
||||
static char pointer_buf[32];
|
||||
|
||||
if (num_taken == 0)
|
||||
return NULL;
|
||||
if (num_taken == 0)
|
||||
return NULL;
|
||||
|
||||
/* We're *allowed* to have some with labels, some without. */
|
||||
if (labelarr) {
|
||||
size_t i;
|
||||
for (i = 0; i < num_taken; i++)
|
||||
if (labelarr[i])
|
||||
return labelarr[i];
|
||||
}
|
||||
/* We're *allowed* to have some with labels, some without. */
|
||||
if (labelarr) {
|
||||
size_t i;
|
||||
for (i = 0; i < num_taken; i++)
|
||||
if (labelarr[i])
|
||||
return labelarr[i];
|
||||
}
|
||||
|
||||
sprintf(pointer_buf, "%p", takenarr[0]);
|
||||
return pointer_buf;
|
||||
sprintf(pointer_buf, "%p", takenarr[0]);
|
||||
return pointer_buf;
|
||||
}
|
||||
|
||||
void take_cleanup(void)
|
||||
{
|
||||
max_taken = num_taken = 0;
|
||||
free(takenarr);
|
||||
takenarr = NULL;
|
||||
free(labelarr);
|
||||
labelarr = NULL;
|
||||
max_taken = num_taken = 0;
|
||||
free(takenarr);
|
||||
takenarr = NULL;
|
||||
free(labelarr);
|
||||
labelarr = NULL;
|
||||
}
|
||||
|
||||
void take_allocfail(void (*fn)(const void *p))
|
||||
{
|
||||
allocfailfn = fn;
|
||||
allocfailfn = fn;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_TAKE_H
|
||||
#define CCAN_TAKE_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
#include "str.h"
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
#ifdef CCAN_TAKE_DEBUG
|
||||
#define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p)
|
||||
@@ -17,8 +17,8 @@
|
||||
* This doesn't do anything, but useful for documentation.
|
||||
*
|
||||
* Example:
|
||||
* void print_string(const char *str TAKES);
|
||||
*
|
||||
* void print_string(const char *str TAKES);
|
||||
*
|
||||
*/
|
||||
#define TAKES
|
||||
|
||||
@@ -41,18 +41,18 @@
|
||||
* this only returns true once.
|
||||
*
|
||||
* Example:
|
||||
* // Silly routine to add 1
|
||||
* static int *add_one(const int *num TAKES)
|
||||
* {
|
||||
* int *ret;
|
||||
* if (taken(num))
|
||||
* ret = (int *)num;
|
||||
* else
|
||||
* ret = malloc(sizeof(int));
|
||||
* if (ret)
|
||||
* *ret = (*num) + 1;
|
||||
* return ret;
|
||||
* }
|
||||
* // Silly routine to add 1
|
||||
* static int *add_one(const int *num TAKES)
|
||||
* {
|
||||
* int *ret;
|
||||
* if (taken(num))
|
||||
* ret = (int *)num;
|
||||
* else
|
||||
* ret = malloc(sizeof(int));
|
||||
* if (ret)
|
||||
* *ret = (*num) + 1;
|
||||
* return ret;
|
||||
* }
|
||||
*/
|
||||
bool taken(const void *p);
|
||||
|
||||
@@ -63,15 +63,15 @@ bool taken(const void *p);
|
||||
* This is like the above, but doesn't remove it from the taken list.
|
||||
*
|
||||
* Example:
|
||||
* // Silly routine to add 1: doesn't handle taken args!
|
||||
* static int *add_one_notake(const int *num)
|
||||
* {
|
||||
* int *ret = malloc(sizeof(int));
|
||||
* assert(!is_taken(num));
|
||||
* if (ret)
|
||||
* *ret = (*num) + 1;
|
||||
* return ret;
|
||||
* }
|
||||
* // Silly routine to add 1: doesn't handle taken args!
|
||||
* static int *add_one_notake(const int *num)
|
||||
* {
|
||||
* int *ret = malloc(sizeof(int));
|
||||
* assert(!is_taken(num));
|
||||
* if (ret)
|
||||
* *ret = (*num) + 1;
|
||||
* return ret;
|
||||
* }
|
||||
*/
|
||||
bool is_taken(const void *p);
|
||||
|
||||
@@ -83,10 +83,10 @@ bool is_taken(const void *p);
|
||||
* a static char buffer with the pointer value in it. NULL if none are taken.
|
||||
*
|
||||
* Example:
|
||||
* static void cleanup(void)
|
||||
* {
|
||||
* assert(!taken_any());
|
||||
* }
|
||||
* static void cleanup(void)
|
||||
* {
|
||||
* assert(!taken_any());
|
||||
* }
|
||||
*/
|
||||
const char *taken_any(void);
|
||||
|
||||
@@ -96,10 +96,10 @@ const char *taken_any(void);
|
||||
* This is useful in atexit() handlers for valgrind-style leak detection.
|
||||
*
|
||||
* Example:
|
||||
* static void cleanup2(void)
|
||||
* {
|
||||
* take_cleanup();
|
||||
* }
|
||||
* static void cleanup2(void)
|
||||
* {
|
||||
* take_cleanup();
|
||||
* }
|
||||
*/
|
||||
void take_cleanup(void);
|
||||
|
||||
@@ -113,15 +113,15 @@ void take_cleanup(void);
|
||||
* it like any allocation failure.
|
||||
*
|
||||
* Example:
|
||||
* static void free_on_fail(const void *p)
|
||||
* {
|
||||
* free((void *)p);
|
||||
* }
|
||||
* static void free_on_fail(const void *p)
|
||||
* {
|
||||
* free((void *)p);
|
||||
* }
|
||||
*
|
||||
* static void init(void)
|
||||
* {
|
||||
* take_allocfail(free_on_fail);
|
||||
* }
|
||||
* static void init(void)
|
||||
* {
|
||||
* take_allocfail(free_on_fail);
|
||||
* }
|
||||
*/
|
||||
void take_allocfail(void (*fn)(const void *p));
|
||||
|
||||
|
||||
1
nostrdb/ccan/ccan/tal/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/tal/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
||||
108
nostrdb/ccan/ccan/tal/_info
Normal file
108
nostrdb/ccan/ccan/tal/_info
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* tal - compact tree allocator routines (inspired by talloc)
|
||||
*
|
||||
* Tal is a hierarchical allocator; any pointer allocated by tal can
|
||||
* become the parent of another allocation. When you free that parent,
|
||||
* the children (and grandchildren, etc) are automatically freed.
|
||||
*
|
||||
* This allows you to build complex objects based on their lifetimes, eg:
|
||||
*
|
||||
* struct foo *X = tal(NULL, struct foo);
|
||||
* X->val = tal(X, int);
|
||||
*
|
||||
* and the pointer X->val would be a "child" of the tal context "X";
|
||||
* tal_free(X->val) would free X->val as expected, by tal_free(X) would
|
||||
* free X and X->val.
|
||||
*
|
||||
* With an overhead of approximately 4 pointers per object
|
||||
* (vs. talloc's 12 pointers), it uses dynamic allocation for
|
||||
* destructors and child lists, so those operations can fail. It does
|
||||
* not support talloc's references or failing destructors.
|
||||
*
|
||||
* See Also:
|
||||
* ccan/tal/str (useful string helpers)
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <err.h>
|
||||
* #include <ccan/tal/tal.h>
|
||||
*
|
||||
* // A structure containing a popened command.
|
||||
* struct command {
|
||||
* FILE *f;
|
||||
* char *command;
|
||||
* };
|
||||
*
|
||||
* // When struct command is freed, we also want to pclose pipe.
|
||||
* static void close_cmd(struct command *cmd)
|
||||
* {
|
||||
* pclose(cmd->f);
|
||||
* }
|
||||
*
|
||||
* // This function opens a writable pipe to the given command.
|
||||
* static struct command *open_output_cmd(const tal_t *ctx,
|
||||
* const char *a0, const char *a1)
|
||||
* {
|
||||
* struct command *cmd = tal(ctx, struct command);
|
||||
*
|
||||
* if (!cmd)
|
||||
* return NULL;
|
||||
*
|
||||
* // Note that tal/str has helpers to make this much easier!
|
||||
* cmd->command = tal_arrz(cmd, char, strlen(a0) + strlen(a1) + 2);
|
||||
* if (!cmd->command) {
|
||||
* tal_free(cmd);
|
||||
* return NULL;
|
||||
* }
|
||||
* strcat(cmd->command, a0);
|
||||
* strcat(cmd->command, " ");
|
||||
* strcat(cmd->command, a1);
|
||||
*
|
||||
* cmd->f = popen(cmd->command, "w");
|
||||
* if (!cmd->f) {
|
||||
* tal_free(cmd);
|
||||
* return NULL;
|
||||
* }
|
||||
* tal_add_destructor(cmd, close_cmd);
|
||||
* return cmd;
|
||||
* }
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* struct command *cmd;
|
||||
*
|
||||
* if (argc != 2)
|
||||
* errx(1, "Usage: %s <command>\n", argv[0]);
|
||||
*
|
||||
* cmd = open_output_cmd(NULL, argv[1], "hello");
|
||||
* if (!cmd)
|
||||
* err(1, "Running '%s hello'", argv[1]);
|
||||
* fprintf(cmd->f, "This is a test\n");
|
||||
* tal_free(cmd);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/alignof\n");
|
||||
printf("ccan/compiler\n");
|
||||
printf("ccan/likely\n");
|
||||
printf("ccan/list\n");
|
||||
printf("ccan/str\n");
|
||||
printf("ccan/take\n");
|
||||
printf("ccan/typesafe_cb\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
26
nostrdb/ccan/ccan/tal/benchmark/Makefile
Normal file
26
nostrdb/ccan/ccan/tal/benchmark/Makefile
Normal file
@@ -0,0 +1,26 @@
|
||||
CFLAGS=-O3 -Wall -flto -I../../..
|
||||
#CFLAGS=-O3 -Wall -I../../..
|
||||
#CFLAGS=-g -Wall -I../../..
|
||||
LDFLAGS=-O3 -flto
|
||||
LDLIBS=-lrt
|
||||
|
||||
all: speed samba-allocs
|
||||
|
||||
speed: speed.o tal.o talloc.o time.o list.o take.o str.o
|
||||
samba-allocs: samba-allocs.o tal.o talloc.o time.o list.o take.o
|
||||
|
||||
tal.o: ../tal.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
str.o: ../str/str.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
talloc.o: ../../talloc/talloc.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
time.o: ../../time/time.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
list.o: ../../list/list.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
take.o: ../../take/take.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f speed samba-allocs *.o
|
||||
374
nostrdb/ccan/ccan/tal/benchmark/samba-allocs.c
Normal file
374
nostrdb/ccan/ccan/tal/benchmark/samba-allocs.c
Normal file
@@ -0,0 +1,374 @@
|
||||
/* Grab dump of Samba4 talloc tree to do benchmarks on it. */
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/str/str.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
struct node {
|
||||
void *n;
|
||||
struct node *parent;
|
||||
char *name;
|
||||
bool destructor;
|
||||
size_t len;
|
||||
unsigned int num_children;
|
||||
struct node *children[0];
|
||||
};
|
||||
|
||||
static int node_count;
|
||||
|
||||
static struct node *new_node(void)
|
||||
{
|
||||
node_count++;
|
||||
return calloc(sizeof(struct node), 1);
|
||||
}
|
||||
|
||||
/* struct db_context contains 282 bytes in 5 blocks (ref 0) d=(nil) 0x1f64e70 */
|
||||
static struct node *parse(const char *line)
|
||||
{
|
||||
struct node *n = new_node();
|
||||
const char *p;
|
||||
|
||||
p = strstr(line, " contains ");
|
||||
p += strlen(" contains ");
|
||||
p += strspn(line, " ");
|
||||
n->len = strtol(p, NULL, 0);
|
||||
p = strstr(p, "d=");
|
||||
if (p[2] != '(')
|
||||
n->destructor = true;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void add_child(struct node *parent, struct node *child)
|
||||
{
|
||||
unsigned int i;
|
||||
struct node *oldp = parent;
|
||||
|
||||
parent = realloc(parent, sizeof(*parent)
|
||||
+ sizeof(parent->children[0]) * (parent->num_children+1));
|
||||
parent->children[parent->num_children++] = child;
|
||||
child->parent = parent;
|
||||
|
||||
if (parent == oldp)
|
||||
return;
|
||||
|
||||
/* Fix up children's parent pointers. */
|
||||
for (i = 0; i < parent->num_children-1; i++) {
|
||||
assert(parent->children[i]->parent == oldp);
|
||||
parent->children[i]->parent = parent;
|
||||
}
|
||||
|
||||
/* Fix up parent's child pointer. */
|
||||
if (parent->parent) {
|
||||
assert(parent->parent->children[parent->parent->num_children-1]
|
||||
== oldp);
|
||||
parent->parent->children[parent->parent->num_children-1]
|
||||
= parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Random string of required length */
|
||||
static char *namelen(int len)
|
||||
{
|
||||
char *p = malloc(len);
|
||||
memset(p, 'x', len-1);
|
||||
p[len-1] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct node *read_nodes(FILE *f)
|
||||
{
|
||||
char line[4096];
|
||||
unsigned int curr_indent = 0, indent;
|
||||
struct node *n, *curr = new_node();
|
||||
|
||||
/* Ignore first line */
|
||||
fgets(line, 4096, f);
|
||||
|
||||
while (fgets(line, 4096, f)) {
|
||||
bool is_name;
|
||||
|
||||
indent = strspn(line, " ");
|
||||
|
||||
/* Ignore references for now. */
|
||||
if (strstarts(line + indent, "reference to: "))
|
||||
continue;
|
||||
|
||||
/* Blank name? Use offset of 'contains' to guess indent! */
|
||||
if (strstarts(line + indent, "contains "))
|
||||
indent -= 31;
|
||||
|
||||
is_name = strstarts(line + indent, ".name ");
|
||||
|
||||
n = parse(line + indent);
|
||||
if (is_name) {
|
||||
curr->name = namelen(n->len);
|
||||
free(n);
|
||||
} else {
|
||||
if (indent > curr_indent) {
|
||||
assert(indent == curr_indent + 4);
|
||||
curr_indent += 4;
|
||||
} else {
|
||||
/* Go back up to parent. */
|
||||
for (curr_indent += 4;
|
||||
curr_indent != indent;
|
||||
curr_indent -= 4)
|
||||
curr = curr->parent;
|
||||
}
|
||||
add_child(curr, n);
|
||||
curr = n;
|
||||
}
|
||||
}
|
||||
while (curr->parent) {
|
||||
curr = curr->parent;
|
||||
curr_indent -= 4;
|
||||
}
|
||||
assert(curr_indent == 0);
|
||||
return curr;
|
||||
}
|
||||
|
||||
static int unused_talloc_destructor(void *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_tallocs(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
static int count;
|
||||
|
||||
if (count++ % 16 == 0)
|
||||
node->n = talloc_array(node->parent ? node->parent->n : NULL,
|
||||
char, node->len);
|
||||
else
|
||||
node->n = talloc_size(node->parent ? node->parent->n : NULL,
|
||||
node->len);
|
||||
if (node->destructor)
|
||||
talloc_set_destructor(node->n, unused_talloc_destructor);
|
||||
if (node->name)
|
||||
talloc_set_name(node->n, "%s", node->name);
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
do_tallocs(node->children[i]);
|
||||
}
|
||||
|
||||
static void free_tallocs(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
free_tallocs(node->children[i]);
|
||||
|
||||
talloc_free(node->n);
|
||||
}
|
||||
|
||||
static void unused_tal_destructor(void *p)
|
||||
{
|
||||
}
|
||||
|
||||
static void do_tals(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
static int count;
|
||||
|
||||
node->n = tal_arr(node->parent ? node->parent->n : NULL,
|
||||
char, node->len);
|
||||
|
||||
if (node->destructor)
|
||||
tal_add_destructor(node->n, unused_tal_destructor);
|
||||
if (node->name)
|
||||
tal_set_name(node->n, node->name);
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
do_tals(node->children[i]);
|
||||
}
|
||||
|
||||
static void free_tals(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
free_tals(node->children[i]);
|
||||
|
||||
tal_free(node->n);
|
||||
}
|
||||
|
||||
static void do_mallocs(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
node->n = malloc(node->len + (node->name ? strlen(node->name) + 1 : 1));
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
do_mallocs(node->children[i]);
|
||||
}
|
||||
|
||||
static void free_mallocs(struct node *node)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < node->num_children; i++)
|
||||
free_mallocs(node->children[i]);
|
||||
|
||||
free(node->n);
|
||||
}
|
||||
|
||||
/* See proc(5): field 23 is vsize, 24 is rss (in pages) */
|
||||
static void dump_vsize(void)
|
||||
{
|
||||
int fd, i;
|
||||
char buf[1000], *p = buf;
|
||||
|
||||
sprintf(buf, "/proc/%u/stat", getpid());
|
||||
fd = open(buf, O_RDONLY);
|
||||
read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
|
||||
for (i = 0; i < 22; i++) {
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
}
|
||||
i = atoi(p);
|
||||
printf("Virtual size = %i, ", i);
|
||||
p += strcspn(p, " ");
|
||||
p += strspn(p, " ");
|
||||
i = atoi(p);
|
||||
printf("RSS = %i\n", i * getpagesize());
|
||||
}
|
||||
|
||||
#define LOOPS 1000
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct timeabs start;
|
||||
struct timerel alloc_time, free_time;
|
||||
struct node *root;
|
||||
unsigned int i;
|
||||
FILE *f;
|
||||
bool run_talloc = true, run_tal = true, run_malloc = true;
|
||||
|
||||
f = argv[1] ? fopen(argv[1], "r") : stdin;
|
||||
root = read_nodes(f);
|
||||
fclose(f);
|
||||
printf("Read %u nodes\n", node_count);
|
||||
|
||||
if (argc > 2) {
|
||||
if (streq(argv[2], "--talloc-size")) {
|
||||
do_tallocs(root);
|
||||
dump_vsize();
|
||||
exit(0);
|
||||
}
|
||||
if (streq(argv[2], "--tal-size")) {
|
||||
do_tals(root);
|
||||
dump_vsize();
|
||||
exit(0);
|
||||
}
|
||||
if (strcmp(argv[2], "--talloc") == 0)
|
||||
run_tal = run_malloc = false;
|
||||
else if (strcmp(argv[2], "--tal") == 0)
|
||||
run_talloc = run_malloc = false;
|
||||
else if (strcmp(argv[2], "--malloc") == 0)
|
||||
run_talloc = run_tal = false;
|
||||
else
|
||||
errx(1, "Bad flag %s", argv[2]);
|
||||
}
|
||||
|
||||
if (!run_malloc)
|
||||
goto after_malloc;
|
||||
|
||||
alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
|
||||
free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
start = time_now();
|
||||
do_mallocs(root);
|
||||
alloc_time = timerel_add(alloc_time,
|
||||
time_between(time_now(), start));
|
||||
|
||||
start = time_now();
|
||||
free_mallocs(root);
|
||||
free_time = timerel_add(free_time,
|
||||
time_between(time_now(), start));
|
||||
}
|
||||
alloc_time = time_divide(alloc_time, i);
|
||||
free_time = time_divide(free_time, i);
|
||||
printf("Malloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
|
||||
printf("Free time: %"PRIu64"ns\n", time_to_nsec(free_time));
|
||||
|
||||
after_malloc:
|
||||
if (!run_talloc)
|
||||
goto after_talloc;
|
||||
|
||||
alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
|
||||
free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
start = time_now();
|
||||
do_tallocs(root);
|
||||
alloc_time = timerel_add(alloc_time,
|
||||
time_between(time_now(), start));
|
||||
|
||||
start = time_now();
|
||||
free_tallocs(root);
|
||||
free_time = timerel_add(free_time,
|
||||
time_between(time_now(), start));
|
||||
}
|
||||
alloc_time = time_divide(alloc_time, i);
|
||||
free_time = time_divide(free_time, i);
|
||||
printf("Talloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
|
||||
printf("talloc_free time: %"PRIu64"ns\n", time_to_nsec(free_time));
|
||||
|
||||
free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
do_tallocs(root);
|
||||
|
||||
start = time_now();
|
||||
talloc_free(root->n);
|
||||
free_time = timerel_add(free_time,
|
||||
time_between(time_now(), start));
|
||||
}
|
||||
free_time = time_divide(free_time, i);
|
||||
printf("Single talloc_free time: %"PRIu64"\n", time_to_nsec(free_time));
|
||||
|
||||
after_talloc:
|
||||
if (!run_tal)
|
||||
goto after_tal;
|
||||
|
||||
alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
|
||||
free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
start = time_now();
|
||||
do_tals(root);
|
||||
alloc_time = timerel_add(alloc_time,
|
||||
time_between(time_now(), start));
|
||||
|
||||
start = time_now();
|
||||
free_tals(root);
|
||||
free_time = timerel_add(free_time,
|
||||
time_between(time_now(), start));
|
||||
}
|
||||
alloc_time = time_divide(alloc_time, i);
|
||||
free_time = time_divide(free_time, i);
|
||||
printf("Tal time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
|
||||
printf("Tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time));
|
||||
|
||||
free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
|
||||
for (i = 0; i < LOOPS; i++) {
|
||||
do_tals(root);
|
||||
|
||||
start = time_now();
|
||||
tal_free(root->n);
|
||||
free_time = timerel_add(free_time,
|
||||
time_between(time_now(), start));
|
||||
}
|
||||
free_time = time_divide(free_time, i);
|
||||
printf("Single tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time));
|
||||
after_tal:
|
||||
|
||||
return 0;
|
||||
}
|
||||
125
nostrdb/ccan/ccan/tal/benchmark/speed.c
Normal file
125
nostrdb/ccan/ccan/tal/benchmark/speed.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Taken from samba/lib/talloc/testsuite.c: Unix SMB/CIFS implementation.
|
||||
|
||||
local testing of talloc routines.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
** NOTE! The following LGPL license applies to the talloc
|
||||
** library. This does NOT imply that all of Samba is released
|
||||
** under the LGPL
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <ccan/talloc/talloc.h>
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <ccan/time/time.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOOPS 1024
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *ctx;
|
||||
unsigned count;
|
||||
int i, j;
|
||||
struct timeabs tv;
|
||||
void *p1, *p2[100], *p3[100];
|
||||
bool run_talloc = true, run_tal = true, run_malloc = true;
|
||||
|
||||
if (argv[1]) {
|
||||
if (strcmp(argv[1], "--talloc") == 0)
|
||||
run_tal = run_malloc = false;
|
||||
else if (strcmp(argv[1], "--tal") == 0)
|
||||
run_talloc = run_malloc = false;
|
||||
else if (strcmp(argv[1], "--malloc") == 0)
|
||||
run_talloc = run_tal = false;
|
||||
else
|
||||
errx(1, "Bad flag %s", argv[1]);
|
||||
}
|
||||
|
||||
if (!run_talloc)
|
||||
goto after_talloc;
|
||||
|
||||
ctx = talloc_new(NULL);
|
||||
tv = time_now();
|
||||
count = 0;
|
||||
do {
|
||||
for (i=0;i<LOOPS;i++) {
|
||||
p1 = talloc_size(ctx, LOOPS % 128);
|
||||
for (j = 0; j < 100; j++) {
|
||||
p2[j] = talloc_strdup(p1, "foo bar");
|
||||
p3[j] = talloc_size(p1, 300);
|
||||
}
|
||||
talloc_free(p1);
|
||||
}
|
||||
count += (1 + 200) * LOOPS;
|
||||
} while (time_between(time_now(), tv).ts.tv_sec < 5);
|
||||
|
||||
fprintf(stderr, "talloc: %.0f ops/sec\n", count/5.0);
|
||||
|
||||
talloc_free(ctx);
|
||||
|
||||
after_talloc:
|
||||
if (!run_tal)
|
||||
goto after_tal;
|
||||
|
||||
ctx = tal(NULL, char);
|
||||
tv = time_now();
|
||||
count = 0;
|
||||
do {
|
||||
for (i=0;i<LOOPS;i++) {
|
||||
p1 = tal_arr(ctx, char, LOOPS % 128);
|
||||
for (j = 0; j < 100; j++) {
|
||||
p2[j] = tal_strdup(p1, "foo bar");
|
||||
p3[j] = tal_arr(p1, char, 300);
|
||||
}
|
||||
tal_free(p1);
|
||||
}
|
||||
count += (1 + 200) * LOOPS;
|
||||
} while (time_between(time_now(), tv).ts.tv_sec < 5);
|
||||
fprintf(stderr, "tal: %.0f ops/sec\n", count/5.0);
|
||||
|
||||
tal_free(ctx);
|
||||
|
||||
after_tal:
|
||||
if (!run_malloc)
|
||||
goto after_malloc;
|
||||
|
||||
tv = time_now();
|
||||
count = 0;
|
||||
do {
|
||||
for (i=0;i<LOOPS;i++) {
|
||||
p1 = malloc(LOOPS % 128);
|
||||
for (j = 0; j < 100; j++) {
|
||||
p2[j] = strdup("foo bar");
|
||||
p3[j] = malloc(300);
|
||||
}
|
||||
for (j = 0; j < 100; j++) {
|
||||
free(p2[j]);
|
||||
free(p3[j]);
|
||||
}
|
||||
free(p1);
|
||||
}
|
||||
count += (1 + 200) * LOOPS;
|
||||
} while (time_between(time_now(), tv).ts.tv_sec < 5);
|
||||
fprintf(stderr, "malloc: %.0f ops/sec\n", count/5.0);
|
||||
|
||||
after_malloc:
|
||||
printf("success: speed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
26137
nostrdb/ccan/ccan/tal/benchmark/talloc.dump
Normal file
26137
nostrdb/ccan/ccan/tal/benchmark/talloc.dump
Normal file
File diff suppressed because it is too large
Load Diff
1
nostrdb/ccan/ccan/tal/str/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/tal/str/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../licenses/BSD-MIT
|
||||
61
nostrdb/ccan/ccan/tal/str/_info
Normal file
61
nostrdb/ccan/ccan/tal/str/_info
Normal file
@@ -0,0 +1,61 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* tal/str - string helper routines which use tal
|
||||
*
|
||||
* This is a grab bag of functions for string operations, designed to enhance
|
||||
* the standard string.h; these are separated from the non-tal-needing
|
||||
* string utilities in "str.h". Each string created by this library
|
||||
* will have tal_count() equal to strlen() + 1 (assuming you didn't create
|
||||
* a string containing a NUL, such as using tal_fmt("%c", 0)).
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/tal/str/str.h>
|
||||
* #include <ccan/tal/grab_file/grab_file.h>
|
||||
* #include <err.h>
|
||||
*
|
||||
* // Dumb demo program to double-linespace a file.
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *textfile;
|
||||
* char **lines;
|
||||
*
|
||||
* if (argc > 2)
|
||||
* errx(1, "Takes 0 or 1 arguments");
|
||||
* // Grab lines in file.
|
||||
* textfile = grab_file(NULL, argv[1]);
|
||||
* if (!textfile)
|
||||
* err(1, "Failed reading %s", argv[1]);
|
||||
* lines = tal_strsplit(textfile, textfile, "\n", STR_EMPTY_OK);
|
||||
*
|
||||
* // Join them back together with two linefeeds.
|
||||
* printf("%s", tal_strjoin(textfile, lines, "\n\n", STR_TRAIL));
|
||||
*
|
||||
* // Free everything, just because we can.
|
||||
* tal_free(textfile);
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
printf("ccan/str\n");
|
||||
#ifdef TAL_USE_TALLOC
|
||||
printf("ccan/tal/talloc\n");
|
||||
#else
|
||||
printf("ccan/tal\n");
|
||||
#endif
|
||||
printf("ccan/take\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -4,311 +4,312 @@
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include "str.h"
|
||||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "str.h"
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
char *tal_strdup_(const tal_t *ctx, const char *p, const char *label)
|
||||
{
|
||||
/* We have to let through NULL for take(). */
|
||||
return tal_dup_arr_label(ctx, char, p, p ? strlen(p) + 1: 1, 0, label);
|
||||
/* We have to let through NULL for take(). */
|
||||
return tal_dup_arr_label(ctx, char, p, p ? strlen(p) + 1: 1, 0, label);
|
||||
}
|
||||
|
||||
char *tal_strndup_(const tal_t *ctx, const char *p, size_t n, const char *label)
|
||||
{
|
||||
size_t len;
|
||||
char *ret;
|
||||
size_t len;
|
||||
char *ret;
|
||||
|
||||
/* We have to let through NULL for take(). */
|
||||
if (likely(p))
|
||||
len = strnlen(p, n);
|
||||
else
|
||||
len = n;
|
||||
/* We have to let through NULL for take(). */
|
||||
if (likely(p))
|
||||
len = strnlen(p, n);
|
||||
else
|
||||
len = n;
|
||||
|
||||
ret = tal_dup_arr_label(ctx, char, p, len, 1, label);
|
||||
if (ret)
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
ret = tal_dup_arr_label(ctx, char, p, len, 1, label);
|
||||
if (ret)
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *ret;
|
||||
va_list ap;
|
||||
char *ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = tal_vfmt_(ctx, fmt, ap, label);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
ret = tal_vfmt_(ctx, fmt, ap, label);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap)
|
||||
{
|
||||
/* A decent guess to start. */
|
||||
size_t max = strlen(fmt) * 2 + 1;
|
||||
bool ok;
|
||||
/* A decent guess to start. */
|
||||
size_t max = strlen(fmt) * 2 + 1;
|
||||
bool ok;
|
||||
|
||||
for (;;) {
|
||||
va_list ap2;
|
||||
int ret;
|
||||
for (;;) {
|
||||
va_list ap2;
|
||||
int ret;
|
||||
|
||||
if (!tal_resize(buf, off + max)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
if (!tal_resize(buf, off + max)) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
va_copy(ap2, ap);
|
||||
ret = vsnprintf(*buf + off, max, fmt, ap2);
|
||||
va_end(ap2);
|
||||
va_copy(ap2, ap);
|
||||
ret = vsnprintf(*buf + off, max, fmt, ap2);
|
||||
va_end(ap2);
|
||||
|
||||
if (ret < max) {
|
||||
ok = true;
|
||||
/* Make sure tal_count() is correct! */
|
||||
tal_resize(buf, off + ret + 1);
|
||||
break;
|
||||
}
|
||||
max *= 2;
|
||||
}
|
||||
if (ret < max) {
|
||||
ok = true;
|
||||
/* Make sure tal_count() is correct! */
|
||||
tal_resize(buf, off + ret + 1);
|
||||
break;
|
||||
}
|
||||
max *= 2;
|
||||
}
|
||||
|
||||
if (taken(fmt))
|
||||
tal_free(fmt);
|
||||
return ok;
|
||||
if (taken(fmt))
|
||||
tal_free(fmt);
|
||||
return ok;
|
||||
}
|
||||
|
||||
char *tal_vfmt_(const tal_t *ctx, const char *fmt, va_list ap, const char *label)
|
||||
{
|
||||
char *buf;
|
||||
char *buf;
|
||||
|
||||
if (!fmt && taken(fmt))
|
||||
return NULL;
|
||||
if (!fmt && taken(fmt))
|
||||
return NULL;
|
||||
|
||||
/* A decent guess to start. */
|
||||
buf = tal_arr_label(ctx, char, strlen(fmt) * 2, label);
|
||||
if (!do_vfmt(&buf, 0, fmt, ap))
|
||||
buf = tal_free(buf);
|
||||
return buf;
|
||||
/* A decent guess to start. */
|
||||
buf = tal_arr_label(ctx, char, strlen(fmt) * 2, label);
|
||||
if (!do_vfmt(&buf, 0, fmt, ap))
|
||||
buf = tal_free(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool tal_append_vfmt(char **baseptr, const char *fmt, va_list ap)
|
||||
{
|
||||
if (!fmt && taken(fmt))
|
||||
return false;
|
||||
if (!fmt && taken(fmt))
|
||||
return false;
|
||||
|
||||
return do_vfmt(baseptr, strlen(*baseptr), fmt, ap);
|
||||
return do_vfmt(baseptr, strlen(*baseptr), fmt, ap);
|
||||
}
|
||||
|
||||
bool tal_append_fmt(char **baseptr, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
bool ret;
|
||||
va_list ap;
|
||||
bool ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = tal_append_vfmt(baseptr, fmt, ap);
|
||||
va_end(ap);
|
||||
va_start(ap, fmt);
|
||||
ret = tal_append_vfmt(baseptr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *tal_strcat_(const tal_t *ctx, const char *s1, const char *s2,
|
||||
const char *label)
|
||||
const char *label)
|
||||
{
|
||||
size_t len1, len2;
|
||||
char *ret;
|
||||
size_t len1, len2;
|
||||
char *ret;
|
||||
|
||||
if (unlikely(!s2) && taken(s2)) {
|
||||
if (taken(s1))
|
||||
tal_free(s1);
|
||||
return NULL;
|
||||
}
|
||||
/* We have to let through NULL for take(). */
|
||||
len1 = s1 ? strlen(s1) : 0;
|
||||
len2 = strlen(s2);
|
||||
if (unlikely(!s2) && taken(s2)) {
|
||||
if (taken(s1))
|
||||
tal_free(s1);
|
||||
return NULL;
|
||||
}
|
||||
/* We have to let through NULL for take(). */
|
||||
len1 = s1 ? strlen(s1) : 0;
|
||||
len2 = strlen(s2);
|
||||
|
||||
ret = tal_dup_arr_label(ctx, char, s1, len1, len2 + 1, label);
|
||||
if (likely(ret))
|
||||
memcpy(ret + len1, s2, len2 + 1);
|
||||
ret = tal_dup_arr_label(ctx, char, s1, len1, len2 + 1, label);
|
||||
if (likely(ret))
|
||||
memcpy(ret + len1, s2, len2 + 1);
|
||||
|
||||
if (taken(s2))
|
||||
tal_free(s2);
|
||||
return ret;
|
||||
if (taken(s2))
|
||||
tal_free(s2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char **tal_strsplit_(const tal_t *ctx,
|
||||
const char *string, const char *delims, enum strsplit flags,
|
||||
const char *label)
|
||||
const char *string, const char *delims, enum strsplit flags,
|
||||
const char *label)
|
||||
{
|
||||
char **parts, *str;
|
||||
size_t max = 64, num = 0;
|
||||
char **parts, *str;
|
||||
size_t max = 64, num = 0;
|
||||
|
||||
parts = tal_arr(ctx, char *, max + 1);
|
||||
if (unlikely(!parts)) {
|
||||
if (taken(string))
|
||||
tal_free(string);
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return NULL;
|
||||
}
|
||||
str = tal_strdup(parts, string);
|
||||
if (unlikely(!str))
|
||||
goto fail;
|
||||
if (unlikely(!delims) && is_taken(delims))
|
||||
goto fail;
|
||||
parts = tal_arr(ctx, char *, max + 1);
|
||||
if (unlikely(!parts)) {
|
||||
if (taken(string))
|
||||
tal_free(string);
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return NULL;
|
||||
}
|
||||
str = tal_strdup(parts, string);
|
||||
if (unlikely(!str))
|
||||
goto fail;
|
||||
if (unlikely(!delims) && is_taken(delims))
|
||||
goto fail;
|
||||
|
||||
if (flags == STR_NO_EMPTY)
|
||||
str += strspn(str, delims);
|
||||
if (flags == STR_NO_EMPTY)
|
||||
str += strspn(str, delims);
|
||||
|
||||
while (*str != '\0') {
|
||||
size_t len = strcspn(str, delims), dlen;
|
||||
while (*str != '\0') {
|
||||
size_t len = strcspn(str, delims), dlen;
|
||||
|
||||
parts[num] = str;
|
||||
dlen = strspn(str + len, delims);
|
||||
parts[num][len] = '\0';
|
||||
if (flags == STR_EMPTY_OK && dlen)
|
||||
dlen = 1;
|
||||
str += len + dlen;
|
||||
if (++num == max && !tal_resize(&parts, max*=2 + 1))
|
||||
goto fail;
|
||||
}
|
||||
parts[num] = NULL;
|
||||
parts[num] = str;
|
||||
dlen = strspn(str + len, delims);
|
||||
parts[num][len] = '\0';
|
||||
if (flags == STR_EMPTY_OK && dlen)
|
||||
dlen = 1;
|
||||
str += len + dlen;
|
||||
if (++num == max && !tal_resize(&parts, max*=2 + 1))
|
||||
goto fail;
|
||||
}
|
||||
parts[num] = NULL;
|
||||
|
||||
/* Ensure that tal_count() is correct. */
|
||||
if (unlikely(!tal_resize(&parts, num+1)))
|
||||
goto fail;
|
||||
/* Ensure that tal_count() is correct. */
|
||||
if (unlikely(!tal_resize(&parts, num+1)))
|
||||
goto fail;
|
||||
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return parts;
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return parts;
|
||||
|
||||
fail:
|
||||
tal_free(parts);
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return NULL;
|
||||
tal_free(parts);
|
||||
if (taken(delims))
|
||||
tal_free(delims);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *tal_strjoin_(const tal_t *ctx,
|
||||
char *strings[], const char *delim, enum strjoin flags,
|
||||
const char *label)
|
||||
char *strings[], const char *delim, enum strjoin flags,
|
||||
const char *label)
|
||||
{
|
||||
unsigned int i;
|
||||
char *ret = NULL;
|
||||
size_t totlen = 0, dlen;
|
||||
unsigned int i;
|
||||
char *ret = NULL;
|
||||
size_t totlen = 0, dlen;
|
||||
|
||||
if (unlikely(!strings) && is_taken(strings))
|
||||
goto fail;
|
||||
if (unlikely(!strings) && is_taken(strings))
|
||||
goto fail;
|
||||
|
||||
if (unlikely(!delim) && is_taken(delim))
|
||||
goto fail;
|
||||
if (unlikely(!delim) && is_taken(delim))
|
||||
goto fail;
|
||||
|
||||
dlen = strlen(delim);
|
||||
ret = tal_arr_label(ctx, char, dlen*2+1, label);
|
||||
if (!ret)
|
||||
goto fail;
|
||||
dlen = strlen(delim);
|
||||
ret = tal_arr_label(ctx, char, dlen*2+1, label);
|
||||
if (!ret)
|
||||
goto fail;
|
||||
|
||||
ret[0] = '\0';
|
||||
for (i = 0; strings[i]; i++) {
|
||||
size_t len = strlen(strings[i]);
|
||||
ret[0] = '\0';
|
||||
for (i = 0; strings[i]; i++) {
|
||||
size_t len = strlen(strings[i]);
|
||||
|
||||
if (flags == STR_NO_TRAIL && !strings[i+1])
|
||||
dlen = 0;
|
||||
if (!tal_resize(&ret, totlen + len + dlen + 1))
|
||||
goto fail;
|
||||
memcpy(ret + totlen, strings[i], len);
|
||||
totlen += len;
|
||||
memcpy(ret + totlen, delim, dlen);
|
||||
totlen += dlen;
|
||||
}
|
||||
ret[totlen] = '\0';
|
||||
/* Make sure tal_count() is correct! */
|
||||
tal_resize(&ret, totlen+1);
|
||||
if (flags == STR_NO_TRAIL && !strings[i+1])
|
||||
dlen = 0;
|
||||
if (!tal_resize(&ret, totlen + len + dlen + 1))
|
||||
goto fail;
|
||||
memcpy(ret + totlen, strings[i], len);
|
||||
totlen += len;
|
||||
memcpy(ret + totlen, delim, dlen);
|
||||
totlen += dlen;
|
||||
}
|
||||
ret[totlen] = '\0';
|
||||
/* Make sure tal_count() is correct! */
|
||||
tal_resize(&ret, totlen+1);
|
||||
out:
|
||||
if (taken(strings))
|
||||
tal_free(strings);
|
||||
if (taken(delim))
|
||||
tal_free(delim);
|
||||
return ret;
|
||||
if (taken(strings))
|
||||
tal_free(strings);
|
||||
if (taken(delim))
|
||||
tal_free(delim);
|
||||
return ret;
|
||||
fail:
|
||||
ret = tal_free(ret);
|
||||
goto out;
|
||||
ret = tal_free(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
static size_t count_open_braces(const char *string)
|
||||
{
|
||||
#if 1
|
||||
size_t num = 0, esc = 0;
|
||||
size_t num = 0, esc = 0;
|
||||
|
||||
while (*string) {
|
||||
if (*string == '\\')
|
||||
esc++;
|
||||
else {
|
||||
/* An odd number of \ means it's escaped. */
|
||||
if (*string == '(' && (esc & 1) == 0)
|
||||
num++;
|
||||
esc = 0;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
return num;
|
||||
while (*string) {
|
||||
if (*string == '\\')
|
||||
esc++;
|
||||
else {
|
||||
/* An odd number of \ means it's escaped. */
|
||||
if (*string == '(' && (esc & 1) == 0)
|
||||
num++;
|
||||
esc = 0;
|
||||
}
|
||||
string++;
|
||||
}
|
||||
return num;
|
||||
#else
|
||||
return strcount(string, "(");
|
||||
return strcount(string, "(");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tal_strreg_(const tal_t *ctx, const char *string, const char *label,
|
||||
const char *regex, ...)
|
||||
const char *regex, ...)
|
||||
{
|
||||
size_t nmatch = 1 + count_open_braces(regex);
|
||||
regmatch_t matches[nmatch];
|
||||
regex_t r;
|
||||
bool ret = false;
|
||||
unsigned int i;
|
||||
va_list ap;
|
||||
size_t nmatch = 1 + count_open_braces(regex);
|
||||
regmatch_t matches[nmatch];
|
||||
regex_t r;
|
||||
bool ret = false;
|
||||
unsigned int i;
|
||||
va_list ap;
|
||||
|
||||
if (unlikely(!regex) && is_taken(regex))
|
||||
goto fail_no_re;
|
||||
if (unlikely(!regex) && is_taken(regex))
|
||||
goto fail_no_re;
|
||||
|
||||
if (regcomp(&r, regex, REG_EXTENDED) != 0)
|
||||
goto fail_no_re;
|
||||
if (regcomp(&r, regex, REG_EXTENDED) != 0)
|
||||
goto fail_no_re;
|
||||
|
||||
if (unlikely(!string) && is_taken(string))
|
||||
goto fail;
|
||||
if (unlikely(!string) && is_taken(string))
|
||||
goto fail;
|
||||
|
||||
if (regexec(&r, string, nmatch, matches, 0) != 0)
|
||||
goto fail;
|
||||
if (regexec(&r, string, nmatch, matches, 0) != 0)
|
||||
goto fail;
|
||||
|
||||
ret = true;
|
||||
va_start(ap, regex);
|
||||
for (i = 1; i < nmatch; i++) {
|
||||
char **arg = va_arg(ap, char **);
|
||||
if (arg) {
|
||||
/* eg. ([a-z])? can give "no match". */
|
||||
if (matches[i].rm_so == -1)
|
||||
*arg = NULL;
|
||||
else {
|
||||
*arg = tal_strndup_(ctx,
|
||||
string + matches[i].rm_so,
|
||||
matches[i].rm_eo
|
||||
- matches[i].rm_so,
|
||||
label);
|
||||
/* FIXME: If we fail, we set some and leak! */
|
||||
if (!*arg) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
ret = true;
|
||||
va_start(ap, regex);
|
||||
for (i = 1; i < nmatch; i++) {
|
||||
char **arg = va_arg(ap, char **);
|
||||
if (arg) {
|
||||
/* eg. ([a-z])? can give "no match". */
|
||||
if (matches[i].rm_so == -1)
|
||||
*arg = NULL;
|
||||
else {
|
||||
*arg = tal_strndup_(ctx,
|
||||
string + matches[i].rm_so,
|
||||
matches[i].rm_eo
|
||||
- matches[i].rm_so,
|
||||
label);
|
||||
/* FIXME: If we fail, we set some and leak! */
|
||||
if (!*arg) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
fail:
|
||||
regfree(&r);
|
||||
regfree(&r);
|
||||
fail_no_re:
|
||||
if (taken(regex))
|
||||
tal_free(regex);
|
||||
if (taken(string))
|
||||
tal_free(string);
|
||||
return ret;
|
||||
if (taken(regex))
|
||||
tal_free(regex);
|
||||
if (taken(string))
|
||||
tal_free(string);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifdef TAL_USE_TALLOC
|
||||
#include <ccan/tal/talloc/talloc.h>
|
||||
#else
|
||||
#include "ccan/tal/tal.h"
|
||||
#include <ccan/tal/tal.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
@@ -30,7 +30,7 @@ char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
|
||||
*/
|
||||
#define tal_strndup(ctx, p, n) tal_strndup_(ctx, p, n, TAL_LABEL(char, "[]"))
|
||||
char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
|
||||
const char *label);
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
* tal_fmt - allocate a formatted string
|
||||
@@ -39,10 +39,10 @@ char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
|
||||
*
|
||||
* The returned string will have tal_count() == strlen() + 1.
|
||||
*/
|
||||
#define tal_fmt(ctx, ...) \
|
||||
tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
|
||||
#define tal_fmt(ctx, ...) \
|
||||
tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
|
||||
char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt TAKES,
|
||||
...) PRINTF_FMT(3,4);
|
||||
...) PRINTF_FMT(3,4);
|
||||
|
||||
/**
|
||||
* tal_vfmt - allocate a formatted string (va_list version)
|
||||
@@ -52,11 +52,11 @@ char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt TAKES,
|
||||
*
|
||||
* The returned string will have tal_count() == strlen() + 1.
|
||||
*/
|
||||
#define tal_vfmt(ctx, fmt, va) \
|
||||
tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
|
||||
#define tal_vfmt(ctx, fmt, va) \
|
||||
tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
|
||||
char *tal_vfmt_(const tal_t *ctx, const char *fmt TAKES, va_list ap,
|
||||
const char *label)
|
||||
PRINTF_FMT(2,0);
|
||||
const char *label)
|
||||
PRINTF_FMT(2,0);
|
||||
|
||||
/**
|
||||
* tal_append_fmt - append a formatted string to a talloc string.
|
||||
@@ -89,11 +89,11 @@ bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
|
||||
*/
|
||||
#define tal_strcat(ctx, s1, s2) tal_strcat_(ctx, s1, s2, TAL_LABEL(char, "[]"))
|
||||
char *tal_strcat_(const tal_t *ctx, const char *s1 TAKES, const char *s2 TAKES,
|
||||
const char *label);
|
||||
const char *label);
|
||||
|
||||
enum strsplit {
|
||||
STR_EMPTY_OK,
|
||||
STR_NO_EMPTY
|
||||
STR_EMPTY_OK,
|
||||
STR_NO_EMPTY
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -115,33 +115,33 @@ enum strsplit {
|
||||
* return the number of elements plus 1 (for that NULL).
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/tal/str/str.h>
|
||||
* ...
|
||||
* static unsigned int count_long_lines(const char *string)
|
||||
* {
|
||||
* char **lines;
|
||||
* unsigned int i, long_lines = 0;
|
||||
* #include <ccan/tal/str/str.h>
|
||||
* ...
|
||||
* static unsigned int count_long_lines(const char *string)
|
||||
* {
|
||||
* char **lines;
|
||||
* unsigned int i, long_lines = 0;
|
||||
*
|
||||
* // Can only fail on out-of-memory.
|
||||
* lines = tal_strsplit(NULL, string, "\n", STR_NO_EMPTY);
|
||||
* for (i = 0; lines[i] != NULL; i++)
|
||||
* if (strlen(lines[i]) > 80)
|
||||
* long_lines++;
|
||||
* tal_free(lines);
|
||||
* return long_lines;
|
||||
* }
|
||||
* // Can only fail on out-of-memory.
|
||||
* lines = tal_strsplit(NULL, string, "\n", STR_NO_EMPTY);
|
||||
* for (i = 0; lines[i] != NULL; i++)
|
||||
* if (strlen(lines[i]) > 80)
|
||||
* long_lines++;
|
||||
* tal_free(lines);
|
||||
* return long_lines;
|
||||
* }
|
||||
*/
|
||||
#define tal_strsplit(ctx, string, delims, flag) \
|
||||
tal_strsplit_(ctx, string, delims, flag, TAL_LABEL(char *, "[]"))
|
||||
#define tal_strsplit(ctx, string, delims, flag) \
|
||||
tal_strsplit_(ctx, string, delims, flag, TAL_LABEL(char *, "[]"))
|
||||
char **tal_strsplit_(const tal_t *ctx,
|
||||
const char *string TAKES,
|
||||
const char *delims TAKES,
|
||||
enum strsplit flag,
|
||||
const char *label);
|
||||
const char *string TAKES,
|
||||
const char *delims TAKES,
|
||||
enum strsplit flag,
|
||||
const char *label);
|
||||
|
||||
enum strjoin {
|
||||
STR_TRAIL,
|
||||
STR_NO_TRAIL
|
||||
STR_TRAIL,
|
||||
STR_NO_TRAIL
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -158,24 +158,24 @@ enum strjoin {
|
||||
* The returned string will have tal_count() == strlen() + 1.
|
||||
*
|
||||
* Example:
|
||||
* // Append the string "--EOL" to each line.
|
||||
* static char *append_to_all_lines(const char *string)
|
||||
* {
|
||||
* char **lines, *ret;
|
||||
* // Append the string "--EOL" to each line.
|
||||
* static char *append_to_all_lines(const char *string)
|
||||
* {
|
||||
* char **lines, *ret;
|
||||
*
|
||||
* lines = tal_strsplit(NULL, string, "\n", STR_EMPTY_OK);
|
||||
* ret = tal_strjoin(NULL, lines, "-- EOL\n", STR_TRAIL);
|
||||
* tal_free(lines);
|
||||
* return ret;
|
||||
* }
|
||||
* lines = tal_strsplit(NULL, string, "\n", STR_EMPTY_OK);
|
||||
* ret = tal_strjoin(NULL, lines, "-- EOL\n", STR_TRAIL);
|
||||
* tal_free(lines);
|
||||
* return ret;
|
||||
* }
|
||||
*/
|
||||
#define tal_strjoin(ctx, strings, delim, flags) \
|
||||
tal_strjoin_(ctx, strings, delim, flags, TAL_LABEL(char, "[]"))
|
||||
#define tal_strjoin(ctx, strings, delim, flags) \
|
||||
tal_strjoin_(ctx, strings, delim, flags, TAL_LABEL(char, "[]"))
|
||||
char *tal_strjoin_(const void *ctx,
|
||||
char *strings[] TAKES,
|
||||
const char *delim TAKES,
|
||||
enum strjoin flags,
|
||||
const char *label);
|
||||
char *strings[] TAKES,
|
||||
const char *delim TAKES,
|
||||
enum strjoin flags,
|
||||
const char *label);
|
||||
|
||||
/**
|
||||
* tal_strreg - match/extract from a string via (extended) regular expressions.
|
||||
@@ -196,30 +196,30 @@ char *tal_strjoin_(const void *ctx,
|
||||
* The allocated strings will have tal_count() == strlen() + 1.
|
||||
*
|
||||
* See Also:
|
||||
* regcomp(3), regex(3).
|
||||
* regcomp(3), regex(3).
|
||||
*
|
||||
* Example:
|
||||
* // Given "My name is Rusty" outputs "Hello Rusty!\n"
|
||||
* // Given "my first name is Rusty Russell" outputs "Hello Rusty Russell!\n"
|
||||
* // Given "My name isnt Rusty Russell" outputs "Hello there!\n"
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *person, *input;
|
||||
* // Given "My name is Rusty" outputs "Hello Rusty!\n"
|
||||
* // Given "my first name is Rusty Russell" outputs "Hello Rusty Russell!\n"
|
||||
* // Given "My name isnt Rusty Russell" outputs "Hello there!\n"
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *person, *input;
|
||||
*
|
||||
* (void)argc;
|
||||
* // Join args and trim trailing space.
|
||||
* input = tal_strjoin(NULL, argv+1, " ", STR_NO_TRAIL);
|
||||
* if (tal_strreg(NULL, input,
|
||||
* "[Mm]y (first )?name is ([A-Za-z ]+)",
|
||||
* NULL, &person))
|
||||
* printf("Hello %s!\n", person);
|
||||
* else
|
||||
* printf("Hello there!\n");
|
||||
* return 0;
|
||||
* }
|
||||
* (void)argc;
|
||||
* // Join args and trim trailing space.
|
||||
* input = tal_strjoin(NULL, argv+1, " ", STR_NO_TRAIL);
|
||||
* if (tal_strreg(NULL, input,
|
||||
* "[Mm]y (first )?name is ([A-Za-z ]+)",
|
||||
* NULL, &person))
|
||||
* printf("Hello %s!\n", person);
|
||||
* else
|
||||
* printf("Hello there!\n");
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
#define tal_strreg(ctx, string, ...) \
|
||||
tal_strreg_(ctx, string, TAL_LABEL(char, "[]"), __VA_ARGS__)
|
||||
#define tal_strreg(ctx, string, ...) \
|
||||
tal_strreg_(ctx, string, TAL_LABEL(char, "[]"), __VA_ARGS__)
|
||||
bool tal_strreg_(const void *ctx, const char *string TAKES,
|
||||
const char *label, const char *regex, ...);
|
||||
const char *label, const char *regex, ...);
|
||||
#endif /* CCAN_STR_TAL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
/* Licensed under BSD-MIT - see LICENSE file for details */
|
||||
#ifndef CCAN_TAL_H
|
||||
#define CCAN_TAL_H
|
||||
#include "../config.h"
|
||||
#include "ccan/compiler/compiler.h"
|
||||
#include "ccan/likely/likely.h"
|
||||
#include "ccan/typesafe_cb/typesafe_cb.h"
|
||||
#include "ccan/str/str.h"
|
||||
#include "ccan/take/take.h"
|
||||
|
||||
#include "config.h"
|
||||
#include <ccan/compiler/compiler.h>
|
||||
#include <ccan/likely/likely.h>
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h>
|
||||
#include <ccan/str/str.h>
|
||||
#include <ccan/take/take.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
@@ -32,11 +31,11 @@ typedef void tal_t;
|
||||
* tal_count() of the return will be 1.
|
||||
*
|
||||
* Example:
|
||||
* int *p = tal(NULL, int);
|
||||
* *p = 1;
|
||||
* int *p = tal(NULL, int);
|
||||
* *p = 1;
|
||||
*/
|
||||
#define tal(ctx, type) \
|
||||
tal_label(ctx, type, TAL_LABEL(type, ""))
|
||||
#define tal(ctx, type) \
|
||||
tal_label(ctx, type, TAL_LABEL(type, ""))
|
||||
|
||||
/**
|
||||
* talz - zeroing allocator function
|
||||
@@ -46,11 +45,11 @@ typedef void tal_t;
|
||||
* Equivalent to tal() followed by memset() to zero.
|
||||
*
|
||||
* Example:
|
||||
* p = talz(NULL, int);
|
||||
* assert(*p == 0);
|
||||
* p = talz(NULL, int);
|
||||
* assert(*p == 0);
|
||||
*/
|
||||
#define talz(ctx, type) \
|
||||
talz_label(ctx, type, TAL_LABEL(type, ""))
|
||||
#define talz(ctx, type) \
|
||||
talz_label(ctx, type, TAL_LABEL(type, ""))
|
||||
|
||||
/**
|
||||
* tal_free - free a tal-allocated pointer.
|
||||
@@ -64,7 +63,7 @@ typedef void tal_t;
|
||||
* for any destructors or notifiers.
|
||||
*
|
||||
* Example:
|
||||
* p = tal_free(p);
|
||||
* p = tal_free(p);
|
||||
*/
|
||||
void *tal_free(const tal_t *p);
|
||||
|
||||
@@ -77,12 +76,12 @@ void *tal_free(const tal_t *p);
|
||||
* tal_count() of the returned pointer will be @count.
|
||||
*
|
||||
* Example:
|
||||
* p = tal_arr(NULL, int, 2);
|
||||
* p[0] = 0;
|
||||
* p[1] = 1;
|
||||
* p = tal_arr(NULL, int, 2);
|
||||
* p[0] = 0;
|
||||
* p[1] = 1;
|
||||
*/
|
||||
#define tal_arr(ctx, type, count) \
|
||||
tal_arr_label(ctx, type, count, TAL_LABEL(type, "[]"))
|
||||
#define tal_arr(ctx, type, count) \
|
||||
tal_arr_label(ctx, type, count, TAL_LABEL(type, "[]"))
|
||||
|
||||
/**
|
||||
* tal_arrz - allocate an array of zeroed objects.
|
||||
@@ -93,11 +92,11 @@ void *tal_free(const tal_t *p);
|
||||
* Equivalent to tal_arr() followed by memset() to zero.
|
||||
*
|
||||
* Example:
|
||||
* p = tal_arrz(NULL, int, 2);
|
||||
* assert(p[0] == 0 && p[1] == 0);
|
||||
* p = tal_arrz(NULL, int, 2);
|
||||
* assert(p[0] == 0 && p[1] == 0);
|
||||
*/
|
||||
#define tal_arrz(ctx, type, count) \
|
||||
tal_arrz_label(ctx, type, count, TAL_LABEL(type, "[]"))
|
||||
tal_arrz_label(ctx, type, count, TAL_LABEL(type, "[]"))
|
||||
|
||||
/**
|
||||
* tal_resize - enlarge or reduce a tal object.
|
||||
@@ -111,10 +110,10 @@ void *tal_free(const tal_t *p);
|
||||
* has been moved.
|
||||
*
|
||||
* Example:
|
||||
* tal_resize(&p, 100);
|
||||
* tal_resize(&p, 100);
|
||||
*/
|
||||
#define tal_resize(p, count) \
|
||||
tal_resize_((void **)(p), sizeof**(p), (count), false)
|
||||
tal_resize_((void **)(p), sizeof**(p), (count), false)
|
||||
|
||||
/**
|
||||
* tal_resizez - enlarge or reduce a tal object; zero out extra.
|
||||
@@ -124,10 +123,10 @@ void *tal_free(const tal_t *p);
|
||||
* This returns true on success (and may move *@p), or false on failure.
|
||||
*
|
||||
* Example:
|
||||
* tal_resizez(&p, 200);
|
||||
* tal_resizez(&p, 200);
|
||||
*/
|
||||
#define tal_resizez(p, count) \
|
||||
tal_resize_((void **)(p), sizeof**(p), (count), true)
|
||||
tal_resize_((void **)(p), sizeof**(p), (count), true)
|
||||
|
||||
/**
|
||||
* tal_steal - change the parent of a tal-allocated pointer.
|
||||
@@ -141,10 +140,10 @@ void *tal_free(const tal_t *p);
|
||||
#if HAVE_STATEMENT_EXPR
|
||||
/* Weird macro avoids gcc's 'warning: value computed is not used'. */
|
||||
#define tal_steal(ctx, ptr) \
|
||||
({ (tal_typeof(ptr) tal_steal_((ctx),(ptr))); })
|
||||
({ (tal_typeof(ptr) tal_steal_((ctx),(ptr))); })
|
||||
#else
|
||||
#define tal_steal(ctx, ptr) \
|
||||
(tal_typeof(ptr) tal_steal_((ctx),(ptr)))
|
||||
(tal_typeof(ptr) tal_steal_((ctx),(ptr)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -157,8 +156,8 @@ void *tal_free(const tal_t *p);
|
||||
*
|
||||
* Note that this can only fail if your allocfn fails and your errorfn returns.
|
||||
*/
|
||||
#define tal_add_destructor(ptr, function) \
|
||||
tal_add_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
#define tal_add_destructor(ptr, function) \
|
||||
tal_add_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
|
||||
/**
|
||||
* tal_del_destructor - remove a destructor callback function.
|
||||
@@ -169,8 +168,8 @@ void *tal_free(const tal_t *p);
|
||||
* false. Note that if we're inside the destructor call itself, this will
|
||||
* return false.
|
||||
*/
|
||||
#define tal_del_destructor(ptr, function) \
|
||||
tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
#define tal_del_destructor(ptr, function) \
|
||||
tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
|
||||
/**
|
||||
* tal_add_destructor2 - add a 2-arg callback function when context is destroyed.
|
||||
@@ -184,13 +183,13 @@ void *tal_free(const tal_t *p);
|
||||
*
|
||||
* Note that this can only fail if your allocfn fails and your errorfn returns.
|
||||
*/
|
||||
#define tal_add_destructor2(ptr, function, arg) \
|
||||
tal_add_destructor2_((ptr), \
|
||||
typesafe_cb_cast(void (*)(tal_t *, void *), \
|
||||
void (*)(__typeof__(ptr), \
|
||||
__typeof__(arg)), \
|
||||
(function)), \
|
||||
(arg))
|
||||
#define tal_add_destructor2(ptr, function, arg) \
|
||||
tal_add_destructor2_((ptr), \
|
||||
typesafe_cb_cast(void (*)(tal_t *, void *), \
|
||||
void (*)(__typeof__(ptr), \
|
||||
__typeof__(arg)), \
|
||||
(function)), \
|
||||
(arg))
|
||||
|
||||
/**
|
||||
* tal_del_destructor - remove a destructor callback function.
|
||||
@@ -201,8 +200,8 @@ void *tal_free(const tal_t *p);
|
||||
* false. Note that if we're inside the destructor call itself, this will
|
||||
* return false.
|
||||
*/
|
||||
#define tal_del_destructor(ptr, function) \
|
||||
tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
#define tal_del_destructor(ptr, function) \
|
||||
tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr)))
|
||||
|
||||
/**
|
||||
* tal_del_destructor2 - remove 2-arg callback function.
|
||||
@@ -213,23 +212,23 @@ void *tal_free(const tal_t *p);
|
||||
* If @function has not been successfully added as a destructor with
|
||||
* @arg, this returns false.
|
||||
*/
|
||||
#define tal_del_destructor2(ptr, function, arg) \
|
||||
tal_del_destructor2_((ptr), \
|
||||
typesafe_cb_cast(void (*)(tal_t *, void *), \
|
||||
void (*)(__typeof__(ptr), \
|
||||
__typeof__(arg)), \
|
||||
(function)), \
|
||||
(arg))
|
||||
#define tal_del_destructor2(ptr, function, arg) \
|
||||
tal_del_destructor2_((ptr), \
|
||||
typesafe_cb_cast(void (*)(tal_t *, void *), \
|
||||
void (*)(__typeof__(ptr), \
|
||||
__typeof__(arg)), \
|
||||
(function)), \
|
||||
(arg))
|
||||
enum tal_notify_type {
|
||||
TAL_NOTIFY_FREE = 1,
|
||||
TAL_NOTIFY_STEAL = 2,
|
||||
TAL_NOTIFY_MOVE = 4,
|
||||
TAL_NOTIFY_RESIZE = 8,
|
||||
TAL_NOTIFY_RENAME = 16,
|
||||
TAL_NOTIFY_ADD_CHILD = 32,
|
||||
TAL_NOTIFY_DEL_CHILD = 64,
|
||||
TAL_NOTIFY_ADD_NOTIFIER = 128,
|
||||
TAL_NOTIFY_DEL_NOTIFIER = 256
|
||||
TAL_NOTIFY_FREE = 1,
|
||||
TAL_NOTIFY_STEAL = 2,
|
||||
TAL_NOTIFY_MOVE = 4,
|
||||
TAL_NOTIFY_RESIZE = 8,
|
||||
TAL_NOTIFY_RENAME = 16,
|
||||
TAL_NOTIFY_ADD_CHILD = 32,
|
||||
TAL_NOTIFY_DEL_CHILD = 64,
|
||||
TAL_NOTIFY_ADD_NOTIFIER = 128,
|
||||
TAL_NOTIFY_DEL_NOTIFIER = 256
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -270,23 +269,23 @@ enum tal_notify_type {
|
||||
* callback. This is also called for tal_add_destructor and
|
||||
* tal_del_destructor.
|
||||
*/
|
||||
#define tal_add_notifier(ptr, types, callback) \
|
||||
tal_add_notifier_((ptr), (types), \
|
||||
typesafe_cb_postargs(void, tal_t *, (callback), \
|
||||
(ptr), \
|
||||
enum tal_notify_type, void *))
|
||||
#define tal_add_notifier(ptr, types, callback) \
|
||||
tal_add_notifier_((ptr), (types), \
|
||||
typesafe_cb_postargs(void, tal_t *, (callback), \
|
||||
(ptr), \
|
||||
enum tal_notify_type, void *))
|
||||
|
||||
/**
|
||||
* tal_del_notifier - remove a notifier callback function.
|
||||
* @ptr: The tal allocated object.
|
||||
* @callback: the function to call.
|
||||
*/
|
||||
#define tal_del_notifier(ptr, callback) \
|
||||
tal_del_notifier_((ptr), \
|
||||
typesafe_cb_postargs(void, void *, (callback), \
|
||||
(ptr), \
|
||||
enum tal_notify_type, void *), \
|
||||
false, NULL)
|
||||
#define tal_del_notifier(ptr, callback) \
|
||||
tal_del_notifier_((ptr), \
|
||||
typesafe_cb_postargs(void, void *, (callback), \
|
||||
(ptr), \
|
||||
enum tal_notify_type, void *), \
|
||||
false, NULL)
|
||||
|
||||
/**
|
||||
* tal_set_name - attach a name to a tal pointer.
|
||||
@@ -295,7 +294,7 @@ enum tal_notify_type {
|
||||
*
|
||||
* The name is copied, unless we're certain it's a string literal.
|
||||
*/
|
||||
#define tal_set_name(ptr, name) \
|
||||
#define tal_set_name(ptr, name) \
|
||||
tal_set_name_((ptr), (name), TAL_IS_LITERAL(name))
|
||||
|
||||
/**
|
||||
@@ -355,8 +354,8 @@ tal_t *tal_parent(const tal_t *ctx);
|
||||
* @type: the type (should match type of @p!)
|
||||
* @p: the object to copy (or reparented if take()). Must not be NULL.
|
||||
*/
|
||||
#define tal_dup(ctx, type, p) \
|
||||
tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), false)
|
||||
#define tal_dup(ctx, type, p) \
|
||||
tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), false)
|
||||
|
||||
/**
|
||||
* tal_dup_or_null - duplicate an object, or just pass NULL.
|
||||
@@ -366,8 +365,8 @@ tal_t *tal_parent(const tal_t *ctx);
|
||||
*
|
||||
* if @p is NULL, just return NULL, otherwise to tal_dup().
|
||||
*/
|
||||
#define tal_dup_or_null(ctx, type, p) \
|
||||
tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), true)
|
||||
#define tal_dup_or_null(ctx, type, p) \
|
||||
tal_dup_label(ctx, type, p, TAL_LABEL(type, ""), true)
|
||||
|
||||
/**
|
||||
* tal_dup_arr - duplicate an array.
|
||||
@@ -377,8 +376,8 @@ tal_t *tal_parent(const tal_t *ctx);
|
||||
* @n: the number of sizeof(type) entries to copy.
|
||||
* @extra: the number of extra sizeof(type) entries to allocate.
|
||||
*/
|
||||
#define tal_dup_arr(ctx, type, p, n, extra) \
|
||||
tal_dup_arr_label(ctx, type, p, n, extra, TAL_LABEL(type, "[]"))
|
||||
#define tal_dup_arr(ctx, type, p, n, extra) \
|
||||
tal_dup_arr_label(ctx, type, p, n, extra, TAL_LABEL(type, "[]"))
|
||||
|
||||
|
||||
/**
|
||||
@@ -387,28 +386,28 @@ tal_t *tal_parent(const tal_t *ctx);
|
||||
* @type: the type (should match type of @p!)
|
||||
* @p: the tal array to copy (or resized & reparented if take())
|
||||
*
|
||||
* The common case of duplicating an entire tal array.
|
||||
* The comon case of duplicating an entire tal array.
|
||||
*/
|
||||
#define tal_dup_talarr(ctx, type, p) \
|
||||
((type *)tal_dup_talarr_((ctx), tal_typechk_(p, type *), \
|
||||
TAL_LABEL(type, "[]")))
|
||||
#define tal_dup_talarr(ctx, type, p) \
|
||||
((type *)tal_dup_talarr_((ctx), tal_typechk_(p, type *), \
|
||||
TAL_LABEL(type, "[]")))
|
||||
/* Lower-level interfaces, where you want to supply your own label string. */
|
||||
#define tal_label(ctx, type, label) \
|
||||
((type *)tal_alloc_((ctx), sizeof(type), false, label))
|
||||
#define talz_label(ctx, type, label) \
|
||||
((type *)tal_alloc_((ctx), sizeof(type), true, label))
|
||||
#define tal_arr_label(ctx, type, count, label) \
|
||||
((type *)tal_alloc_arr_((ctx), sizeof(type), (count), false, label))
|
||||
#define tal_arrz_label(ctx, type, count, label) \
|
||||
((type *)tal_alloc_arr_((ctx), sizeof(type), (count), true, label))
|
||||
#define tal_dup_label(ctx, type, p, label, nullok) \
|
||||
((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
|
||||
sizeof(type), 1, 0, nullok, \
|
||||
label))
|
||||
#define tal_dup_arr_label(ctx, type, p, n, extra, label) \
|
||||
((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
|
||||
sizeof(type), (n), (extra), false, \
|
||||
label))
|
||||
#define tal_label(ctx, type, label) \
|
||||
((type *)tal_alloc_((ctx), sizeof(type), false, label))
|
||||
#define talz_label(ctx, type, label) \
|
||||
((type *)tal_alloc_((ctx), sizeof(type), true, label))
|
||||
#define tal_arr_label(ctx, type, count, label) \
|
||||
((type *)tal_alloc_arr_((ctx), sizeof(type), (count), false, label))
|
||||
#define tal_arrz_label(ctx, type, count, label) \
|
||||
((type *)tal_alloc_arr_((ctx), sizeof(type), (count), true, label))
|
||||
#define tal_dup_label(ctx, type, p, label, nullok) \
|
||||
((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
|
||||
sizeof(type), 1, 0, nullok, \
|
||||
label))
|
||||
#define tal_dup_arr_label(ctx, type, p, n, extra, label) \
|
||||
((type *)tal_dup_((ctx), tal_typechk_(p, type *), \
|
||||
sizeof(type), (n), (extra), false, \
|
||||
label))
|
||||
|
||||
/**
|
||||
* tal_set_backend - set the allocation or error functions to use
|
||||
@@ -418,15 +417,15 @@ tal_t *tal_parent(const tal_t *ctx);
|
||||
* @error_fn: called on errors or NULL (default is abort)
|
||||
*
|
||||
* The defaults are set up so tal functions never return NULL, but you
|
||||
* can override error_fn to change that. error_fn can return, and is
|
||||
* can override erorr_fn to change that. error_fn can return, and is
|
||||
* called if alloc_fn or resize_fn fail.
|
||||
*
|
||||
* If any parameter is NULL, that function is unchanged.
|
||||
*/
|
||||
void tal_set_backend(void *(*alloc_fn)(size_t size),
|
||||
void *(*resize_fn)(void *, size_t size),
|
||||
void (*free_fn)(void *),
|
||||
void (*error_fn)(const char *msg));
|
||||
void *(*resize_fn)(void *, size_t size),
|
||||
void (*free_fn)(void *),
|
||||
void (*error_fn)(const char *msg));
|
||||
|
||||
/**
|
||||
* tal_expand - expand a tal array with contents.
|
||||
@@ -438,17 +437,17 @@ void tal_set_backend(void *(*alloc_fn)(size_t size),
|
||||
* be increased by @num2.
|
||||
*
|
||||
* Example:
|
||||
* int *arr1 = tal_arrz(NULL, int, 2);
|
||||
* int arr2[2] = { 1, 3 };
|
||||
* int *arr1 = tal_arrz(NULL, int, 2);
|
||||
* int arr2[2] = { 1, 3 };
|
||||
*
|
||||
* tal_expand(&arr1, arr2, 2);
|
||||
* assert(tal_count(arr1) == 4);
|
||||
* assert(arr1[2] == 1);
|
||||
* assert(arr1[3] == 3);
|
||||
* tal_expand(&arr1, arr2, 2);
|
||||
* assert(tal_count(arr1) == 4);
|
||||
* assert(arr1[2] == 1);
|
||||
* assert(arr1[3] == 3);
|
||||
*/
|
||||
#define tal_expand(a1p, a2, num2) \
|
||||
tal_expand_((void **)(a1p), (a2), sizeof**(a1p), \
|
||||
(num2) + 0*sizeof(*(a1p) == (a2)))
|
||||
#define tal_expand(a1p, a2, num2) \
|
||||
tal_expand_((void **)(a1p), (a2), sizeof**(a1p), \
|
||||
(num2) + 0*sizeof(*(a1p) == (a2)))
|
||||
|
||||
/**
|
||||
* tal_cleanup - remove pointers from NULL node
|
||||
@@ -472,7 +471,7 @@ void tal_cleanup(void);
|
||||
* when a problem is found, otherwise it is not.
|
||||
*
|
||||
* See also:
|
||||
* tal_set_backend()
|
||||
* tal_set_backend()
|
||||
*/
|
||||
bool tal_check(const tal_t *ctx, const char *errorstr);
|
||||
|
||||
@@ -493,7 +492,7 @@ void tal_dump(void);
|
||||
#else
|
||||
#ifdef CCAN_TAL_DEBUG
|
||||
#define TAL_LABEL(type, arr) \
|
||||
__FILE__ ":" stringify(__LINE__) ":" stringify(type) arr
|
||||
__FILE__ ":" stringify(__LINE__) ":" stringify(type) arr
|
||||
#else
|
||||
#define TAL_LABEL(type, arr) stringify(type) arr
|
||||
#endif /* CCAN_TAL_DEBUG */
|
||||
@@ -524,12 +523,12 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal);
|
||||
|
||||
void *tal_alloc_(const tal_t *ctx, size_t bytes, bool clear, const char *label);
|
||||
void *tal_alloc_arr_(const tal_t *ctx, size_t bytes, size_t count, bool clear,
|
||||
const char *label);
|
||||
const char *label);
|
||||
|
||||
void *tal_dup_(const tal_t *ctx, const void *p TAKES, size_t size,
|
||||
size_t n, size_t extra, bool nullok, const char *label);
|
||||
size_t n, size_t extra, bool nullok, const char *label);
|
||||
void *tal_dup_talarr_(const tal_t *ctx, const tal_t *src TAKES,
|
||||
const char *label);
|
||||
const char *label);
|
||||
|
||||
tal_t *tal_steal_(const tal_t *new_parent, const tal_t *t);
|
||||
|
||||
@@ -538,16 +537,16 @@ bool tal_expand_(tal_t **ctxp, const void *src TAKES, size_t size, size_t count)
|
||||
|
||||
bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me));
|
||||
bool tal_add_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
|
||||
void *arg);
|
||||
void *arg);
|
||||
bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me));
|
||||
bool tal_del_destructor2_(const tal_t *ctx, void (*destroy)(void *me, void *arg),
|
||||
void *arg);
|
||||
void *arg);
|
||||
|
||||
bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
|
||||
void (*notify)(tal_t *ctx, enum tal_notify_type,
|
||||
void *info));
|
||||
void (*notify)(tal_t *ctx, enum tal_notify_type,
|
||||
void *info));
|
||||
bool tal_del_notifier_(const tal_t *ctx,
|
||||
void (*notify)(tal_t *ctx, enum tal_notify_type,
|
||||
void *info),
|
||||
bool match_extra_arg, void *arg);
|
||||
void (*notify)(tal_t *ctx, enum tal_notify_type,
|
||||
void *info),
|
||||
bool match_extra_arg, void *arg);
|
||||
#endif /* CCAN_TAL_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/typesafe_cb/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/typesafe_cb/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/CC0
|
||||
151
nostrdb/ccan/ccan/typesafe_cb/_info
Normal file
151
nostrdb/ccan/ccan/typesafe_cb/_info
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* typesafe_cb - macros for safe callbacks.
|
||||
*
|
||||
* The basis of the typesafe_cb header is typesafe_cb_cast(): a
|
||||
* conditional cast macro. If an expression exactly matches a given
|
||||
* type, it is cast to the target type, otherwise it is left alone.
|
||||
*
|
||||
* This allows us to create functions which take a small number of
|
||||
* specific types, rather than being forced to use a void *. In
|
||||
* particular, it is useful for creating typesafe callbacks as the
|
||||
* helpers typesafe_cb(), typesafe_cb_preargs() and
|
||||
* typesafe_cb_postargs() demonstrate.
|
||||
*
|
||||
* The standard way of passing arguments to callback functions in C is
|
||||
* to use a void pointer, which the callback then casts back to the
|
||||
* expected type. This unfortunately subverts the type checking the
|
||||
* compiler would perform if it were a direct call. Here's an example:
|
||||
*
|
||||
* static void my_callback(void *_obj)
|
||||
* {
|
||||
* struct obj *obj = _obj;
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* register_callback(my_callback, &my_obj);
|
||||
*
|
||||
* If we wanted to use the natural type for my_callback (ie. "void
|
||||
* my_callback(struct obj *obj)"), we could make register_callback()
|
||||
* take a void * as its first argument, but this would subvert all
|
||||
* type checking. We really want register_callback() to accept only
|
||||
* the exactly correct function type to match the argument, or a
|
||||
* function which takes a void *.
|
||||
*
|
||||
* This is where typesafe_cb() comes in: it uses typesafe_cb_cast() to
|
||||
* cast the callback function if it matches the argument type:
|
||||
*
|
||||
* void _register_callback(void (*cb)(void *arg), void *arg);
|
||||
* #define register_callback(cb, arg) \
|
||||
* _register_callback(typesafe_cb(void, void *, (cb), (arg)), \
|
||||
* (arg))
|
||||
*
|
||||
* On compilers which don't support the extensions required
|
||||
* typesafe_cb_cast() and friend become an unconditional cast, so your
|
||||
* code will compile but you won't get type checking.
|
||||
*
|
||||
* Example:
|
||||
* #include <ccan/typesafe_cb/typesafe_cb.h>
|
||||
* #include <stdlib.h>
|
||||
* #include <stdio.h>
|
||||
*
|
||||
* // Generic callback infrastructure.
|
||||
* struct callback {
|
||||
* struct callback *next;
|
||||
* int value;
|
||||
* int (*callback)(int value, void *arg);
|
||||
* void *arg;
|
||||
* };
|
||||
* static struct callback *callbacks;
|
||||
*
|
||||
* static void _register_callback(int value, int (*cb)(int, void *),
|
||||
* void *arg)
|
||||
* {
|
||||
* struct callback *new = malloc(sizeof(*new));
|
||||
* new->next = callbacks;
|
||||
* new->value = value;
|
||||
* new->callback = cb;
|
||||
* new->arg = arg;
|
||||
* callbacks = new;
|
||||
* }
|
||||
* #define register_callback(value, cb, arg) \
|
||||
* _register_callback(value, \
|
||||
* typesafe_cb_preargs(int, void *, \
|
||||
* (cb), (arg), int),\
|
||||
* (arg))
|
||||
*
|
||||
* static struct callback *find_callback(int value)
|
||||
* {
|
||||
* struct callback *i;
|
||||
*
|
||||
* for (i = callbacks; i; i = i->next)
|
||||
* if (i->value == value)
|
||||
* return i;
|
||||
* return NULL;
|
||||
* }
|
||||
*
|
||||
* // Define several silly callbacks. Note they don't use void *!
|
||||
* #define DEF_CALLBACK(name, op) \
|
||||
* static int name(int val, int *arg) \
|
||||
* { \
|
||||
* printf("%s", #op); \
|
||||
* return val op *arg; \
|
||||
* }
|
||||
* DEF_CALLBACK(multiply, *);
|
||||
* DEF_CALLBACK(add, +);
|
||||
* DEF_CALLBACK(divide, /);
|
||||
* DEF_CALLBACK(sub, -);
|
||||
* DEF_CALLBACK(or, |);
|
||||
* DEF_CALLBACK(and, &);
|
||||
* DEF_CALLBACK(xor, ^);
|
||||
* DEF_CALLBACK(assign, =);
|
||||
*
|
||||
* // Silly game to find the longest chain of values.
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* int i, run = 1, num = argc > 1 ? atoi(argv[1]) : 0;
|
||||
*
|
||||
* for (i = 1; i < 1024;) {
|
||||
* // Since run is an int, compiler checks "add" does too.
|
||||
* register_callback(i++, add, &run);
|
||||
* register_callback(i++, divide, &run);
|
||||
* register_callback(i++, sub, &run);
|
||||
* register_callback(i++, multiply, &run);
|
||||
* register_callback(i++, or, &run);
|
||||
* register_callback(i++, and, &run);
|
||||
* register_callback(i++, xor, &run);
|
||||
* register_callback(i++, assign, &run);
|
||||
* }
|
||||
*
|
||||
* printf("%i ", num);
|
||||
* while (run < 56) {
|
||||
* struct callback *cb = find_callback(num % i);
|
||||
* if (!cb) {
|
||||
* printf("-> STOP\n");
|
||||
* return 1;
|
||||
* }
|
||||
* num = cb->callback(num, cb->arg);
|
||||
* printf("->%i ", num);
|
||||
* run++;
|
||||
* }
|
||||
* printf("-> Winner!\n");
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: CC0 (Public domain)
|
||||
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* CC0 (Public domain) - see LICENSE file for details */
|
||||
#ifndef CCAN_TYPESAFE_CB_H
|
||||
#define CCAN_TYPESAFE_CB_H
|
||||
#include "../config.h"
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
|
||||
/**
|
||||
@@ -24,16 +24,16 @@
|
||||
* "typeof": it will not be evaluated if typeof is not supported.
|
||||
*
|
||||
* Example:
|
||||
* // 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)))
|
||||
* // 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)))
|
||||
*/
|
||||
#define typesafe_cb_cast(desttype, oktype, expr) \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \
|
||||
oktype), \
|
||||
(desttype)(expr), (expr))
|
||||
#define typesafe_cb_cast(desttype, oktype, expr) \
|
||||
__builtin_choose_expr( \
|
||||
__builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \
|
||||
oktype), \
|
||||
(desttype)(expr), (expr))
|
||||
#else
|
||||
#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr))
|
||||
#endif
|
||||
@@ -51,18 +51,18 @@
|
||||
* for expr) if you need more than 3 arguments.
|
||||
*
|
||||
* Example:
|
||||
* // We can take either a long, unsigned long, void * or a const void *.
|
||||
* void _set_some_value(void *val);
|
||||
* #define set_some_value(expr) \
|
||||
* _set_some_value(typesafe_cb_cast3(void *,, \
|
||||
* long, unsigned long, const void *,\
|
||||
* (expr)))
|
||||
* // We can take either a long, unsigned long, void * or a const void *.
|
||||
* void _set_some_value(void *val);
|
||||
* #define set_some_value(expr) \
|
||||
* _set_some_value(typesafe_cb_cast3(void *,, \
|
||||
* long, unsigned long, const void *,\
|
||||
* (expr)))
|
||||
*/
|
||||
#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \
|
||||
typesafe_cb_cast(desttype, ok1, \
|
||||
typesafe_cb_cast(desttype, ok2, \
|
||||
typesafe_cb_cast(desttype, ok3, \
|
||||
(expr))))
|
||||
#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \
|
||||
typesafe_cb_cast(desttype, ok1, \
|
||||
typesafe_cb_cast(desttype, ok2, \
|
||||
typesafe_cb_cast(desttype, ok3, \
|
||||
(expr))))
|
||||
|
||||
/**
|
||||
* typesafe_cb - cast a callback function if it matches the arg
|
||||
@@ -79,14 +79,14 @@
|
||||
* or assigned to a void * elsewhere anyway.
|
||||
*
|
||||
* Example:
|
||||
* void _register_callback(void (*fn)(void *arg), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg))
|
||||
* void _register_callback(void (*fn)(void *arg), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg))
|
||||
*/
|
||||
#define typesafe_cb(rtype, atype, fn, arg) \
|
||||
typesafe_cb_cast(rtype (*)(atype), \
|
||||
rtype (*)(__typeof__(arg)), \
|
||||
(fn))
|
||||
#define typesafe_cb(rtype, atype, fn, arg) \
|
||||
typesafe_cb_cast(rtype (*)(atype), \
|
||||
rtype (*)(__typeof__(arg)), \
|
||||
(fn))
|
||||
|
||||
/**
|
||||
* typesafe_cb_preargs - cast a callback function if it matches the arg
|
||||
@@ -99,16 +99,16 @@
|
||||
* before the @arg.
|
||||
*
|
||||
* Example:
|
||||
* void _register_callback(void (*fn)(int, void *arg), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb_preargs(void, void *, \
|
||||
* (fn), (arg), int), \
|
||||
* (arg))
|
||||
* void _register_callback(void (*fn)(int, void *arg), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb_preargs(void, void *, \
|
||||
* (fn), (arg), int), \
|
||||
* (arg))
|
||||
*/
|
||||
#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \
|
||||
typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \
|
||||
rtype (*)(__VA_ARGS__, __typeof__(arg)), \
|
||||
(fn))
|
||||
#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \
|
||||
typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \
|
||||
rtype (*)(__VA_ARGS__, __typeof__(arg)), \
|
||||
(fn))
|
||||
|
||||
/**
|
||||
* typesafe_cb_postargs - cast a callback function if it matches the arg
|
||||
@@ -121,14 +121,14 @@
|
||||
* after the @arg.
|
||||
*
|
||||
* Example:
|
||||
* void _register_callback(void (*fn)(void *arg, int), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb_postargs(void, (fn), void *, \
|
||||
* (arg), int), \
|
||||
* (arg))
|
||||
* void _register_callback(void (*fn)(void *arg, int), void *arg);
|
||||
* #define register_callback(fn, arg) \
|
||||
* _register_callback(typesafe_cb_postargs(void, (fn), void *, \
|
||||
* (arg), int), \
|
||||
* (arg))
|
||||
*/
|
||||
#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \
|
||||
typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \
|
||||
rtype (*)(__typeof__(arg), __VA_ARGS__), \
|
||||
(fn))
|
||||
#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \
|
||||
typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \
|
||||
rtype (*)(__typeof__(arg), __VA_ARGS__), \
|
||||
(fn))
|
||||
#endif /* CCAN_CAST_IF_TYPE_H */
|
||||
|
||||
1
nostrdb/ccan/ccan/utf8/LICENSE
Symbolic link
1
nostrdb/ccan/ccan/utf8/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
||||
48
nostrdb/ccan/ccan/utf8/_info
Normal file
48
nostrdb/ccan/ccan/utf8/_info
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* utf8 - Simple routines to encode/decode valid UTF-8.
|
||||
*
|
||||
* This code contains routines to encode and decode UTF-8 characters.
|
||||
* Table and test code stolen entirely from:
|
||||
* Copyright (c) 2017 Christian Hansen <chansen@cpan.org>
|
||||
* <https://github.com/chansen/c-utf8-valid>
|
||||
*
|
||||
* Example:
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* size_t i;
|
||||
* struct utf8_state utf8_state = UTF8_STATE_INIT;
|
||||
* bool decoded = true;
|
||||
*
|
||||
* for (i = 0; i < strlen(argv[1]); i++) {
|
||||
* decoded = utf8_decode(&utf8_state, argv[1][i]);
|
||||
* if (decoded) {
|
||||
* if (errno != 0)
|
||||
* err(1, "Invalid UTF8 char %zu-%zu",
|
||||
* i - utf8_state.used_len, i);
|
||||
* printf("Character %u\n", utf8_state.c);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* if (!decoded)
|
||||
* errx(1, "Incomplete UTF8");
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* Expect exactly one argument */
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
if (strcmp(argv[1], "depends") == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
/* MIT (BSD) license - see LICENSE file for details - taken from ccan. thanks rusty! */
|
||||
|
||||
#include "utf8.h"
|
||||
/* MIT (BSD) license - see LICENSE file for details */
|
||||
#include <ccan/utf8/utf8.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -33,10 +32,10 @@
|
||||
/*
|
||||
* UTF-8 Encoding Form
|
||||
*
|
||||
* U+0000..U+007F 0xxxxxxx <= 7 bits
|
||||
* U+0080..U+07FF 110xxxxx 10xxxxxx <= 11 bits
|
||||
* U+0800..U+FFFF 1110xxxx 10xxxxxx 10xxxxxx <= 16 bits
|
||||
* U+10000..U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx <= 21 bits
|
||||
* U+0000..U+007F 0xxxxxxx <= 7 bits
|
||||
* U+0080..U+07FF 110xxxxx 10xxxxxx <= 11 bits
|
||||
* U+0800..U+FFFF 1110xxxx 10xxxxxx 10xxxxxx <= 16 bits
|
||||
* U+10000..U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx <= 21 bits
|
||||
*
|
||||
*
|
||||
* U+0000..U+007F 00..7F
|
||||
@@ -59,122 +58,121 @@
|
||||
*/
|
||||
bool utf8_decode(struct utf8_state *utf8_state, char c)
|
||||
{
|
||||
if (utf8_state->used_len == utf8_state->total_len) {
|
||||
utf8_state->used_len = 1;
|
||||
/* First character in sequence. */
|
||||
if (((unsigned char)c & 0x80) == 0) {
|
||||
/* ASCII, easy. */
|
||||
if (c == 0)
|
||||
goto bad_encoding;
|
||||
utf8_state->total_len = 1;
|
||||
utf8_state->c = c;
|
||||
goto finished_decoding;
|
||||
} else if (((unsigned char)c & 0xE0) == 0xC0) {
|
||||
utf8_state->total_len = 2;
|
||||
utf8_state->c = ((unsigned char)c & 0x1F);
|
||||
return false;
|
||||
} else if (((unsigned char)c & 0xF0) == 0xE0) {
|
||||
utf8_state->total_len = 3;
|
||||
utf8_state->c = ((unsigned char)c & 0x0F);
|
||||
return false;
|
||||
} else if (((unsigned char)c & 0xF8) == 0xF0) {
|
||||
utf8_state->total_len = 4;
|
||||
utf8_state->c = ((unsigned char)c & 0x07);
|
||||
return false;
|
||||
}
|
||||
goto bad_encoding;
|
||||
}
|
||||
if (utf8_state->used_len == utf8_state->total_len) {
|
||||
utf8_state->used_len = 1;
|
||||
/* First character in sequence. */
|
||||
if (((unsigned char)c & 0x80) == 0) {
|
||||
/* ASCII, easy. */
|
||||
if (c == 0)
|
||||
goto bad_encoding;
|
||||
utf8_state->total_len = 1;
|
||||
utf8_state->c = c;
|
||||
goto finished_decoding;
|
||||
} else if (((unsigned char)c & 0xE0) == 0xC0) {
|
||||
utf8_state->total_len = 2;
|
||||
utf8_state->c = ((unsigned char)c & 0x1F);
|
||||
return false;
|
||||
} else if (((unsigned char)c & 0xF0) == 0xE0) {
|
||||
utf8_state->total_len = 3;
|
||||
utf8_state->c = ((unsigned char)c & 0x0F);
|
||||
return false;
|
||||
} else if (((unsigned char)c & 0xF8) == 0xF0) {
|
||||
utf8_state->total_len = 4;
|
||||
utf8_state->c = ((unsigned char)c & 0x07);
|
||||
return false;
|
||||
}
|
||||
goto bad_encoding;
|
||||
}
|
||||
|
||||
if (((unsigned char)c & 0xC0) != 0x80)
|
||||
goto bad_encoding;
|
||||
if (((unsigned char)c & 0xC0) != 0x80)
|
||||
goto bad_encoding;
|
||||
|
||||
utf8_state->c <<= 6;
|
||||
utf8_state->c |= ((unsigned char)c & 0x3F);
|
||||
|
||||
utf8_state->used_len++;
|
||||
if (utf8_state->used_len == utf8_state->total_len)
|
||||
goto finished_decoding;
|
||||
return false;
|
||||
utf8_state->c <<= 6;
|
||||
utf8_state->c |= ((unsigned char)c & 0x3F);
|
||||
|
||||
utf8_state->used_len++;
|
||||
if (utf8_state->used_len == utf8_state->total_len)
|
||||
goto finished_decoding;
|
||||
return false;
|
||||
|
||||
finished_decoding:
|
||||
if (utf8_state->c == 0 || utf8_state->c > 0x10FFFF)
|
||||
errno = ERANGE;
|
||||
/* The UTF-16 "surrogate range": illegal in UTF-8 */
|
||||
else if (utf8_state->total_len == 3
|
||||
&& (utf8_state->c & 0xFFFFF800) == 0x0000D800)
|
||||
errno = ERANGE;
|
||||
else {
|
||||
int min_bits;
|
||||
switch (utf8_state->total_len) {
|
||||
case 1:
|
||||
min_bits = 0;
|
||||
break;
|
||||
case 2:
|
||||
min_bits = 7;
|
||||
break;
|
||||
case 3:
|
||||
min_bits = 11;
|
||||
break;
|
||||
case 4:
|
||||
min_bits = 16;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if ((utf8_state->c >> min_bits) == 0)
|
||||
errno = EFBIG;
|
||||
else
|
||||
errno = 0;
|
||||
}
|
||||
return true;
|
||||
if (utf8_state->c == 0 || utf8_state->c > 0x10FFFF)
|
||||
errno = ERANGE;
|
||||
/* The UTF-16 "surrogate range": illegal in UTF-8 */
|
||||
else if (utf8_state->total_len == 3
|
||||
&& (utf8_state->c & 0xFFFFF800) == 0x0000D800)
|
||||
errno = ERANGE;
|
||||
else {
|
||||
int min_bits;
|
||||
switch (utf8_state->total_len) {
|
||||
case 1:
|
||||
min_bits = 0;
|
||||
break;
|
||||
case 2:
|
||||
min_bits = 7;
|
||||
break;
|
||||
case 3:
|
||||
min_bits = 11;
|
||||
break;
|
||||
case 4:
|
||||
min_bits = 16;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
if ((utf8_state->c >> min_bits) == 0)
|
||||
errno = EFBIG;
|
||||
else
|
||||
errno = 0;
|
||||
}
|
||||
return true;
|
||||
|
||||
bad_encoding:
|
||||
utf8_state->total_len = utf8_state->used_len;
|
||||
errno = EINVAL;
|
||||
return true;
|
||||
utf8_state->total_len = utf8_state->used_len;
|
||||
errno = EINVAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t utf8_encode(uint32_t point, char dest[UTF8_MAX_LEN])
|
||||
{
|
||||
if ((point >> 7) == 0) {
|
||||
if (point == 0) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
/* 0xxxxxxx */
|
||||
dest[0] = point;
|
||||
return 1;
|
||||
}
|
||||
if ((point >> 7) == 0) {
|
||||
if (point == 0) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
/* 0xxxxxxx */
|
||||
dest[0] = point;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((point >> 11) == 0) {
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
dest[1] = 0x80 | (point & 0x3F);
|
||||
dest[0] = 0xC0 | (point >> 6);
|
||||
return 2;
|
||||
}
|
||||
if ((point >> 11) == 0) {
|
||||
/* 110xxxxx 10xxxxxx */
|
||||
dest[1] = 0x80 | (point & 0x3F);
|
||||
dest[0] = 0xC0 | (point >> 6);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if ((point >> 16) == 0) {
|
||||
if (point >= 0xD800 && point <= 0xDFFF) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
dest[2] = 0x80 | (point & 0x3F);
|
||||
dest[1] = 0x80 | ((point >> 6) & 0x3F);
|
||||
dest[0] = 0xE0 | (point >> 12);
|
||||
return 3;
|
||||
}
|
||||
if ((point >> 16) == 0) {
|
||||
if (point >= 0xD800 && point <= 0xDFFF) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
/* 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
dest[2] = 0x80 | (point & 0x3F);
|
||||
dest[1] = 0x80 | ((point >> 6) & 0x3F);
|
||||
dest[0] = 0xE0 | (point >> 12);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (point > 0x10FFFF) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
if (point > 0x10FFFF) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
dest[3] = 0x80 | (point & 0x3F);
|
||||
dest[2] = 0x80 | ((point >> 6) & 0x3F);
|
||||
dest[1] = 0x80 | ((point >> 12) & 0x3F);
|
||||
dest[0] = 0xF0 | (point >> 18);
|
||||
return 4;
|
||||
/* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
dest[3] = 0x80 | (point & 0x3F);
|
||||
dest[2] = 0x80 | ((point >> 6) & 0x3F);
|
||||
dest[1] = 0x80 | ((point >> 12) & 0x3F);
|
||||
dest[0] = 0xF0 | (point >> 18);
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
#include <string.h>
|
||||
|
||||
/* Unicode is limited to 21 bits. */
|
||||
#define UTF8_MAX_LEN 4
|
||||
#define UTF8_MAX_LEN 4
|
||||
|
||||
struct utf8_state {
|
||||
/* How many characters we are expecting as part of this Unicode point */
|
||||
uint16_t total_len;
|
||||
/* How many characters we've already seen. */
|
||||
uint16_t used_len;
|
||||
/* Compound character, aka Unicode point. */
|
||||
uint32_t c;
|
||||
/* How many characters we are expecting as part of this Unicode point */
|
||||
uint16_t total_len;
|
||||
/* How many characters we've already seen. */
|
||||
uint16_t used_len;
|
||||
/* Compound character, aka Unicode point. */
|
||||
uint32_t c;
|
||||
};
|
||||
|
||||
#define UTF8_STATE_INIT { 0, 0, 0 }
|
||||
|
||||
static inline void utf8_state_init(struct utf8_state *utf8_state)
|
||||
{
|
||||
memset(utf8_state, 0, sizeof(*utf8_state));
|
||||
memset(utf8_state, 0, sizeof(*utf8_state));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,5 +51,4 @@ bool utf8_decode(struct utf8_state *utf8_state, char c);
|
||||
* Sets errno to ERANGE if point was invalid.
|
||||
*/
|
||||
size_t utf8_encode(uint32_t point, char dest[UTF8_MAX_LEN]);
|
||||
|
||||
#endif /* CCAN_UTF8_H */
|
||||
|
||||
17
nostrdb/ccan/licenses/BSD-MIT
Normal file
17
nostrdb/ccan/licenses/BSD-MIT
Normal file
@@ -0,0 +1,17 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
28
nostrdb/ccan/licenses/CC0
Normal file
28
nostrdb/ccan/licenses/CC0
Normal file
@@ -0,0 +1,28 @@
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||
|
||||
the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||
moral rights retained by the original author(s) and/or performer(s);
|
||||
publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||
rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||
rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||
database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||
other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||
Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||
Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||
Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||
510
nostrdb/ccan/licenses/LGPL-2.1
Normal file
510
nostrdb/ccan/licenses/LGPL-2.1
Normal file
@@ -0,0 +1,510 @@
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations
|
||||
below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it
|
||||
becomes a de-facto standard. To achieve this, non-free programs must
|
||||
be allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control
|
||||
compilation and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at least
|
||||
three years, to give the same user the materials specified in
|
||||
Subsection 6a, above, for a charge no more than the cost of
|
||||
performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply, and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License
|
||||
may add an explicit geographical distribution limitation excluding those
|
||||
countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms
|
||||
of the ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library.
|
||||
It is safest to attach them to the start of each source file to most
|
||||
effectively convey the exclusion of warranty; and each file should
|
||||
have at least the "copyright" line and a pointer to where the full
|
||||
notice is found.
|
||||
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or
|
||||
your school, if any, to sign a "copyright disclaimer" for the library,
|
||||
if necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James
|
||||
Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
||||
165
nostrdb/ccan/licenses/LGPL-3
Normal file
165
nostrdb/ccan/licenses/LGPL-3
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
Reference in New Issue
Block a user