1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QENDIAN_P_H
5#define QENDIAN_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qendian.h>
19#include <QtCore/private/qglobal_p.h>
20
21QT_BEGIN_NAMESPACE
22
23enum class QSpecialIntegerBitfieldInitializer {};
24constexpr QSpecialIntegerBitfieldInitializer QSpecialIntegerBitfieldZero{};
25
26template<class S>
27class QSpecialIntegerStorage
28{
29public:
30 using UnsignedStorageType = std::make_unsigned_t<typename S::StorageType>;
31
32 constexpr QSpecialIntegerStorage() = default;
33 constexpr QSpecialIntegerStorage(QSpecialIntegerBitfieldInitializer) : val(0) {}
34 constexpr QSpecialIntegerStorage(UnsignedStorageType initial) : val(initial) {}
35
36 UnsignedStorageType val;
37};
38
39template<class S, int pos, int width, class T = typename S::StorageType>
40class QSpecialIntegerAccessor;
41
42template<class S, int pos, int width, class T = typename S::StorageType>
43class QSpecialIntegerConstAccessor
44{
45 Q_DISABLE_COPY_MOVE(QSpecialIntegerConstAccessor)
46public:
47 using Storage = const QSpecialIntegerStorage<S>;
48 using Type = T;
49 using UnsignedType = std::make_unsigned_t<T>;
50
51 operator Type() const noexcept
52 {
53 if constexpr (std::is_signed_v<Type>) {
54 UnsignedType i = S::fromSpecial(storage->val);
55 i <<= (sizeof(Type) * 8) - width - pos;
56 Type t = Type(i);
57 t >>= (sizeof(Type) * 8) - width;
58 return t;
59 }
60 return (S::fromSpecial(storage->val) & mask()) >> pos;
61 }
62
63 bool operator!() const noexcept { return !(storage->val & S::toSpecial(mask())); }
64
65 static constexpr UnsignedType mask() noexcept
66 {
67 if constexpr (width == sizeof(UnsignedType) * 8) {
68 static_assert(pos == 0);
69 return ~UnsignedType(0);
70 } else {
71 return ((UnsignedType(1) << width) - 1) << pos;
72 }
73 }
74
75private:
76 template<class Storage, typename... Accessors>
77 friend class QSpecialIntegerBitfieldUnion;
78 friend class QSpecialIntegerAccessor<S, pos, width, T>;
79
80 explicit QSpecialIntegerConstAccessor(Storage *storage) : storage(storage) {}
81
82 friend bool operator==(const QSpecialIntegerConstAccessor<S, pos, width, T> &i,
83 const QSpecialIntegerConstAccessor<S, pos, width, T> &j) noexcept
84 {
85 return ((i.storage->val ^ j.storage->val) & S::toSpecial(mask())) == 0;
86 }
87
88 friend bool operator!=(const QSpecialIntegerConstAccessor<S, pos, width, T> &i,
89 const QSpecialIntegerConstAccessor<S, pos, width, T> &j) noexcept
90 {
91 return ((i.storage->val ^ j.storage->val) & S::toSpecial(mask())) != 0;
92 }
93
94 Storage *storage;
95};
96
97template<class S, int pos, int width, class T>
98class QSpecialIntegerAccessor
99{
100 Q_DISABLE_COPY_MOVE(QSpecialIntegerAccessor)
101public:
102 using Const = QSpecialIntegerConstAccessor<S, pos, width, T>;
103 using Storage = QSpecialIntegerStorage<S>;
104 using Type = T;
105 using UnsignedType = std::make_unsigned_t<T>;
106
107 QSpecialIntegerAccessor &operator=(Type t)
108 {
109 UnsignedType i = S::fromSpecial(storage->val);
110 i &= ~Const::mask();
111 i |= (UnsignedType(t) << pos) & Const::mask();
112 storage->val = S::toSpecial(i);
113 return *this;
114 }
115
116 operator Const() { return Const(storage); }
117
118private:
119 template<class Storage, typename... Accessors>
120 friend class QSpecialIntegerBitfieldUnion;
121
122 explicit QSpecialIntegerAccessor(Storage *storage) : storage(storage) {}
123
124 Storage *storage;
125};
126
127template<class S, typename... Accessors>
128class QSpecialIntegerBitfieldUnion
129{
130public:
131 constexpr QSpecialIntegerBitfieldUnion() = default;
132 constexpr QSpecialIntegerBitfieldUnion(QSpecialIntegerBitfieldInitializer initial)
133 : storage(initial)
134 {}
135
136 constexpr QSpecialIntegerBitfieldUnion(
137 typename QSpecialIntegerStorage<S>::UnsignedStorageType initial)
138 : storage(initial)
139 {}
140
141 template<typename A>
142 void set(typename A::Type value)
143 {
144 member<A>() = value;
145 }
146
147 template<typename A>
148 typename A::Type get() const
149 {
150 return member<A>();
151 }
152
153 typename QSpecialIntegerStorage<S>::UnsignedStorageType data() const
154 {
155 return storage.val;
156 }
157
158private:
159 template<typename A>
160 static constexpr bool isAccessor = std::disjunction_v<std::is_same<A, Accessors>...>;
161
162 template<typename A>
163 A member()
164 {
165 static_assert(isAccessor<A>);
166 return A(&storage);
167 }
168
169 template<typename A>
170 typename A::Const member() const
171 {
172 static_assert(isAccessor<A>);
173 return typename A::Const(&storage);
174 }
175
176 QSpecialIntegerStorage<S> storage;
177};
178
179template<typename T, typename... Accessors>
180using QLEIntegerBitfieldUnion
181 = QSpecialIntegerBitfieldUnion<QLittleEndianStorageType<T>, Accessors...>;
182
183template<typename T, typename... Accessors>
184using QBEIntegerBitfieldUnion
185 = QSpecialIntegerBitfieldUnion<QBigEndianStorageType<T>, Accessors...>;
186
187template<typename... Accessors>
188using qint32_le_bitfield_union = QLEIntegerBitfieldUnion<int, Accessors...>;
189template<typename... Accessors>
190using quint32_le_bitfield_union = QLEIntegerBitfieldUnion<uint, Accessors...>;
191template<typename... Accessors>
192using qint32_be_bitfield_union = QBEIntegerBitfieldUnion<int, Accessors...>;
193template<typename... Accessors>
194using quint32_be_bitfield_union = QBEIntegerBitfieldUnion<uint, Accessors...>;
195
196template<int pos, int width, typename T = int>
197using qint32_le_bitfield_member
198 = QSpecialIntegerAccessor<QLittleEndianStorageType<int>, pos, width, T>;
199template<int pos, int width, typename T = uint>
200using quint32_le_bitfield_member
201 = QSpecialIntegerAccessor<QLittleEndianStorageType<uint>, pos, width, T>;
202template<int pos, int width, typename T = int>
203using qint32_be_bitfield_member
204 = QSpecialIntegerAccessor<QBigEndianStorageType<int>, pos, width, T>;
205template<int pos, int width, typename T = uint>
206using quint32_be_bitfield_member
207 = QSpecialIntegerAccessor<QBigEndianStorageType<uint>, pos, width, T>;
208
209QT_END_NAMESPACE
210
211#endif // QENDIAN_P_H
212

source code of qtbase/src/corelib/global/qendian_p.h