aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLexi Winter <ivy@FreeBSD.org>2025-05-13 14:17:40 +0100
committerLexi Winter <ivy@FreeBSD.org>2025-05-13 14:17:40 +0100
commit7de7af9042f3b4196478a86cd273b3b7f63c42f6 (patch)
treefeb277747effbd5b09af65584af950a45bacb4db
parent313713b24c6d2a3061972c4f431515c4f1b01c77 (diff)
sys/cdefs.h: add __const_castlf/dev/const-cast
-rw-r--r--sys/sys/cdefs.h40
1 files changed, 40 insertions, 0 deletions
diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h
index e79cf2972f3f..b3c055301f61 100644
--- a/sys/sys/cdefs.h
+++ b/sys/sys/cdefs.h
@@ -832,4 +832,44 @@
#define __align_down(x, y) __builtin_align_down(x, y)
#define __is_aligned(x, y) __builtin_is_aligned(x, y)
+/*
+ * __const_cast: a const-safe cast.
+ *
+ * Use it like this:
+ *
+ * __const_cast(type, pointer, return-type, expression)
+ *
+ * 'pointer' should be a pointer to an object of type 'type'. If 'pointer'
+ * points to a const 'type', then the return value will be cast to
+ * 'const return-type', otherwise the return value will be cast to
+ * 'return-type'. In either case, the return value is 'expression'.
+ *
+ * For example, a const-safe macro to cast a pointer to an array of char to a
+ * pointer to an array of uint8_t:
+ *
+ * #define GETBYTES(s) __const_cast(char, (s), uint8_t, (s))
+ */
+
+#ifdef __cplusplus
+template<typename... _Ts>
+struct __const_cast_visitor : _Ts... { using _Ts::operator()...; };
+template<typename... _Ts>
+__const_cast_visitor(_Ts...) -> __const_cast_visitor<_Ts...>;
+#define __const_cast(T, p, U, expr) \
+ (__const_cast_visitor{ \
+ [&](const T *) -> const U { \
+ return reinterpret_cast<const U>(expr); \
+ }, \
+ [&](T *) -> U { \
+ return reinterpret_cast<U>(expr); \
+ } \
+ })(p)
+#else
+#define __const_cast(T, p, U, expr) \
+ _Generic((p), \
+ const T *: (const U)expr, \
+ T *: (U)expr \
+ )
+#endif
+
#endif /* !_SYS_CDEFS_H_ */