summaryrefslogtreecommitdiff
path: root/lib/ccan/cast/cast.h
blob: daebd8572391f07dfb17ae20c341c114c2507c3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#ifndef CCAN_CAST_H
#define CCAN_CAST_H
#include "config.h"
#include <stdint.h>
#include <ccan/build_assert/build_assert.h>

/**
 * cast_signed - cast a (const) char * to/from (const) signed/unsigned char *.
 * @type: some char * variant.
 * @expr: expression (of some char * variant) to cast.
 *
 * Some libraries insist on an unsigned char in various places; cast_signed
 * makes sure (with suitable compiler) that the expression you are casting
 * only differs in signed/unsigned, not in type or const-ness.
 */
#define cast_signed(type, expr)						\
	((type)(expr)							\
	 + BUILD_ASSERT_OR_ZERO(cast_sign_compatible(type, (expr))))

/**
 * cast_const - remove a const qualifier from a pointer.
 * @type: some pointer type.
 * @expr: expression to cast.
 *
 * This ensures that you are only removing the const qualifier from an
 * expression.  The expression must otherwise match @type.
 *
 * If @type is a pointer to a pointer, you must use cast_const2 (etc).
 *
 * Example:
 *	// Dumb open-coded strstr variant.
 *	static char *find_needle(const char *haystack)
 *	{
 *		size_t i;
 *		for (i = 0; i < strlen(haystack); i++)
 *		if (memcmp("needle", haystack+i, strlen("needle")) == 0)
 *			return cast_const(char *, haystack+i);
 *		return NULL;
 *	}
 */
#define cast_const(type, expr)						\
	((type)((intptr_t)(expr)					\
		+ BUILD_ASSERT_OR_ZERO(cast_const_compat1((expr), type))))

/**
 * cast_const2 - remove a const qualifier from a pointer to a pointer.
 * @type: some pointer to pointer type.
 * @expr: expression to cast.
 *
 * This ensures that you are only removing the const qualifier from an
 * expression.  The expression must otherwise match @type.
 */
#define cast_const2(type, expr)						\
	((type)((intptr_t)(expr)					\
		+ BUILD_ASSERT_OR_ZERO(cast_const_compat2((expr), type))))

/**
 * cast_const3 - remove a const from a pointer to a pointer to a pointer..
 * @type: some pointer to pointer to pointer type.
 * @expr: expression to cast.
 *
 * This ensures that you are only removing the const qualifier from an
 * expression.  The expression must otherwise match @type.
 */
#define cast_const3(type, expr)						\
	((type)((intptr_t)(expr)					\
		+ BUILD_ASSERT_OR_ZERO(cast_const_compat3((expr), type))))


/**
 * cast_static - explicit mimic of implicit cast.
 * @type: some type.
 * @expr: expression to cast.
 *
 * This ensures that the cast is not to or from a pointer: it can only be
 * an implicit cast, such as a pointer to a similar const pointer, or between
 * integral types.
 */
#if HAVE_COMPOUND_LITERALS
#define cast_static(type, expr)			\
	((struct { type x; }){(expr)}.x)
#else
#define cast_static(type, expr)			\
	((type)(expr))
#endif

/* Herein lies the gcc magic to evoke compile errors. */
#if HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
#define cast_sign_compatible(t, e) \
  __builtin_choose_expr(						\
	  __builtin_types_compatible_p(__typeof__(t), char *) ||	\
	  __builtin_types_compatible_p(__typeof__(t), signed char *) || \
	  __builtin_types_compatible_p(__typeof__(t), unsigned char *), \
	  /* if type is not const qualified */				\
	  __builtin_types_compatible_p(__typeof__(e), char *) ||	\
	  __builtin_types_compatible_p(__typeof__(e), signed char *) || \
	  __builtin_types_compatible_p(__typeof__(e), unsigned char *), \
	  /* and if it is... */						\
	  __builtin_types_compatible_p(__typeof__(e), const char *) ||	\
	  __builtin_types_compatible_p(__typeof__(e), const signed char *) || \
	  __builtin_types_compatible_p(__typeof__(e), const unsigned char *) ||\
	  __builtin_types_compatible_p(__typeof__(e), char *) ||	\
	  __builtin_types_compatible_p(__typeof__(e), signed char *) ||	\
	  __builtin_types_compatible_p(__typeof__(e), unsigned char *)	\
	  )

#define cast_const_strip1(expr)			\
	__typeof__(*(struct { int z; __typeof__(expr) x; }){0}.x)
#define cast_const_strip2(expr) \
	__typeof__(**(struct { int z; __typeof__(expr) x; }){0}.x)
#define cast_const_strip3(expr) \
	__typeof__(***(struct { int z; __typeof__(expr) x; }){0}.x)
#define cast_const_compat1(expr, type)					\
	__builtin_types_compatible_p(cast_const_strip1(expr),		\
				     cast_const_strip1(type))
#define cast_const_compat2(expr, type)					\
	__builtin_types_compatible_p(cast_const_strip2(expr),		\
				     cast_const_strip2(type))
#define cast_const_compat3(expr, type)					\
	__builtin_types_compatible_p(cast_const_strip3(expr),		\
				     cast_const_strip3(type))
#else
#define cast_sign_compatible(type, expr)		\
	(sizeof(*(type)0) == 1 && sizeof(*(expr)) == 1)
#define cast_const_compat1(expr, type)		(1)
#define cast_const_compat2(expr, type)		(1)
#define cast_const_compat3(expr, type)		(1)
#endif
#endif /* CCAN_CAST_H */