summaryrefslogtreecommitdiff
path: root/kernel/lib/libcxx/include/__bit/bit.h
blob: 2a778f688deff3e985d69bda8e603255ecc07a5f (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the BastionOS freestanding C++ standard library.
//
// Bit manipulation utilities — all backed by compiler builtins.
//
//===----------------------------------------------------------------------===//

#ifndef _LIBBASTION_BIT_BIT_H
#define _LIBBASTION_BIT_BIT_H

#include <__config>
#include <__type_traits/integral_constant.h>
#include <__type_traits/primary_categories.h>
#include <__type_traits/type_properties.h>
#include <cstdint>

_LIBBASTION_BEGIN_NAMESPACE_STD

// ── endian ──────────────────────────────────────────────────────────────────

enum class endian {
#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
    little = __ORDER_LITTLE_ENDIAN__,
    big    = __ORDER_BIG_ENDIAN__,
    native = __BYTE_ORDER__,
#else
    little = 0,
    big    = 1,
    native = 0, // assume little-endian
#endif
};

// ── bit_cast ────────────────────────────────────────────────────────────────

template<class _To, class _From>
_LIBBASTION_NODISCARD constexpr _To bit_cast(const _From& __from) noexcept {
    static_assert(sizeof(_To) == sizeof(_From), "bit_cast requires same size types");
    static_assert(__is_trivially_copyable(_To), "bit_cast target must be trivially copyable");
    static_assert(__is_trivially_copyable(_From), "bit_cast source must be trivially copyable");
    return __builtin_bit_cast(_To, __from);
}

// ── Helpers for unsigned integer operations ─────────────────────────────────

namespace __detail {

template<class _Tp>
concept __unsigned_integer = is_unsigned_v<_Tp> && is_integral_v<_Tp> && !__is_same(_Tp, bool);

} // namespace __detail

// ── countl_zero / countl_one ────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int countl_zero(_Tp __x) noexcept {
    if (__x == 0) return static_cast<int>(sizeof(_Tp) * __CHAR_BIT__);
    if constexpr (sizeof(_Tp) <= sizeof(unsigned int))
        return __builtin_clz(static_cast<unsigned int>(__x)) - (sizeof(unsigned int) - sizeof(_Tp)) * __CHAR_BIT__;
    else if constexpr (sizeof(_Tp) <= sizeof(unsigned long))
        return __builtin_clzl(static_cast<unsigned long>(__x));
    else
        return __builtin_clzll(static_cast<unsigned long long>(__x));
}

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int countl_one(_Tp __x) noexcept {
    return countl_zero(static_cast<_Tp>(~__x));
}

// ── countr_zero / countr_one ────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int countr_zero(_Tp __x) noexcept {
    if (__x == 0) return static_cast<int>(sizeof(_Tp) * __CHAR_BIT__);
    if constexpr (sizeof(_Tp) <= sizeof(unsigned int))
        return __builtin_ctz(static_cast<unsigned int>(__x));
    else if constexpr (sizeof(_Tp) <= sizeof(unsigned long))
        return __builtin_ctzl(static_cast<unsigned long>(__x));
    else
        return __builtin_ctzll(static_cast<unsigned long long>(__x));
}

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int countr_one(_Tp __x) noexcept {
    return countr_zero(static_cast<_Tp>(~__x));
}

// ── popcount ────────────────────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int popcount(_Tp __x) noexcept {
    if constexpr (sizeof(_Tp) <= sizeof(unsigned int))
        return __builtin_popcount(static_cast<unsigned int>(__x));
    else if constexpr (sizeof(_Tp) <= sizeof(unsigned long))
        return __builtin_popcountl(static_cast<unsigned long>(__x));
    else
        return __builtin_popcountll(static_cast<unsigned long long>(__x));
}

// ── has_single_bit ──────────────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr bool has_single_bit(_Tp __x) noexcept {
    return __x != 0 && (__x & (__x - 1)) == 0;
}

// ── bit_width ───────────────────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr int bit_width(_Tp __x) noexcept {
    return static_cast<int>(sizeof(_Tp) * __CHAR_BIT__) - countl_zero(__x);
}

// ── bit_ceil / bit_floor ────────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr _Tp bit_ceil(_Tp __x) noexcept {
    if (__x <= 1) return _Tp(1);
    return _Tp(1) << bit_width(static_cast<_Tp>(__x - 1));
}

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr _Tp bit_floor(_Tp __x) noexcept {
    if (__x == 0) return 0;
    return _Tp(1) << (bit_width(__x) - 1);
}

// ── rotl / rotr ─────────────────────────────────────────────────────────────

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr _Tp rotl(_Tp __x, int __s) noexcept {
    constexpr int _Nd = sizeof(_Tp) * __CHAR_BIT__;
    int __r = __s % _Nd;
    if (__r == 0) return __x;
    if (__r < 0)  return rotr(__x, -__r);
    return static_cast<_Tp>((__x << __r) | (__x >> (_Nd - __r)));
}

template<__detail::__unsigned_integer _Tp>
_LIBBASTION_NODISCARD constexpr _Tp rotr(_Tp __x, int __s) noexcept {
    constexpr int _Nd = sizeof(_Tp) * __CHAR_BIT__;
    int __r = __s % _Nd;
    if (__r == 0) return __x;
    if (__r < 0)  return rotl(__x, -__r);
    return static_cast<_Tp>((__x >> __r) | (__x << (_Nd - __r)));
}

// ── byteswap (C++23) ───────────────────────────────────────────────────────

template<class _Tp>
    requires is_integral_v<_Tp>
_LIBBASTION_NODISCARD constexpr _Tp byteswap(_Tp __val) noexcept {
    if constexpr (sizeof(_Tp) == 1) {
        return __val;
    } else if constexpr (sizeof(_Tp) == 2) {
        return static_cast<_Tp>(__builtin_bswap16(static_cast<uint16_t>(__val)));
    } else if constexpr (sizeof(_Tp) == 4) {
        return static_cast<_Tp>(__builtin_bswap32(static_cast<uint32_t>(__val)));
    } else if constexpr (sizeof(_Tp) == 8) {
        return static_cast<_Tp>(__builtin_bswap64(static_cast<uint64_t>(__val)));
    }
}

_LIBBASTION_END_NAMESPACE_STD

#endif // _LIBBASTION_BIT_BIT_H