#ifndef GCML_H #define GCML_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, "%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))) // ------------------------- // Additional Utility Macros // ------------------------- /** * @brief Safely reallocates memory and checks for allocation failure. * @param ptr The pointer to the previously allocated memory. * @param size The new size in bytes to allocate. */ #define SAFE_REALLOC(ptr, size) do { \ void* _tmp = realloc((ptr), (size)); \ if ((_tmp) == NULL) { \ LOG_FATAL("Memory reallocation failed for size %zu", (size_t)(size)); \ } else { \ (ptr) = _tmp; \ } \ } while (0) /** * @brief Marks a function as unused to suppress compiler warnings. */ #define UNUSED_FUNCTION __attribute__((unused)) /** * @brief Converts a value to a string at compile time. * @param value The value to stringify. * @return The string representation of the value. */ #define TO_STRING(value) TOSTRING(value) /** * @brief Generates a unique identifier by appending the line number. * @param prefix The prefix for the identifier. * @return A unique identifier. */ #define UNIQUE_ID(prefix) CONCAT(prefix, __LINE__) /** * @brief Forces a value to evaluate to a specific type without altering its binary representation. * @param value The value to cast. * @param type The target type. * @return The value cast to the specified type. */ #define FORCE_CAST(value, type) (*(type*)&(value)) /** * @brief Creates a do-while loop that executes exactly once. * @param block The block of code to execute. */ #define EXECUTE_ONCE(block) do { block } while(0) /** * @brief Checks if a pointer is aligned to a specified boundary. * @param ptr The pointer to check. * @param align The alignment boundary (must be a power of two). * @return Non-zero if aligned, zero otherwise. */ #define IS_ALIGNED(ptr, align) ((((uintptr_t)(const void*)(ptr)) & ((align) - 1)) == 0) /** * @brief Calculates the number of bits set to 1 in a variable. * @param x The variable to count bits in. * @return The number of bits set to 1. */ #define COUNT_SET_BITS(x) (__builtin_popcount(x)) /** * @brief Calculates the ceiling of a division between two integers. * @param numerator The numerator. * @param denominator The denominator. * @return The ceiling of the division. */ #define CEIL_DIV(numerator, denominator) (((numerator) + (denominator) - 1) / (denominator)) /** * @brief Concatenates two tokens with an underscore. * @param a The first token. * @param b The second token. * @return The concatenated token separated by an underscore. */ #define CONCAT_WITH_UNDERSCORE(a, b) CONCAT(a, _##b) /** * @brief Swaps two variables without using a temporary variable (only for integer types). * @param a The first variable. * @param b The second variable. */ #define SWAP_INPLACE(a, b) do { \ (a) ^= (b); \ (b) ^= (a); \ (a) ^= (b); \ } while (0) // ------------------------- // Safe Reallocation Macro // ------------------------- /** * @brief Safely reallocates memory and checks for allocation failure. * @param ptr The pointer to the previously allocated memory. * @param size The new size in bytes to allocate. */ #define SAFE_REALLOC(ptr, size) do { \ void* _tmp = realloc((ptr), (size)); \ if ((_tmp) == NULL) { \ LOG_FATAL("Memory reallocation failed for size %zu", (size_t)(size)); \ } else { \ (ptr) = _tmp; \ } \ } while (0) #define MAX_OF(...) MAX_OF_IMPL(__VA_ARGS__, MAX_OF_RSEQ_N()) #define MAX_OF_IMPL(...) MAX_OF_ARG_N(__VA_ARGS__) #define MAX_OF_ARG_N(_1, _2, _3, _4, _5, N, ...) N #define MAX_OF_RSEQ_N() 5,4,3,2,1,0 #define MIN_OF(...) MIN_OF_IMPL(__VA_ARGS__, MIN_OF_RSEQ_N()) #define MIN_OF_IMPL(...) MIN_OF_ARG_N(__VA_ARGS__) #define MIN_OF_ARG_N(_1, _2, _3, _4, _5, N, ...) N #define MIN_OF_RSEQ_N() 5,4,3,2,1,0 #define ZERO_STRUCT(s) memset(&(s), 0, sizeof(s)) #define PRINT_VAR(var) LOG_INFO(#var " = %d", var) #endif // GCML_H