[英]C - Is it possible to implement a reduction operation using variadic macros?
This question is nearly a duplicate, but I figured I'd ask again since it's pretty old and the language may have evolved: Variadic recursive preprocessor macros - is it possible?这个问题几乎是重复的,但我想我会再问一次,因为它已经很老了,而且语言可能已经发展: Variadic recursive preprocessor macros - is it possible?
I would like to implement a constant ONE_HOT encoding operation and I'm wondering if this is possible using variadic macros.我想实现一个常量 ONE_HOT 编码操作,我想知道这是否可以使用可变参数宏。
I would like to compute a constant one-hot encoding of my enum
elements and store it in an uint32
.我想计算我的enum
元素的常量单热编码并将其存储在uint32
中。 Basically, reduce all arguments of ONE_HOT(a, b, c, ...)
as (1 << a) | (1 << b) | (1 << c)...
基本上,将ONE_HOT(a, b, c, ...)
所有 arguments 减少为(1 << a) | (1 << b) | (1 << c)...
(1 << a) | (1 << b) | (1 << c)...
(1 << a) | (1 << b) | (1 << c)...
. (1 << a) | (1 << b) | (1 << c)...
typedef enum {
FIRST,
SECOND,
THIRD,
// More entries
MY_ENUM_NUM_ENTRIES // Guaranteed to never be greater than sizeof(uint32_t)*8 by design.
} MY_ENUM_TYPE;
// In this case, only FIRST and THIRD are "set".
uint32_t expected_entries = (1<<FIRST) | (1<<THIRD);
// Check if set
if(expected_entries & (1<<SECOND)){
// Do something.
}
enum
declaration and assign it power-of-2 values.选项 B:修改enum
声明并为其分配 2 的幂值。typedef enum {
FIRST = (1 << 0),
SECOND = (1 << 1),
THIRD = (1 << 2),
// More entries
MY_ENUM_NUM_ENTRIES // Downside: This is now broken. Requires a workaround.
} MY_ENUM_TYPE;
// Upside: The one-hot operation is nicer to read and write.
uint32_t expected_entries = FIRST | THIRD;
// Check if set
if(expected_entries & SECOND){
// Do something.
}
Is there a way to define my operation such that the one-hot computation is reduced and evaluated at compile-time whenever possible?有没有一种方法可以定义我的操作,以便尽可能在编译时减少和评估单热计算?
#define IS_HOT(encoded, bit) (encoded & (1<<bit))
#define SET_HOT(encoded, bit) (encoded | (1<<bit))
#define CLEAR_HOT(encoded, bit) (encoded & (0xFFFFu^(1<<bit)))
// PSEUDO-CODE.
// I want all values (a, b, c, ...) passed into ONE_HOT to be shifted
// and bitwise OR'd together to form the one-hot encoding.
#define ONE_HOT(a, b, c, ...) (1 << a) | (1 << b) | (1 << c) | ONE_HOT(##__VA_ARGS__)
// END PSEUDO-CODE
typedef enum {
FIRST,
SECOND,
THIRD,
// More entries
MY_ENUM_NUM_ENTRIES // Guaranteed to never be greater than sizeof(uint32_t)*8 by design.
// BONUS: we don't need to redefine our original enum.
} MY_ENUM_TYPE;
// Upside: The one-hot operation is nicer to read and write.
uint32_t expected_entries = ONE_HOT(FIRST, THIRD);
// This is terrible
// uint32_t expected_entries = SET_HOT(SET_HOT(encoded, FIRST), THIRD);
// Check if set
if(IS_HOT(expected_entries, SECOND)){
// Do something.
}
onehot.h
Implemented with the "Map-Macro" pattern, as suggested.按照建议使用“Map-Macro”模式实施。
#ifndef ONEHOT_H
#define ONEHOT_H
// Defining the map-macro operation per
// https://github.com/swansontec/map-macro
#define MAP_OUT
#define EVAL0(...) __VA_ARGS__
#define EVAL1(...) EVAL0 (EVAL0 (__VA_ARGS__))
#define EVAL2(...) EVAL1 (EVAL1 (__VA_ARGS__))
#define EVAL3(...) EVAL2 (EVAL2 (__VA_ARGS__))
#define EVAL4(...) EVAL3 (EVAL3 (__VA_ARGS__))
#define EVAL(...) EVAL4 (EVAL4 (__VA_ARGS__))
#define MAP_END(...)
#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
// Final structure of the map-macro
#define MAP(f, ...) EVAL (MAP1 (f, __VA_ARGS__, (), 0))
// One-Hot Definition
#define ONE_HOT_SHIFT(a) (1u << a) |
#define ONE_HOT(...) MAP(ONE_HOT_SHIFT, __VA_ARGS__) 0
#define IS_HOT(encoded, bit) (encoded & (1 << bit))
#define SET_HOT(encoded, bit) (encoded | (1 << bit))
#define CLEAR_HOT(encoded, bit) (encoded & (0xFFFFu^(1 << bit)))
#define INTERSECT_HOT(a, b) (a & b)
#define UNION_HOT(a, b) (a | b)
#define EQUALS_HOT(a, b) (~(a^b))
#define A_CONTAINS_ALL_B(a, b) (EQUALS_HOT(INTERSECT_HOT(a, b), b))
#endif
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.