Skip to content

Commit 7ae9afe

Browse files
committed
Adding bitfield.hh
1 parent 9c3d3a1 commit 7ae9afe

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

src/mips/common/util/bitfield.hh

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
3+
MIT License
4+
5+
Copyright (c) 2025 PCSX-Redux authors
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in all
15+
copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23+
SOFTWARE.
24+
25+
*/
26+
27+
#include <stdint.h>
28+
29+
#include <concepts>
30+
#include <type_traits>
31+
32+
#include "util.h"
33+
34+
namespace Utilities {
35+
36+
namespace BitFieldInternal {
37+
38+
template <typename T>
39+
struct DefaultBitSize {
40+
static constexpr unsigned size = sizeof(T) * 8;
41+
};
42+
43+
template <>
44+
struct DefaultBitSize<bool> {
45+
static constexpr unsigned size = 1;
46+
};
47+
48+
template <typename... T>
49+
struct ComputeStorage {
50+
static constexpr unsigned size() { return (sizeInBits() + 7) / 8; }
51+
52+
private:
53+
static constexpr unsigned sizeInBits() { return recSize<0, T...>(); }
54+
template <unsigned index>
55+
static constexpr unsigned recSize() {
56+
return 0;
57+
}
58+
template <unsigned index, typename One, typename... Rest>
59+
static constexpr unsigned recSize() {
60+
return One::Width + recSize<index + 1, Rest...>();
61+
}
62+
};
63+
64+
template <typename Target, typename... T>
65+
struct ComputeOffset {
66+
static constexpr unsigned offset() { return recOffset<0, T...>(); }
67+
68+
private:
69+
template <unsigned index>
70+
static constexpr unsigned recOffset() {
71+
return 0;
72+
}
73+
template <unsigned index, typename One, typename... Rest>
74+
static constexpr unsigned recOffset() {
75+
if constexpr (std::is_same_v<Target, One>) {
76+
return 0;
77+
} else {
78+
return recOffset<index + 1, Rest...>() + One::Width;
79+
}
80+
}
81+
};
82+
83+
} // namespace BitFieldInternal
84+
85+
template <std::integral T, unsigned width = BitFieldInternal::DefaultBitSize<T>::size>
86+
struct BitSpan {
87+
static constexpr unsigned Width = width;
88+
using Underlying = T;
89+
};
90+
91+
template <typename... T>
92+
struct BitField {
93+
template <typename One>
94+
constexpr typename One::Underlying get() {
95+
if constexpr (std::is_signed_v<typename One::Underlying>) {
96+
return get<BitFieldInternal::ComputeOffset<One, T...>::offset(), One::Width, signed>();
97+
} else if constexpr (std::is_unsigned_v<typename One::Underlying>) {
98+
return get<BitFieldInternal::ComputeOffset<One, T...>::offset(), One::Width, unsigned>();
99+
}
100+
return 0;
101+
}
102+
template <typename One>
103+
constexpr void set(typename One::Underlying v) {
104+
if constexpr (std::is_signed_v<typename One::Underlying>) {
105+
set<BitFieldInternal::ComputeOffset<One, T...>::offset(), One::Width, signed>(v);
106+
} else if constexpr (std::is_unsigned_v<typename One::Underlying>) {
107+
set<BitFieldInternal::ComputeOffset<One, T...>::offset(), One::Width, unsigned>(v);
108+
}
109+
}
110+
111+
private:
112+
template <unsigned offset, unsigned width, std::integral U>
113+
constexpr U get() {
114+
constexpr unsigned firstByteOffset = offset / 8;
115+
constexpr unsigned lastByteOffset = (offset + width - 1) / 8;
116+
constexpr unsigned shift = offset % 8;
117+
constexpr uint32_t mask = (1 << width) - 1;
118+
if constexpr ((firstByteOffset % 4) == 0) {
119+
return reinterpret_cast<const U*>(storage)[firstByteOffset / 4] >> shift & mask;
120+
} else if constexpr ((firstByteOffset % 4) != 0) {
121+
return (loadUnaligned<U>(storage + firstByteOffset, lastByteOffset - firstByteOffset + 1) >> shift) & mask;
122+
}
123+
return 0;
124+
}
125+
template <unsigned offset, unsigned width, std::integral U>
126+
constexpr void set(U v) {
127+
constexpr unsigned firstByteOffset = offset / 8;
128+
constexpr unsigned lastByteOffset = (offset + width - 1) / 8;
129+
constexpr unsigned shift = offset % 8;
130+
constexpr uint32_t mask = (1 << width) - 1;
131+
if constexpr ((firstByteOffset % 4) == 0) {
132+
U* ptr = reinterpret_cast<U*>(storage);
133+
ptr[firstByteOffset / 4] &= ~(mask << shift);
134+
ptr[firstByteOffset / 4] |= (v & mask) << shift;
135+
} else if constexpr ((firstByteOffset % 4) != 0) {
136+
U span = loadUnaligned<U>(storage + firstByteOffset, lastByteOffset - firstByteOffset + 1);
137+
span &= ~(mask << shift);
138+
span |= (v & mask) << shift;
139+
storeUnaligned<U>(storage + firstByteOffset, span, lastByteOffset - firstByteOffset + 1);
140+
}
141+
}
142+
uint8_t storage[BitFieldInternal::ComputeStorage<T...>::size()];
143+
};
144+
145+
} // namespace Utilities

0 commit comments

Comments
 (0)