diff mbox series

[FFmpeg-devel,v2,02/23] compat: add a fallback implementation of C23 stdbit.h

Message ID 20240914145711.21340-1-anton@khirnov.net
State New
Headers show
Series None | expand

Commit Message

Anton Khirnov Sept. 14, 2024, 2:56 p.m. UTC
From: Rémi Denis-Courmont <remi@remlab.net>

Header contents taken from VLC commit 7a970a33329c9836d169727ddbaf49a33240d587.

Signed-off-by: Anton Khirnov <anton@khirnov.net>
---
 compat/stdbit/stdbit.h | 596 +++++++++++++++++++++++++++++++++++++++++
 configure              |   4 +
 tests/ref/fate/source  |   1 +
 3 files changed, 601 insertions(+)
 create mode 100644 compat/stdbit/stdbit.h

Comments

James Almer Sept. 15, 2024, 8:29 p.m. UTC | #1
On 9/14/2024 11:56 AM, Anton Khirnov wrote:
> From: Rémi Denis-Courmont <remi@remlab.net>
> 
> Header contents taken from VLC commit 7a970a33329c9836d169727ddbaf49a33240d587.
> 
> Signed-off-by: Anton Khirnov <anton@khirnov.net>
> ---
>   compat/stdbit/stdbit.h | 596 +++++++++++++++++++++++++++++++++++++++++
>   configure              |   4 +
>   tests/ref/fate/source  |   1 +
>   3 files changed, 601 insertions(+)
>   create mode 100644 compat/stdbit/stdbit.h

Should be ok.
diff mbox series

Patch

