commit 879d2926732d79cce8f0ca537811fc8463a86e73 Author: Spencer Conlon Date: Tue Dec 24 05:31:43 2024 +0000 Add gcml.h diff --git a/gcml.h b/gcml.h new file mode 100644 index 0000000..e5000fa --- /dev/null +++ b/gcml.h @@ -0,0 +1,314 @@ +#ifndef COMMON_MACROS_H +#define COMMON_MACROS_H + +#include +#include +#include + +// ------------------------- +// General Utility Macros +// ------------------------- + +/** + * @brief Returns the minimum of two values. + */ +#define MIN(a, b) (( (a) < (b) ) ? (a) : (b)) + +/** + * @brief Returns the maximum of two values. + */ +#define MAX(a, b) (( (a) > (b) ) ? (a) : (b)) + +/** + * @brief Calculates the number of elements in an array. + */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/** + * @brief Suppresses compiler warnings for unused variables. + */ +#define UNUSED(x) (void)(x) + +/** + * @brief Aligns a value `x` up to the nearest multiple of `align`. + */ +#define ALIGN_UP(x, align) (((x) + ((align)-1)) & ~((align)-1)) + +/** + * @brief Aligns a value `x` down to the nearest multiple of `align`. + */ +#define ALIGN_DOWN(x, align) ((x) & ~((align)-1)) + +// ------------------------- +// Debugging and Logging Macros +// ------------------------- + +#ifdef DEBUG + /** + * @brief Prints debug messages with file name, line number, and function name. + */ + #define DEBUG_PRINT(fmt, ...) \ + fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt "\n", \ + __FILE__, __LINE__, __func__, ##__VA_ARGS__) +#else + #define DEBUG_PRINT(fmt, ...) // No operation in release builds +#endif + +/** + * @brief Logs informational messages. + */ +#define LOG_INFO(fmt, ...) \ + fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__) + +/** + * @brief Logs warning messages. + */ +#define LOG_WARN(fmt, ...) \ + fprintf(stderr, "WARNING: " fmt "\n", ##__VA_ARGS__) + +/** + * @brief Logs error messages. + */ +#define LOG_ERROR(fmt, ...) \ + fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) + +/** + * @brief Logs fatal error messages and exits the program. + */ +#define LOG_FATAL(fmt, ...) do { \ + fprintf(stderr, "FATAL: " fmt "\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ +} while (0) + +// ------------------------- +// Assertion Macros +// ------------------------- + +/** + * @brief Asserts a condition and logs an error message if the condition is false. + */ +#ifndef NDEBUG + #define ASSERT(cond, fmt, ...) do { \ + if (!(cond)) { \ + fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", \ + #cond, __func__, __FILE__, __LINE__); \ + fprintf(stderr, fmt "\n", ##__VA_ARGS__); \ + abort(); \ + } \ + } while (0) +#else + #define ASSERT(cond, fmt, ...) ((void)0) +#endif + +// ------------------------- +// Stringification Macros +// ------------------------- + +/** + * @brief Converts a macro argument to a string. + */ +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +// ------------------------- +// Token Pasting Macros +// ------------------------- + +/** + * @brief Concatenates two tokens. + */ +#define CONCAT(a, b) a ## b + +/** + * @brief Concatenates three tokens. + */ +#define CONCAT3(a, b, c) a ## b ## c + +// ------------------------- +// Memory Management Macros +// ------------------------- + +/** + * @brief Allocates memory and checks for allocation failure. + * @param ptr The pointer to assign the allocated memory. + * @param size The size in bytes to allocate. + */ +#define SAFE_MALLOC(ptr, size) do { \ + (ptr) = malloc(size); \ + if ((ptr) == NULL) { \ + LOG_FATAL("Memory allocation failed for size %zu", (size_t)(size)); \ + } \ +} while (0) + +/** + * @brief Allocates zero-initialized memory and checks for allocation failure. + * @param ptr The pointer to assign the allocated memory. + * @param count The number of elements to allocate. + * @param type The type of each element. + */ +#define SAFE_CALLOC(ptr, count, type) do { \ + (ptr) = calloc((count), sizeof(type)); \ + if ((ptr) == NULL) { \ + LOG_FATAL("Memory allocation (calloc) failed for count %zu of type %s", \ + (size_t)(count), #type); \ + } \ +} while (0) + +/** + * @brief Frees memory and sets the pointer to NULL. + * @param ptr The pointer to free. + */ +#define SAFE_FREE(ptr) do { \ + free(ptr); \ + ptr = NULL; \ +} while(0) + +// ------------------------- +// Type Casting Macros +// ------------------------- + +/** + * @brief Safely casts a pointer to a specific type. + * @param ptr The pointer to cast. + * @param type The target type. + */ +#define SAFE_CAST(ptr, type) ((type)(ptr)) + +// ------------------------- +// Bit Manipulation Macros +// ------------------------- + +/** + * @brief Sets a bit at a specific position. + * @param x The variable. + * @param pos The bit position. + */ +#define SET_BIT(x, pos) ((x) |= (1U << (pos))) + +/** + * @brief Clears a bit at a specific position. + * @param x The variable. + * @param pos The bit position. + */ +#define CLEAR_BIT(x, pos) ((x) &= ~(1U << (pos))) + +/** + * @brief Toggles a bit at a specific position. + * @param x The variable. + * @param pos The bit position. + */ +#define TOGGLE_BIT(x, pos) ((x) ^= (1U << (pos))) + +/** + * @brief Checks if a bit at a specific position is set. + * @param x The variable. + * @param pos The bit position. + * @return Non-zero if the bit is set, zero otherwise. + */ +#define CHECK_BIT(x, pos) (((x) >> (pos)) & 1U) + +// ------------------------- +// Compile-Time Assertion Macro +// ------------------------- + +/** + * @brief Performs a compile-time assertion. + * @param expr The expression to evaluate. + * @param msg The message to display if the assertion fails. + */ +#define STATIC_ASSERT(expr, msg) _Static_assert(expr, msg) + +// ------------------------- +// Deprecation Warning Macros +// ------------------------- + +/** + * @brief Marks a function as deprecated with a custom message. + */ +#if defined(__GNUC__) || defined(__clang__) + #define DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) + #define DEPRECATED(msg) __declspec(deprecated(msg)) +#else + #pragma message("WARNING: DEPRECATED macro is not supported for this compiler.") + #define DEPRECATED(msg) +#endif + +// ------------------------- +// Loop Macros +// ------------------------- + +/** + * @brief Iterates over each element in an array. + * @param item The loop variable. + * @param array The array to iterate over. + */ +#define FOREACH(item, array) \ + for (size_t keep = 1, \ + count = ARRAY_SIZE(array), \ + i = 0; \ + keep && i < count; \ + keep = !keep, i++) \ + for (item = (array) + i; keep; keep = !keep) + +/** + * @brief Repeats a block of code `n` times. + * @param n The number of times to repeat. + * @param block The block of code to execute. + */ +#define REPEAT(n, block) \ + for (size_t _i = 0; _i < (n); ++_i) { block; } + +// ------------------------- +// Swap Macro +// ------------------------- + +/** + * @brief Swaps two variables of the same type. + * @param a The first variable. + * @param b The second variable. + */ +#define SWAP(a, b) do { \ + typeof(a) _swap_temp = (a); \ + (a) = (b); \ + (b) = _swap_temp; \ +} while (0) + +// ------------------------- +// Execute Once Macro +// ------------------------- + +/** + * @brief Executes a block of code only once. + * @param block The block of code to execute. + */ +#define DO_ONCE(block) \ + do { \ + static int _do_once_flag = 0; \ + if (!_do_once_flag) { \ + _do_once_flag = 1; \ + block \ + } \ + } while (0) + +// ------------------------- +// Utility Macros +// ------------------------- + +/** + * @brief Calculates the offset of a member within a struct. + * @param type The struct type. + * @param member The member within the struct. + */ +#define OFFSET_OF(type, member) ((size_t) &(((type *)0)->member)) + +/** + * @brief Retrieves the containing struct from a member pointer. + * @param ptr The pointer to the member. + * @param type The type of the containing struct. + * @param member The member within the struct. + */ +#define CONTAINER_OF(ptr, type, member) \ + ((type *)((char *)(ptr) - OFFSET_OF(type, member))) + +#endif // COMMON_MACROS_H