Compare commits

4 Commits

Author SHA1 Message Date
485e04c6fd add struct-group.h 2023-06-20 21:31:44 +02:00
5294dbe371 updates from changes in AoC 2022 2023-06-20 21:27:49 +02:00
15cc0e54e9 add pjwhash 2023-06-20 21:27:00 +02:00
3fe7315f7c more fixes for 32 bits architecture 2022-12-07 08:23:09 +01:00
8 changed files with 271 additions and 30 deletions

View File

@@ -19,12 +19,13 @@
#define DEBUG_DEBUG #define DEBUG_DEBUG
#endif #endif
#include "bits.h"
#include "debug.h" #include "debug.h"
#define NANOSEC 1000000000 /* nano sec in sec */ #define NANOSEC 1000000000 /* nano sec in sec */
#define MILLISEC 1000000 /* milli sec in sec */ #define MILLISEC 1000000 /* milli sec in sec */
static s64 timer_start; /* in nanosecond */ static long long timer_start; /* in nanosecond */
static u32 debug_level=0; static u32 debug_level=0;
void debug_level_set(u32 level) void debug_level_set(u32 level)
@@ -48,7 +49,7 @@ void debug_init(u32 level)
log(0, "timer started.\n"); log(0, "timer started.\n");
} }
inline static s64 timer_elapsed() inline static long long timer_elapsed()
{ {
struct timespec timer; struct timespec timer;
@@ -56,7 +57,6 @@ inline static s64 timer_elapsed()
return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start; return (timer.tv_sec * NANOSEC + timer.tv_nsec) - timer_start;
} }
/* void debug - log function /* void debug - log function
* @timestamp : boolean * @timestamp : boolean
* @indent : indent level (2 spaces each) * @indent : indent level (2 spaces each)
@@ -75,9 +75,9 @@ void debug(u32 level, bool timestamp, u32 indent, const char *src,
printf("%*s", 2*(indent-1), ""); printf("%*s", 2*(indent-1), "");
if (timestamp) { if (timestamp) {
s64 diff = timer_elapsed(); long long diff = timer_elapsed();
printf("%ld.%03ld ", diff/NANOSEC, (diff/1000000)%1000); printf("%lld.%03lld ", diff/NANOSEC, (diff/1000000)%1000);
printf("%010ld ", diff); printf("%010lld ", diff);
} }
if (src) { if (src) {

View File

@@ -25,10 +25,10 @@
#endif #endif
/* no plan to support 32bits for now... /* no plan to support 32bits for now...
* #if __WORDSIZE != 64
* #error "Only 64 bits word size supported."
* #endif
*/ */
#if __WORDSIZE != 64
#error "Only 64 bits word size supported."
#endif
/* fixed-size types /* fixed-size types
*/ */
@@ -44,11 +44,30 @@ typedef uint8_t u8;
/* convenience types /* convenience types
*/ */
typedef long long int llong;
typedef unsigned long long int ullong;
typedef unsigned long int ulong; typedef unsigned long int ulong;
typedef unsigned int uint; typedef unsigned int uint;
typedef unsigned short ushort; typedef unsigned short ushort;
typedef unsigned char uchar; typedef unsigned char uchar;
/* define common types sizes
*/
#define BITS_PER_CHAR 8
#ifndef BITS_PER_SHORT
#define BITS_PER_SHORT (BITS_PER_CHAR * sizeof (short))
#endif
#ifndef BITS_PER_INT
#define BITS_PER_INT (BITS_PER_CHAR * sizeof (int))
#endif
#ifndef BITS_PER_LONG
#define BITS_PER_LONG (BITS_PER_CHAR * sizeof (long))
#endif
#ifndef BITS_PER_LLONG
#define BITS_PER_LLONG (BITS_PER_CHAR * sizeof (long long))
#endif
/* count set bits: 10101000 -> 3 /* count set bits: 10101000 -> 3
* ^ ^ ^ * ^ ^ ^
*/ */
@@ -73,6 +92,27 @@ static __always_inline int popcount64(u64 n)
# endif # endif
} }
static __always_inline int popcount32(u32 n)
{
# if __has_builtin(__builtin_popcount)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_popcount(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
int count = 0;
while (n) {
count++;
n &= (n - 1);
}
return count;
# endif
}
/* char is a special case, as it can be signed or unsigned /* char is a special case, as it can be signed or unsigned
*/ */
typedef signed char schar; typedef signed char schar;
@@ -242,27 +282,6 @@ static __always_inline uint ffs32(u32 n)
# endif # endif
} }
static __always_inline int popcount32(u32 n)
{
# if __has_builtin(__builtin_popcount)
# ifdef DEBUG_BITS
log_f(1, "builtin.\n");
# endif
return __builtin_popcount(n);
# else
# ifdef DEBUG_BITS
log_f(1, "emulated.\n");
# endif
int count = 0;
while (n) {
count++;
n &= (n - 1);
}
return count;
# endif
}
/* rolXX are taken from kernel's <linux/bitops.h> are are: /* rolXX are taken from kernel's <linux/bitops.h> are are:
* SPDX-License-Identifier: GPL-2.0 * SPDX-License-Identifier: GPL-2.0
*/ */

View File

@@ -18,6 +18,8 @@
#ifndef _BR_H #ifndef _BR_H
#define _BR_H #define _BR_H
#include "struct-group.h"
/* Indirect stringification. Doing two levels allows the parameter to be a /* Indirect stringification. Doing two levels allows the parameter to be a
* macro itself. For example, compile with -DFOO=bar, __stringify(FOO) * macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar". * converts to "bar".
@@ -31,6 +33,17 @@
#define __PASTE(x, y) ___PASTE(x, y) #define __PASTE(x, y) ___PASTE(x, y)
#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
/* unused/used parameters/functions
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-unused-type-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-unused-variable-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-unused-label-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-used-function-attribute
* https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-used-variable-attribute
*/
#define __unused __attribute__((__unused__))
#define __used __attribute__((__used__))
/* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster /* see https://lkml.org/lkml/2018/3/20/845 for explanation of this monster
*/ */
#define __is_constexpr(x) \ #define __is_constexpr(x) \

View File

@@ -25,6 +25,7 @@
#ifdef DEBUG_DEBUG #ifdef DEBUG_DEBUG
void debug_init(u32 level); void debug_init(u32 level);
void debug_level_set(u32 level); void debug_level_set(u32 level);
u32 debug_level_get(void);
void _printf debug(u32 level, bool timestamp, void _printf debug(u32 level, bool timestamp,
u32 indent, const char *src, u32 indent, const char *src,
u32 line, const char *, ...); u32 line, const char *, ...);

View File

@@ -0,0 +1,53 @@
/* pjwhash-inline.h - PJW hash function, inline version.
*
* Copyright (C) 2021-2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#ifndef _PJWHASH_INLINE_H
#define _PJWHASH_INLINE_H
#include "bits.h"
#define THREE_QUARTERS ((int) ((BITS_PER_INT * 3) / 4))
#define ONE_EIGHTH ((int) (BITS_PER_INT / 8))
#define HIGH_BITS ( ~((uint)(~0) >> ONE_EIGHTH ))
#ifndef _pjw_inline
#define _pjw_inline static inline
#endif
/**
* unsigned int pjwhash - PJW hash function
* @key: the key address.
* @length: the length of key.
*
* This hash was created by Peter Jay Weinberger (AT&T Bell Labs):
* https://en.wikipedia.org/wiki/PJW_hash_function
*
* Return: the PJW hash.
*/
_pjw_inline uint pjwhash(const void* key, uint length)
{
uint hash = 0, high;
const u8 *k = key;
for (uint i = 0; i < length; ++k, ++i) {
hash = (hash << ONE_EIGHTH) + *k;
high = hash & HIGH_BITS;
if (high != 0) {
hash ^= high >> THREE_QUARTERS;
hash &= ~high;
}
}
return hash;
}
#endif /* _PJWHASH_INLINE_H */

30
c/include/pjwhash.h Normal file
View File

@@ -0,0 +1,30 @@
/* pjwhash.h - PJW hash function, extern version.
*
* Copyright (C) 2021-2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*/
#ifndef _PJWHASH_H
#define _PJWHASH_H
#include "bits.h"
/**
* unsigned int pjwhash - PJW hash function
* @key: the key address.
* @length: the length of key.
*
* This hash was created by Peter Jay Weinberger (AT&T Bell Labs):
* https://en.wikipedia.org/wiki/PJW_hash_function
*
* Return: the PJW hash.
*/
extern uint pjwhash (const void* key, uint length);
#endif /* _PJWHASH_H */

105
c/include/struct-group.h Normal file
View File

@@ -0,0 +1,105 @@
/* struct-group.h - mirrored structure macros.
*
* Copyright (C) 2021-2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
* Some parts are taken from Linux's kernel <linux/stddef.h> and others, and are :
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _STRUCT_GROUP_H
#define _STRUCT_GROUP_H
/**
* __struct_group() - Create a mirrored named and anonyomous struct
*
* @TAG: The tag name for the named sub-struct (usually empty)
* @NAME: The identifier name of the mirrored sub-struct
* @ATTRS: Any struct attributes (usually empty)
* @MEMBERS: The member declarations for the mirrored structs
*
* Used to create an anonymous union of two structs with identical layout
* and size: one anonymous and one named. The former's members can be used
* normally without sub-struct naming, and the latter can be used to
* reason about the start, end, and size of the group of struct members.
* The named struct can also be explicitly tagged for layer reuse, as well
* as both having struct attributes appended.
*/
#define __struct_group(TAG, NAME, ATTRS, MEMBERS...) \
union { \
struct { MEMBERS } ATTRS; \
struct TAG { MEMBERS } ATTRS NAME; \
}
/**
* DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
*
* @TYPE: The type of each flexible array element
* @NAME: The name of the flexible array member
*
* In order to have a flexible array member in a union or alone in a
* struct, it needs to be wrapped in an anonymous struct with at least 1
* named member, but that member can be empty.
*/
#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
struct { \
struct { } __empty_ ## NAME; \
TYPE NAME[]; \
}
/**
* struct_group() - Wrap a set of declarations in a mirrored struct
*
* @NAME: The identifier name of the mirrored sub-struct
* @MEMBERS: The member declarations for the mirrored structs
*
* Used to create an anonymous union of two structs with identical
* layout and size: one anonymous and one named. The former can be
* used normally without sub-struct naming, and the latter can be
* used to reason about the start, end, and size of the group of
* struct members.
*/
#define struct_group(NAME, MEMBERS...) \
__struct_group(/* no tag */, NAME, /* no attrs */, MEMBERS)
/**
* struct_group_attr() - Create a struct_group() with trailing attributes
*
* @NAME: The identifier name of the mirrored sub-struct
* @ATTRS: Any struct attributes to apply
* @MEMBERS: The member declarations for the mirrored structs
*
* Used to create an anonymous union of two structs with identical
* layout and size: one anonymous and one named. The former can be
* used normally without sub-struct naming, and the latter can be
* used to reason about the start, end, and size of the group of
* struct members. Includes structure attributes argument.
*/
#define struct_group_attr(NAME, ATTRS, MEMBERS...) \
__struct_group(/* no tag */, NAME, ATTRS, MEMBERS)
/**
* struct_group_tagged() - Create a struct_group with a reusable tag
*
* @TAG: The tag name for the named sub-struct
* @NAME: The identifier name of the mirrored sub-struct
* @MEMBERS: The member declarations for the mirrored structs
*
* Used to create an anonymous union of two structs with identical
* layout and size: one anonymous and one named. The former can be
* used normally without sub-struct naming, and the latter can be
* used to reason about the start, end, and size of the group of
* struct members. Includes struct tag argument for the named copy,
* so the specified layout can be reused later.
*/
#define struct_group_tagged(TAG, NAME, MEMBERS...) \
__struct_group(TAG, NAME, /* no attrs */, MEMBERS)
#endif /* _STRUCT_GROUP_H */

20
c/pjwhash.c Normal file
View File

@@ -0,0 +1,20 @@
/* pjwhash.c - PJW hash function.
*
* Copyright (C) 2021-2022 Bruno Raoult ("br")
* Licensed under the GNU General Public License v3.0 or later.
* Some rights reserved. See COPYING.
*
* You should have received a copy of the GNU General Public License along with this
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
*
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
*
*/
#define _pjw_inline extern
//#include "bits.h"
//extern unsigned int pjwhash (const void* key, uint length);
#include "pjwhash.h"
#include "pjwhash-inline.h"