diff --git a/compat/stdbit/stdbit.h b/compat/stdbit/stdbit.h
new file mode 100644
index 0000000000..b434fc2357
--- /dev/null
+++ b/compat/stdbit/stdbit.h
@@ -0,0 +1,596 @@ 
+/*
+ * Copyright (C) 2023 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ */
+
+#ifndef __STDC_VERSION_STDBIT_H__
+#define __STDC_VERSION_STDBIT_H__ 202311L
+
+#include <stdbool.h>
+#include <limits.h> /* CHAR_BIT */
+
+#define __STDC_ENDIAN_LITTLE__ 1234
+#define __STDC_ENDIAN_BIG__    4321
+
+#ifdef __BYTE_ORDER__
+# if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+#  define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__
+# elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#  define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__
+# else
+#  define __STDC_ENDIAN_NATIVE__ 3412
+# endif
+#elif defined(_MSC_VER)
+#  define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__
+#else
+# error Not implemented.
+#endif
+
+#define __stdbit_generic_type_func(func, value) \
+    _Generic (value, \
+        unsigned long long: stdc_##func##_ull((unsigned long long)(value)), \
+        unsigned long:      stdc_##func##_ul((unsigned long)(value)), \
+        unsigned int:       stdc_##func##_ui((unsigned int)(value)), \
+        unsigned short:     stdc_##func##_us((unsigned short)(value)), \
+        unsigned char:      stdc_##func##_uc((unsigned char)(value)))
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_leading_zeros_ull(unsigned long long value)
+{
+    return value ? __builtin_clzll(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ul(unsigned long value)
+{
+    return value ? __builtin_clzl(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ui(unsigned int value)
+{
+    return value ? __builtin_clz(value) : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_us(unsigned short value)
+{
+    return stdc_leading_zeros_ui(value)
+           - CHAR_BIT * (sizeof (int) - sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_uc(unsigned char value)
+{
+    return stdc_leading_zeros_ui(value) - (CHAR_BIT * (sizeof (int) - 1));
+}
+#else
+static inline unsigned int __stdc_leading_zeros(unsigned long long value,
+                                                unsigned int size)
+{
+    unsigned int zeros = size * CHAR_BIT;
+
+    while (value != 0) {
+        value >>= 1;
+        zeros--;
+    }
+
+    return zeros;
+}
+
+static inline unsigned int stdc_leading_zeros_ull(unsigned long long value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ul(unsigned long value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_ui(unsigned int value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_us(unsigned short value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_leading_zeros_uc(unsigned char value)
+{
+    return __stdc_leading_zeros(value, sizeof (value));
+}
+#endif
+
+#define stdc_leading_zeros(value) \
+        __stdbit_generic_type_func(leading_zeros, value)
+
+static inline unsigned int stdc_leading_ones_ull(unsigned long long value)
+{
+    return stdc_leading_zeros_ull(~value);
+}
+
+static inline unsigned int stdc_leading_ones_ul(unsigned long value)
+{
+    return stdc_leading_zeros_ul(~value);
+}
+
+static inline unsigned int stdc_leading_ones_ui(unsigned int value)
+{
+    return stdc_leading_zeros_ui(~value);
+}
+
+static inline unsigned int stdc_leading_ones_us(unsigned short value)
+{
+    return stdc_leading_zeros_us(~value);
+}
+
+static inline unsigned int stdc_leading_ones_uc(unsigned char value)
+{
+    return stdc_leading_zeros_uc(~value);
+}
+
+#define stdc_leading_ones(value) \
+        __stdbit_generic_type_func(leading_ones, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value)
+{
+    return value ? (unsigned int)__builtin_ctzll(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ul(unsigned long value)
+{
+    return value ? (unsigned int)__builtin_ctzl(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ui(unsigned int value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_us(unsigned short value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_uc(unsigned char value)
+{
+    return value ? (unsigned int)__builtin_ctz(value)
+                 : (CHAR_BIT * sizeof (value));
+}
+#else
+static inline unsigned int __stdc_trailing_zeros(unsigned long long value,
+                                                 unsigned int size)
+{
+    unsigned int zeros = size * CHAR_BIT;
+
+    while (value != 0) {
+        value <<= 1;
+        zeros--;
+    }
+
+    return zeros;
+}
+
+static inline unsigned int stdc_trailing_zeros_ull(unsigned long long value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ul(unsigned long value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_ui(unsigned int value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_us(unsigned short value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+
+static inline unsigned int stdc_trailing_zeros_uc(unsigned char value)
+{
+    return __stdc_trailing_zeros(value, sizeof (value));
+}
+#endif
+
+#define stdc_trailing_zeros(value) \
+        __stdbit_generic_type_func(trailing_zeros, value)
+
+static inline unsigned int stdc_trailing_ones_ull(unsigned long long value)
+{
+    return stdc_trailing_zeros_ull(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_ul(unsigned long value)
+{
+    return stdc_trailing_zeros_ul(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_ui(unsigned int value)
+{
+    return stdc_trailing_zeros_ui(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_us(unsigned short value)
+{
+    return stdc_trailing_zeros_us(~value);
+}
+
+static inline unsigned int stdc_trailing_ones_uc(unsigned char value)
+{
+    return stdc_trailing_zeros_uc(~value);
+}
+
+#define stdc_trailing_ones(value) \
+        __stdbit_generic_type_func(trailing_ones, value)
+
+static inline unsigned int stdc_first_leading_one_ull(unsigned long long value)
+{
+    return value ? (stdc_leading_zeros_ull(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_ul(unsigned long value)
+{
+    return value ? (stdc_leading_zeros_ul(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_ui(unsigned int value)
+{
+    return value ? (stdc_leading_zeros_ui(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_us(unsigned short value)
+{
+    return value ? (stdc_leading_zeros_us(value) + 1) : 0;
+}
+
+static inline unsigned int stdc_first_leading_one_uc(unsigned char value)
+{
+    return value ? (stdc_leading_zeros_uc(value) + 1) : 0;
+}
+
+#define stdc_first_leading_one(value) \
+        __stdbit_generic_type_func(first_leading_one, value)
+
+static inline unsigned int stdc_first_leading_zero_ull(unsigned long long value)
+{
+    return stdc_leading_ones_ull(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_ul(unsigned long value)
+{
+    return stdc_leading_ones_ul(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_ui(unsigned int value)
+{
+    return stdc_leading_ones_ui(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_us(unsigned short value)
+{
+    return stdc_leading_ones_us(~value);
+}
+
+static inline unsigned int stdc_first_leading_zero_uc(unsigned char value)
+{
+    return stdc_leading_ones_uc(~value);
+}
+
+#define stdc_first_leading_zero(value) \
+        __stdbit_generic_type_func(first_leading_zero, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value)
+{
+    return __builtin_ffsll(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_ul(unsigned long value)
+{
+    return __builtin_ffsl(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_ui(unsigned int value)
+{
+    return __builtin_ffs(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_us(unsigned short value)
+{
+    return __builtin_ffs(value);
+}
+
+static inline unsigned int stdc_first_trailing_one_uc(unsigned char value)
+{
+    return __builtin_ffs(value);
+}
+#else
+static inline unsigned int stdc_first_trailing_one_ull(unsigned long long value)
+{
+    return value ? (1 + stdc_trailing_zeros_ull(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_ul(unsigned long value)
+{
+    return value ? (1 + stdc_trailing_zeros_ul(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_ui(unsigned int value)
+{
+    return value ? (1 + stdc_trailing_zeros_ui(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_us(unsigned short value)
+{
+    return value ? (1 + stdc_trailing_zeros_us(value)) : 0;
+}
+
+static inline unsigned int stdc_first_trailing_one_uc(unsigned char value)
+{
+    return value ? (1 + stdc_trailing_zeros_uc(value)) : 0;
+}
+#endif
+
+#define stdc_first_trailing_one(value) \
+        __stdbit_generic_type_func(first_trailing_one, value)
+
+static inline unsigned int stdc_first_trailing_zero_ull(unsigned long long value)
+{
+    return stdc_first_trailing_one_ull(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_ul(unsigned long value)
+{
+    return stdc_first_trailing_one_ul(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_ui(unsigned int value)
+{
+    return stdc_first_trailing_one_ui(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_us(unsigned short value)
+{
+    return stdc_first_trailing_one_us(~value);
+}
+
+static inline unsigned int stdc_first_trailing_zero_uc(unsigned char value)
+{
+    return stdc_first_trailing_one_uc(~value);
+}
+
+#define stdc_first_trailing_zero(value) \
+        __stdbit_generic_type_func(first_trailing_zero, value)
+
+#if defined (__GNUC__) || defined (__clang__)
+static inline unsigned int stdc_count_ones_ull(unsigned long long value)
+{
+    return __builtin_popcountll(value);
+}
+
+static inline unsigned int stdc_count_ones_ul(unsigned long value)
+{
+    return __builtin_popcountl(value);
+}
+
+static inline unsigned int stdc_count_ones_ui(unsigned int value)
+{
+    return __builtin_popcount(value);
+}
+
+static inline unsigned int stdc_count_ones_us(unsigned short value)
+{
+    return __builtin_popcount(value);
+}
+
+static inline unsigned int stdc_count_ones_uc(unsigned char value)
+{
+    return __builtin_popcount(value);
+}
+#else
+static inline unsigned int __stdc_count_ones(unsigned long long value,
+                                             unsigned int size)
+{
+    unsigned int ones = 0;
+
+    for (unsigned int c = 0; c < (size * CHAR_BIT); c++) {
+         ones += value & 1;
+         value >>= 1;
+    }
+
+    return ones;
+}
+
+static inline unsigned int stdc_count_ones_ull(unsigned long long value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_ul(unsigned long value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_ui(unsigned int value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_us(unsigned short value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+
+static inline unsigned int stdc_count_ones_uc(unsigned char value)
+{
+    return __stdc_count_ones(value, sizeof (value));
+}
+#endif
+
+#define stdc_count_ones(value) \
+        __stdbit_generic_type_func(count_ones, value)
+
+static inline unsigned int stdc_count_zeros_ull(unsigned long long value)
+{
+    return stdc_count_ones_ull(~value);
+}
+
+static inline unsigned int stdc_count_zeros_ul(unsigned long value)
+{
+    return stdc_count_ones_ul(~value);
+}
+
+static inline unsigned int stdc_count_zeros_ui(unsigned int value)
+{
+    return stdc_count_ones_ui(~value);
+}
+
+static inline unsigned int stdc_count_zeros_us(unsigned short value)
+{
+    return stdc_count_ones_us(~value);
+}
+
+static inline unsigned int stdc_count_zeros_uc(unsigned char value)
+{
+    return stdc_count_ones_uc(~value);
+}
+
+#define stdc_count_zeros(value) \
+        __stdbit_generic_type_func(count_zeros, value)
+
+static inline bool stdc_has_single_bit_ull(unsigned long long value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_ul(unsigned long value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_ui(unsigned int value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_us(unsigned short value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+static inline bool stdc_has_single_bit_uc(unsigned char value)
+{
+    return value && (value & (value - 1)) == 0;
+}
+
+#define stdc_has_single_bit(value) \
+        __stdbit_generic_type_func(has_single_bit, value)
+
+static inline unsigned int stdc_bit_width_ull(unsigned long long value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ull(value);
+}
+
+static inline unsigned int stdc_bit_width_ul(unsigned long value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ul(value);
+}
+
+static inline unsigned int stdc_bit_width_ui(unsigned int value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_ui(value);
+}
+
+static inline unsigned int stdc_bit_width_us(unsigned short value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_us(value);
+}
+
+static inline unsigned int stdc_bit_width_uc(unsigned char value)
+{
+    return (CHAR_BIT * sizeof (value)) - stdc_leading_zeros_uc(value);
+}
+
+#define stdc_bit_width(value) \
+        __stdbit_generic_type_func(bit_width, value)
+
+static inline unsigned long long stdc_bit_floor_ull(unsigned long long value)
+{
+    return value ? (1ULL << (stdc_bit_width_ull(value) - 1)) : 0ULL;
+}
+
+static inline unsigned long stdc_bit_floor_ul(unsigned long value)
+{
+    return value ? (1UL << (stdc_bit_width_ul(value) - 1)) : 0UL;
+}
+
+static inline unsigned int stdc_bit_floor_ui(unsigned int value)
+{
+    return value ? (1U << (stdc_bit_width_ui(value) - 1)) : 0U;
+}
+
+static inline unsigned short stdc_bit_floor_us(unsigned short value)
+{
+    return value ? (1U << (stdc_bit_width_us(value) - 1)) : 0U;
+}
+
+static inline unsigned int stdc_bit_floor_uc(unsigned char value)
+{
+    return value ? (1U << (stdc_bit_width_uc(value) - 1)) : 0U;
+}
+
+#define stdc_bit_floor(value) \
+        __stdbit_generic_type_func(bit_floor, value)
+
+/* NOTE: Bit ceiling undefines overflow. */
+static inline unsigned long long stdc_bit_ceil_ull(unsigned long long value)
+{
+    return 1ULL << (value ? stdc_bit_width_ull(value - 1) : 0);
+}
+
+static inline unsigned long stdc_bit_ceil_ul(unsigned long value)
+{
+    return 1UL << (value ? stdc_bit_width_ul(value - 1) : 0);
+}
+
+static inline unsigned int stdc_bit_ceil_ui(unsigned int value)
+{
+    return 1U << (value ? stdc_bit_width_ui(value - 1) : 0);
+}
+
+static inline unsigned short stdc_bit_ceil_us(unsigned short value)
+{
+    return 1U << (value ? stdc_bit_width_us(value - 1) : 0);
+}
+
+static inline unsigned int stdc_bit_ceil_uc(unsigned char value)
+{
+    return 1U << (value ? stdc_bit_width_uc(value - 1) : 0);
+}
+
+#define stdc_bit_ceil(value) \
+        __stdbit_generic_type_func(bit_ceil, value)
+
+#endif /* __STDC_VERSION_STDBIT_H__ */
diff --git a/configure b/configure
index 337172a6c6..83c0d02f8c 100755
--- a/configure
+++ b/configure
@@ -7766,6 +7766,10 @@  if disabled stdatomic; then
     fi
 fi
 
+check_builtin stdbit "stdbit.h assert.h" \
+    'static_assert(__STDC_VERSION_STDBIT_H__ >= 202311L, "Compiler lacks stdbit.h")' || \
+    add_cppflags '-I\$(SRC_PATH)/compat/stdbit'
+
 # Check if requested libraries were found.
 for lib in $AUTODETECT_LIBS; do
     requested $lib && ! enabled $lib && die "ERROR: $lib requested but not found";
diff --git a/tests/ref/fate/source b/tests/ref/fate/source
index 1703b36c02..78d3a2e0fa 100644
--- a/tests/ref/fate/source
+++ b/tests/ref/fate/source
@@ -24,6 +24,7 @@  Headers without standard inclusion guards:
 compat/djgpp/math.h
 compat/float/float.h
 compat/float/limits.h
+compat/stdbit/stdbit.h
 libavcodec/bitstream_template.h
 tools/decode_simple.h
 Use of av_clip() where av_clip_uintp2() could be used: