Linux-man Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v4] <sys/param.h>: Add nitems()
@ 2020-09-28 19:12 Alejandro Colomar
  2020-10-11 16:43 ` Ping: " Alejandro Colomar
  0 siblings, 1 reply; 2+ messages in thread
From: Alejandro Colomar @ 2020-09-28 19:12 UTC (permalink / raw)
  To: libc-alpha
  Cc: Alejandro Colomar, libc-coord, libstdc++,
	gcc, linux-kernel, linux-man, jwakely, fweimer,
	ville.voutilainen, enh, rusty

'nitems()' calculates the length of an array in number of items.
It is safe: if a pointer is passed to the macro (or function, in C++),
the compilation is broken due to:
 - In >= C11: _Static_assert()
 - In C89, C99: Negative anonymous bitfield
 - In C++: The template requires an array

Some BSDs already provide a macro nitems() in <sys/param.h>,
although it usually doesn't provide safety against pointers.

This patch uses the same name for compatibility reasons,
and to be the least disruptive with existing code.

This patch also adds some other macros, which are required by 'nitems()':

__is_same_type(a, b):
Returns non-zero if the two input arguments are of the same type.

__is_array(arr):
Returns non-zero if the input argument is of an array type.

__must_be(expr, msg):
Allows using _Static_assert() everywhere an expression can be used.
It evaluates '(int)0' or breaks the compilation.

__must_be_array(arr):
It evaluates to '(int)0' if the argument is of an array type.
Else, it breaks compilation.

__nitems(arr):
It implements the basic sizeof division needed to calculate the array length.


P.S.: I'd like to put this patch in the public domain.

Signed-off-by: Alejandro Colomar <colomar.6.4.3@gmail.com>
---

A few changes since v3:

- Macros don't need reserved names in their parameters,
so I simplified those names.

- I fixed some wrong indentation levels.

- Renamed __array_len() to __nitems() for consistency.


 misc/sys/param.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/misc/sys/param.h b/misc/sys/param.h
index d7c319b157..08d4093961 100644
--- a/misc/sys/param.h
+++ b/misc/sys/param.h
@@ -102,5 +102,52 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
+/* Macros related to the types of variables */
+#define __is_same_type(a, b)                                                  \
+	__builtin_types_compatible_p(__typeof__(a), __typeof__(b))
+#define __is_array(arr)	(!__is_same_type((arr), &(arr)[0]))
+
+/* Macros for embedding _Static_assert() in expressions */
+#if __STDC_VERSION__ >= 201112L
+# define __must_be(expr, msg)   (                                             \
+        0 * (int)sizeof(                                                      \
+          struct {                                                            \
+            _Static_assert((expr), msg);                                      \
+            char _ISO_C_forbids_a_struct_with_no_members;                     \
+          }                                                                   \
+        )                                                                     \
+)
+#else
+# define __must_be(expr, msg)   (                                             \
+        0 * (int)sizeof(                                                      \
+          struct {                                                            \
+            int  : (-!(expr));                                                \
+            char _ISO_C_forbids_a_struct_with_no_members;                     \
+          }                                                                   \
+        )                                                                     \
+)
+#endif
+#define __must_be_array(arr)	__must_be(__is_array(arr), "Must be an array!")
+
+/* Macros for array sizes */
+#if defined(__cplusplus)
+# if __cplusplus >= 201103L
+template<typename _Tp, std::size_t _Len>
+  constexpr inline std::size_t
+  nitems(const _Tp(&)[_Len]) __THROW
+  {
+    return _Len;
+  }
+# else /* __cplusplus < 201103L */
+template<typename _Tp, std::size_t _Len>
+  char
+  (&__nitems_chararr(const _Tp(&)[_Len]))[_Len];
+#  define nitems(arr)	(sizeof(__nitems_chararr(arr)))
+# endif /* __cplusplus < 201103L */
+#else /* !defined(__cplusplus) */
+# define __nitems(arr)	(sizeof((arr)) / sizeof((arr)[0]))
+# define nitems(arr)	(__nitems(arr) + __must_be_array(arr))
+#endif /* !defined(__cplusplus) */
+
 
 #endif  /* sys/param.h */
-- 
2.28.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Ping: Re: [PATCH v4] <sys/param.h>: Add nitems()
  2020-09-28 19:12 [PATCH v4] <sys/param.h>: Add nitems() Alejandro Colomar
@ 2020-10-11 16:43 ` Alejandro Colomar
  0 siblings, 0 replies; 2+ messages in thread
From: Alejandro Colomar @ 2020-10-11 16:43 UTC (permalink / raw)
  To: libc-alpha
  Cc: libc-coord, libstdc++,
	gcc, linux-kernel, linux-man, jwakely, fweimer,
	ville.voutilainen, enh, rusty

Ping.

On 2020-09-28 21:12, Alejandro Colomar wrote:
> 'nitems()' calculates the length of an array in number of items.
> It is safe: if a pointer is passed to the macro (or function, in C++),
> the compilation is broken due to:
>   - In >= C11: _Static_assert()
>   - In C89, C99: Negative anonymous bitfield
>   - In C++: The template requires an array
> 
> Some BSDs already provide a macro nitems() in <sys/param.h>,
> although it usually doesn't provide safety against pointers.
> 
> This patch uses the same name for compatibility reasons,
> and to be the least disruptive with existing code.
> 
> This patch also adds some other macros, which are required by 'nitems()':
> 
> __is_same_type(a, b):
> Returns non-zero if the two input arguments are of the same type.
> 
> __is_array(arr):
> Returns non-zero if the input argument is of an array type.
> 
> __must_be(expr, msg):
> Allows using _Static_assert() everywhere an expression can be used.
> It evaluates '(int)0' or breaks the compilation.
> 
> __must_be_array(arr):
> It evaluates to '(int)0' if the argument is of an array type.
> Else, it breaks compilation.
> 
> __nitems(arr):
> It implements the basic sizeof division needed to calculate the array length.
> 
> 
> P.S.: I'd like to put this patch in the public domain.
> 
> Signed-off-by: Alejandro Colomar <colomar.6.4.3@gmail.com>
> ---
> 
> A few changes since v3:
> 
> - Macros don't need reserved names in their parameters,
> so I simplified those names.
> 
> - I fixed some wrong indentation levels.
> 
> - Renamed __array_len() to __nitems() for consistency.
> 
> 
>   misc/sys/param.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 47 insertions(+)
> 
> diff --git a/misc/sys/param.h b/misc/sys/param.h
> index d7c319b157..08d4093961 100644
> --- a/misc/sys/param.h
> +++ b/misc/sys/param.h
> @@ -102,5 +102,52 @@
>   #define MIN(a,b) (((a)<(b))?(a):(b))
>   #define MAX(a,b) (((a)>(b))?(a):(b))
>   
> +/* Macros related to the types of variables */
> +#define __is_same_type(a, b)                                                  \
> +	__builtin_types_compatible_p(__typeof__(a), __typeof__(b))
> +#define __is_array(arr)	(!__is_same_type((arr), &(arr)[0]))
> +
> +/* Macros for embedding _Static_assert() in expressions */
> +#if __STDC_VERSION__ >= 201112L
> +# define __must_be(expr, msg)   (                                             \
> +        0 * (int)sizeof(                                                      \
> +          struct {                                                            \
> +            _Static_assert((expr), msg);                                      \
> +            char _ISO_C_forbids_a_struct_with_no_members;                     \
> +          }                                                                   \
> +        )                                                                     \
> +)
> +#else
> +# define __must_be(expr, msg)   (                                             \
> +        0 * (int)sizeof(                                                      \
> +          struct {                                                            \
> +            int  : (-!(expr));                                                \
> +            char _ISO_C_forbids_a_struct_with_no_members;                     \
> +          }                                                                   \
> +        )                                                                     \
> +)
> +#endif
> +#define __must_be_array(arr)	__must_be(__is_array(arr), "Must be an array!")
> +
> +/* Macros for array sizes */
> +#if defined(__cplusplus)
> +# if __cplusplus >= 201103L
> +template<typename _Tp, std::size_t _Len>
> +  constexpr inline std::size_t
> +  nitems(const _Tp(&)[_Len]) __THROW
> +  {
> +    return _Len;
> +  }
> +# else /* __cplusplus < 201103L */
> +template<typename _Tp, std::size_t _Len>
> +  char
> +  (&__nitems_chararr(const _Tp(&)[_Len]))[_Len];
> +#  define nitems(arr)	(sizeof(__nitems_chararr(arr)))
> +# endif /* __cplusplus < 201103L */
> +#else /* !defined(__cplusplus) */
> +# define __nitems(arr)	(sizeof((arr)) / sizeof((arr)[0]))
> +# define nitems(arr)	(__nitems(arr) + __must_be_array(arr))
> +#endif /* !defined(__cplusplus) */
> +
>   
>   #endif  /* sys/param.h */
> 

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, back to index

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-28 19:12 [PATCH v4] <sys/param.h>: Add nitems() Alejandro Colomar
2020-10-11 16:43 ` Ping: " Alejandro Colomar

Linux-man Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-man/0 linux-man/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-man linux-man/ https://lore.kernel.org/linux-man \
		linux-man@vger.kernel.org
	public-inbox-index linux-man

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-man


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git