Вот мой шаблон класса и один из его конструкторов, который будет создавать тип T
с размером N
в байтах от типа P
с размером M
в байтах.Конструктор также принимает индекс u8.
Индекс работает на основе диапазона:
// pseudo code
lower bound is >= 0 in all cases
upper bound depends on sizeof(T) & sizeof(P) therefore
if (M > N) then
idx <= (M / N) - 1
else
idx <= 0;
Вот шаблон класса и его конструктор:
// Actual class implementation without the include files and
// of the using's and other constructors.
using u8 = std::uint8_t;
// etc. u16, u32 & u64...
template<typename T>
struct Register {
T data;
T value;
std::bitset<sizeof(T) * CHAR_BIT> bits;
template<typename P>
Register(const P val, const u8 idx) :
data{ static_cast<T>((val >> std::size(bits) * idx) &
std::numeric_limits<std::make_unsigned_t<T>>::max()) },
value{ data },
bits{ data }
{
// Reg8 From: 16 idx=[0,1], 32 idx=[0,3], 64 idx=[0,7]
// Reg16 From: 32 idx=[0,1], 64 idx=[0,3]
// Reg32 From: 64 idx=[0,1]
constexpr u16 sizeT = sizeof(T);
constexpr u16 sizeP = sizeof(P);
assert((idx >= 0) && ((sizeP > sizeT) ? (idx <= ((sizeP / sizeT) - 1)) : (idx <= 0)));
}
};
// I for got to add these:
using Reg8 = Register<u8>;
using Reg16 = Register<u16>
using Reg32 = Register<u32>
using Reg64 = Register<u64>
Вот базовое визуальное представление этого конструктора в действии. Я буду использовать u8
и u16
для простоты
// pseudo code:
// low byte always farthest to right
// high byte always farthest to left
u16 val{ 0x69BC };
Reg8 r8a{val, 0); // get byte from index 1 or low byte
r8.value = 188
r8.value in hex = 0xBC;
r8.bits = 1011110;
Reg8 r8b{val, 1); // get byte from index 1 or high byte
r8.value = 105;
r8.value in hex = 0x69;
r8.bits = 01101001
И это работает для любого из четырех размеров типа unsigned int с u8 = 1 байт, u16= 2 байта, u32 = 4 байта и u64 = 8 байтов.
На этот раз, если (M
Я собираюсь либо скорректировать этот конструктор, либо создать перегрузку.Здесь мне нужно знать, как выяснить, как сделать обратное тому, что описано выше.
Я буду использовать то же значение u16, что и выше: Но на этот раз мы собираемся построить Reg64 из него синдекс.Диапазон этого индекса будет [0,3] Что-нибудь после 3, и конструктор будет утверждать.
u16 val{ 0x69BC };
Reg64 r64a( val, 0 );
Reg64 r64b( val, 1 );
Reg64 r64c( val, 2 );
Reg64 r64d( val, 3 );
// Reg64 r64x(val, x > 3); Assertion Failure
Здесь я хочу вставить байтовый шаблон значения типа u16 в соответствующее положение слова с индексом0 начиная справаЧтобы упростить это, я не собираюсь использовать двоичную последовательность, поэтому я просто буду использовать шестнадцатеричное обозначение того, что должен делать конструктор в каждом из четырех случаев.
// u16 val{ 0x69BC }; // visual reference
r64a.value in hex: = in bin: 0x0000 0000 0000 69BC
r64b.value in hex: = in bin: 0x0000 0000 69BC 0000
r64c.value in hex: = in bin 0x0000 69BC 0000 0000
r64d.value in hex: = in bin: 0x69BC 0000 0000 0000
r64a.bits = bin rep of above ... and so one for 46b,c&d.
Поэтому, когда я оглядываюсь назад наконструктор из извлечения для элемента данных
data{ static_cast<T>((val >> std::size(bits) * idx) &
std::numeric_limits<std::make_unsigned_t<T>>::max()) },
и условия утверждения:
assert( (idx >= 0) &&
((sizeP > sizeT) ?
(idx <= ((sizeP / sizeT) - 1)) :
(idx <= 0))
);
Оба они должны быть обращены или скорректированы.
Вот мой набор связанных вопросов и проблем:
- Смогу ли я использовать один и тот же конструктор для выполнения обеих ролей?Или я должен написать перегруженную версию этого конструктора?
- Что касается формулы утверждения, я могу понять это достаточно легко, так что никаких проблем нет.Для вставки байтов в заданном месте индекса;это то, что я пытаюсь понять.Любая помощь здесь будет очень полезна с операциями сдвига и логической логикой.
- Наконец, в отношении конструктора;как указано выше, сначала инициализируются данные, а затем из этого строится
bitset
.Должен ли я сначала инициализировать bitset
, а затем соответственно установить для него значения и данные, или же лучше подойдет шаблон вспомогательной функции?