1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_BASE_BIT_HELPER_H
17#define ECMASCRIPT_BASE_BIT_HELPER_H
18
19#include <cstdint>
20#include <cstring>
21#include <limits>
22#include <type_traits>
23
24namespace panda::ecmascript::base {
25constexpr uint64_t pureNaN = 0x7FF8ULL << 48U; // Be sure return the NaN that is safe.
26template <class S, class R>
27union Data {
28    S src;
29    R dst;
30};
31
32template <typename T>
33inline T ReadBuffer(void **buffer, size_t offset)
34{
35    T result = *(reinterpret_cast<T *>(*buffer));
36    *buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(*buffer) + offset);
37    return result;
38}
39
40template <typename T>
41inline T ReadBuffer(void **buffer)
42{
43    T result = *(reinterpret_cast<T *>(*buffer));
44    *buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(*buffer) + result.offset_);
45    return result;
46}
47
48inline char *ReadBuffer(void **buffer)
49{
50    auto result = reinterpret_cast<char *>(*buffer);
51    *buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(*buffer) + strlen(result) + 1);
52    return result;
53}
54
55template <typename T>
56inline T *ReadBufferInSize(void **buffer)
57{
58    T *result = reinterpret_cast<T *>(*buffer);
59    *buffer = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(*buffer) + result->Size());
60    return result;
61}
62
63template <typename T>
64inline constexpr uint32_t CountLeadingZeros(T value)
65{
66    constexpr size_t RADIX = 2;
67    static_assert(std::is_integral<T>::value, "T must be integral");
68    static_assert(std::is_unsigned<T>::value, "T must be unsigned");
69    static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!");
70    static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)");
71    if (value == 0) {
72        return sizeof(T) * 8; // 8: Each byte has 8 bits
73    }
74    if (sizeof(T) == sizeof(uint64_t)) {
75        return __builtin_clzll(static_cast<uint64_t>(value));
76    }
77    // 32 : 32 mean the bits of type T is less than 32
78    return __builtin_clz(static_cast<uint32_t>(value)) - (32 - std::numeric_limits<T>::digits);
79}
80
81inline constexpr uint32_t CountLeadingZeros32(uint32_t value)
82{
83    return CountLeadingZeros(value);
84}
85
86inline constexpr uint32_t CountLeadingZeros64(uint64_t value)
87{
88    return CountLeadingZeros(value);
89}
90
91inline constexpr uint32_t CountLeadingOnes32(uint32_t value)
92{
93    return CountLeadingZeros(~value);
94}
95
96inline constexpr uint32_t CountLeadingOnes64(uint64_t value)
97{
98    return CountLeadingZeros(~value);
99}
100
101template <typename T>
102inline constexpr uint32_t CountTrailingZeros(T value)
103{
104    constexpr size_t RADIX = 2;
105    static_assert(std::is_integral<T>::value, "T must be integral");
106    static_assert(std::is_unsigned<T>::value, "T must be unsigned");
107    static_assert(std::numeric_limits<T>::radix == RADIX, "Unexpected radix!");
108    static_assert(sizeof(T) == sizeof(uint64_t) || sizeof(T) <= sizeof(uint32_t), "Unsupported sizeof(T)");
109    if (value == 0) {
110        return sizeof(T) * 8; // 8: Each byte has 8 bits
111    }
112    if (sizeof(T) == sizeof(uint64_t)) {
113        return __builtin_ctzll(static_cast<uint64_t>(value));
114    }
115    return __builtin_ctz(static_cast<uint32_t>(value));
116}
117
118inline constexpr unsigned CountTrailingZeros32(uint32_t value)
119{
120    return CountTrailingZeros(value);
121}
122
123inline constexpr unsigned CountTrailingZeros64(uint64_t value)
124{
125    return CountTrailingZeros(value);
126}
127
128inline constexpr unsigned CountTrailingOnes32(uint32_t value)
129{
130    return CountTrailingZeros(~value);
131}
132
133inline constexpr unsigned CountTrailingOnes64(uint64_t value)
134{
135    return CountTrailingZeros(~value);
136}
137
138/// isMask_64 - This function returns true if the argument is a non-empty
139/// sequence of ones starting at the least significant bit with the remainder
140/// zero (64 bit version).
141constexpr inline bool IsMask_64(uint64_t Value)
142{
143    return Value && ((Value + 1) & Value) == 0;
144}
145
146/// isShiftedMask_64 - This function returns true if the argument contains a
147/// non-empty sequence of ones with the remainder zero (64 bit version.)
148constexpr inline bool IsShiftedMask_64(uint64_t Value)
149{
150    return Value && IsMask_64((Value - 1) | Value);
151}
152
153template <typename T>
154constexpr T RoundUp(T x, size_t n)
155{
156    static_assert(std::is_integral<T>::value, "T must be integral");
157    return (static_cast<size_t>(x) + n - 1U) & (-n);
158}
159
160template <class To, class From>
161inline To bit_cast(const From &src) noexcept  // NOLINT(readability-identifier-naming)
162{
163    static_assert(sizeof(To) == sizeof(From), "size of the types must be equal");
164    // The use of security functions 'memcpy_s' here will have a greater impact on performance
165    Data<From, To> data;
166    data.src = src;
167    return data.dst;
168}
169
170template <typename T>
171inline constexpr uint32_t BitNumbers()
172{
173    constexpr int BIT_NUMBER_OF_CHAR = 8;
174    return sizeof(T) * BIT_NUMBER_OF_CHAR;
175}
176}  // panda::ecmascript::base
177#endif
178