summaryrefslogtreecommitdiff
path: root/libmisc
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-13 18:49:15 -0500
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-13 18:49:15 -0500
commitc578a300c7d0d46662fcd0bdce69af95a821bc18 (patch)
treea99de333f2812d7c018820f39d78b8c4e744f705 /libmisc
parent6a719c63ecb83a850c317ea94b8932aa0c857770 (diff)
parent57cc0523f600575feda09bd9fae13f685ce85b0f (diff)
Merge commit '57cc0523f600575feda09bd9fae13f685ce85b0f'
Diffstat (limited to 'libmisc')
-rw-r--r--libmisc/CMakeLists.txt1
-rw-r--r--libmisc/include/libmisc/log.h14
-rw-r--r--libmisc/include/libmisc/macro.h55
-rw-r--r--libmisc/include/libmisc/private.h29
-rw-r--r--libmisc/tests/test_assert.c14
-rw-r--r--libmisc/tests/test_macro.c32
6 files changed, 103 insertions, 42 deletions
diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt
index 02b19d5..83e91fe 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -15,6 +15,7 @@ add_lib_test(libmisc test_assert)
add_lib_test(libmisc test_endian)
add_lib_test(libmisc test_hash)
add_lib_test(libmisc test_log)
+add_lib_test(libmisc test_macro)
add_lib_test(libmisc test_private)
add_lib_test(libmisc test_rand)
add_lib_test(libmisc test_vcall)
diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h
index b4f5461..8c6d6be 100644
--- a/libmisc/include/libmisc/log.h
+++ b/libmisc/include/libmisc/log.h
@@ -9,6 +9,8 @@
#include <stdint.h> /* for uint8_t */
+#include <libmisc/macro.h>
+
#ifndef LOG_NAME
#error "each compilation unit that includes <libmisc/log.h> must define LOG_NAME"
#endif
@@ -18,17 +20,13 @@
#else
#define _LOG_NDEBUG 0
#endif
-#define __LOG_STR(x) #x
-#define _LOG_STR(x) __LOG_STR(x)
-#define __LOG_CAT3(a, b, c) a ## b ## c
-#define _LOG_CAT3(a, b, c) __LOG_CAT3(a, b, c)
[[format(printf, 1, 2)]] int _log_printf(const char *format, ...);
-#define n_errorf(nam, fmt, ...) do { _log_printf("error: " _LOG_STR(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_infof(nam, fmt, ...) do { _log_printf("info : " _LOG_STR(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
-#define n_debugf(nam, fmt, ...) do { if (_LOG_CAT3(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
- _log_printf("debug: " _LOG_STR(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_errorf(nam, fmt, ...) do { _log_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_infof(nam, fmt, ...) do { _log_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
+#define n_debugf(nam, fmt, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \
+ _log_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0)
#define errorf(fmt, ...) n_errorf(LOG_NAME, fmt, __VA_ARGS__)
#define infof(fmt, ...) n_infof(LOG_NAME, fmt, __VA_ARGS__)
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
new file mode 100644
index 0000000..9bb068f
--- /dev/null
+++ b/libmisc/include/libmisc/macro.h
@@ -0,0 +1,55 @@
+/* libmisc/macro.h - Useful C preprocessor macros
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _LIBMISC_MACRO_H_
+#define _LIBMISC_MACRO_H_
+
+/* for function definitions */
+
+#define LM_UNUSED(argname)
+#define LM_ALWAYS_INLINE [[gnu::always_inline]] inline
+#define LM_NEVER_INLINE [[gnu::noinline]]
+#define LM_FLATTEN [[gnu::flatten]]
+
+/* numeric */
+
+#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0]))
+#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) )
+#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */
+#define LM_NEXT_POWER_OF_2(x) ((1ULL)<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)))
+
+/* strings */
+
+#define LM_STR(x) #x
+#define LM_STR_(x) LM_STR(x)
+
+/* token pasting */
+
+#define LM_CAT2(a, b) a ## b
+#define LM_CAT3(a, b, c) a ## b ## c
+
+#define LM_CAT2_(a, b) LM_CAT2(a, b)
+#define LM_CAT3_(a, b, c) LM_CAT3(a, b, c)
+
+/* macro arguments */
+
+#define LM_SECOND(a, b, ...) b
+#define LM_EAT(...)
+#define LM_EXPAND(...) __VA_ARGS__
+
+/* conditionals */
+
+#define LM_T xxTxx
+#define LM_F xxFxx
+
+#define LM_SENTINEL() bogus, LM_T /* a magic sentinel value */
+#define LM_IS_SENTINEL(...) LM_SECOND(__VA_ARGS__, LM_F)
+
+#define LM_IF(cond) LM_CAT2(_LM_IF__, cond) /* LM_IF(cond)(then)(else) */
+#define _LM_IF__xxTxx(...) __VA_ARGS__ LM_EAT
+#define _LM_IF__xxFxx(...) LM_EXPAND
+
+#endif /* _LIBMISC_MACRO_H_ */
diff --git a/libmisc/include/libmisc/private.h b/libmisc/include/libmisc/private.h
index bc5e7ad..1db7915 100644
--- a/libmisc/include/libmisc/private.h
+++ b/libmisc/include/libmisc/private.h
@@ -7,31 +7,10 @@
#ifndef _LIBMISC_PRIVATE_H_
#define _LIBMISC_PRIVATE_H_
-/* primitive utilities */
+#include <libmisc/macro.h>
-#define _SECOND(a, b, ...) b
-
-#define _CAT(a, b) a ## b
-#define _CAT2(a, b) _CAT(a, b)
-#define _EAT(...)
-#define _EXPAND(...) __VA_ARGS__
-
-/* conditionals */
-
-#define _T xxTxx
-#define _F xxFxx
-
-#define _SENTINEL() bogus, _T /* a magic sentinel value */
-#define _IS_SENTINEL(...) _SECOND(__VA_ARGS__, _F)
-
-#define _IF(cond) _CAT(_IF__, cond) /* _IF(cond)(then)(else) */
-#define _IF__xxTxx(...) __VA_ARGS__ _EAT
-#define _IF__xxFxx(...) _EXPAND
-
-/* high-level functionality */
-
-#define YES _SENTINEL()
-#define BEGIN_PRIVATE(name) _IF(_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(struct {)
-#define END_PRIVATE(name) _IF(_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(} _CAT2(_HIDDEN_, __COUNTER__);)
+#define YES LM_SENTINEL()
+#define BEGIN_PRIVATE(name) LM_IF(LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(struct {)
+#define END_PRIVATE(name) LM_IF(LM_IS_SENTINEL(IMPLEMENTATION_FOR_##name))()(} LM_CAT2_(_HIDDEN_, __COUNTER__);)
#endif /* _LIBMISC_PRIVATE_H_ */
diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c
index 5b28561..189f6de 100644
--- a/libmisc/tests/test_assert.c
+++ b/libmisc/tests/test_assert.c
@@ -9,12 +9,11 @@
#include <string.h>
#include <stdlib.h>
+#include <libmisc/macro.h>
#include <libmisc/assert.h>
#include "test.h"
-#define UNUSED(name)
-
/* Intercept failures and logging *********************************************/
bool global_failed;
@@ -64,23 +63,20 @@ int vprintf(const char *format, va_list ap) {
} \
} while (0)
-#define _STR(x) #x
-#define STR(x) _STR(x)
-
/* Actual tests ***************************************************************/
static_assert(sizeof(char) == 1);
int main() {
test_should_succeed(assert(true));
- test_should_fail(assert(false), "error: ASSERT: "__FILE__":"STR(__LINE__)":main(): assertion \"false\" failed\n");
+ test_should_fail(assert(false), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n");
test_should_succeed(assert_msg(true, "foo"));
- test_should_fail(assert_msg(false, "foo"), "error: ASSERT: "__FILE__":"STR(__LINE__)":main(): assertion \"false\" failed: foo\n");
+ test_should_fail(assert_msg(false, "foo"), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed: foo\n");
test_should_succeed(assert_msg(true, NULL));
- test_should_fail(assert_msg(false, NULL), "error: ASSERT: "__FILE__":"STR(__LINE__)":main(): assertion \"false\" failed\n");
+ test_should_fail(assert_msg(false, NULL), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n");
- test_should_fail(assert_notreached("xxx"), "error: ASSERT: "__FILE__":"STR(__LINE__)":main(): assertion \"notreached\" failed: xxx\n");
+ test_should_fail(assert_notreached("xxx"), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"notreached\" failed: xxx\n");
if (global_log) {
free(global_log);
diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c
new file mode 100644
index 0000000..7cbf9d3
--- /dev/null
+++ b/libmisc/tests/test_macro.c
@@ -0,0 +1,32 @@
+/* libmisc/tests/test_macro.c - Tests for <libmisc/macro.h>
+ *
+ * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libmisc/macro.h>
+
+#include "test.h"
+
+int main() {
+ /* valid down to 0. */
+ test_assert(LM_NEXT_POWER_OF_2(0) == 1);
+ test_assert(LM_NEXT_POWER_OF_2(1) == 2);
+ test_assert(LM_NEXT_POWER_OF_2(2) == 4);
+ test_assert(LM_NEXT_POWER_OF_2(3) == 4);
+ test_assert(LM_NEXT_POWER_OF_2(4) == 8);
+ test_assert(LM_NEXT_POWER_OF_2(5) == 8);
+ test_assert(LM_NEXT_POWER_OF_2(6) == 8);
+ test_assert(LM_NEXT_POWER_OF_2(7) == 8);
+ test_assert(LM_NEXT_POWER_OF_2(8) == 16);
+ /* ... */
+ test_assert(LM_NEXT_POWER_OF_2(16) == 32);
+ /* ... */
+ test_assert(LM_NEXT_POWER_OF_2(0x7000000000000000) == 0x8000000000000000);
+ /* ... */
+ test_assert(LM_NEXT_POWER_OF_2(0x8000000000000000-1) == 0x8000000000000000);
+ /* Valid up to 0x8000000000000000-1 = (1<<63)-1 */
+ test_assert(LM_NEXT_POWER_OF_2(0x8000000000000000) == 0); /* :( */
+
+ return 0;
+}