rpcs3/Utilities/BitField.h

245 lines
4.8 KiB
C
Raw Normal View History

#pragma once
2016-02-01 21:55:43 +00:00
#include "types.h"
2016-02-01 21:55:43 +00:00
template<typename T, uint N>
struct bf_base
{
using type = T;
using vtype = simple_t<type>;
2016-02-01 21:55:43 +00:00
// Datatype bitsize
static constexpr uint bitmax = sizeof(T) * CHAR_BIT; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds");
// Field bitsize
static constexpr uint bitsize = N;
2016-02-01 21:55:43 +00:00
// Value mask
static constexpr vtype vmask = static_cast<vtype>(~std::make_unsigned_t<vtype>{} >> (bitmax - bitsize));
2016-02-01 21:55:43 +00:00
protected:
type m_data;
2016-02-01 21:55:43 +00:00
};
// Bitfield accessor (N bits from I position, 0 is LSB)
template<typename T, uint I, uint N>
struct bf_t : bf_base<T, N>
{
using type = typename bf_t::type;
using vtype = typename bf_t::vtype;
// Field offset
static constexpr uint bitpos = I; static_assert(bitpos + N <= bf_t::bitmax, "bf_t<> error: I out of bounds");
// Get bitmask of size N, at I pos
static constexpr vtype data_mask()
{
return bf_t::vmask << bitpos;
}
2016-02-01 21:55:43 +00:00
// Bitfield extraction helper
template<typename T2, typename = void>
struct extract_impl
{
static_assert(!sizeof(T2), "bf_t<> error: Invalid type");
};
2016-02-01 21:55:43 +00:00
template<typename T2>
struct extract_impl<T2, std::enable_if_t<std::is_unsigned<T2>::value>>
{
// Load unsigned value
2016-02-01 21:55:43 +00:00
static constexpr T2 extract(const T& data)
{
2016-02-01 21:55:43 +00:00
return (data >> bitpos) & bf_t::vmask;
}
};
2016-02-01 21:55:43 +00:00
template<typename T2>
struct extract_impl<T2, std::enable_if_t<std::is_signed<T2>::value>>
{
// Load signed value (sign-extended)
2016-02-01 21:55:43 +00:00
static constexpr T2 extract(const T& data)
{
2016-02-01 21:55:43 +00:00
return data << (bf_t::bitmax - bitpos - N) >> (bf_t::bitmax - N);
}
};
2016-02-01 21:55:43 +00:00
// Bitfield extraction
static constexpr vtype extract(const T& data)
{
2016-02-01 21:55:43 +00:00
return extract_impl<vtype>::extract(data);
}
2016-02-01 21:55:43 +00:00
// Bitfield insertion
static constexpr vtype insert(vtype value)
{
2016-02-01 21:55:43 +00:00
return (value & bf_t::vmask) << bitpos;
}
2016-02-01 21:55:43 +00:00
// Load bitfield value
constexpr operator vtype() const
{
2016-02-01 21:55:43 +00:00
return extract(this->m_data);
}
2016-02-01 21:55:43 +00:00
// Load raw data with mask applied
constexpr T unshifted() const
{
return this->m_data & data_mask();
}
// Optimized bool conversion (must be removed if inappropriate)
explicit constexpr operator bool() const
{
return unshifted() != 0;
}
2016-02-01 21:55:43 +00:00
// Store bitfield value
bf_t& operator =(vtype value)
{
this->m_data = (this->m_data & ~data_mask()) | insert(value);
return *this;
}
vtype operator ++(int)
{
vtype result = *this;
*this = result + 1;
return result;
}
bf_t& operator ++()
{
return *this = *this + 1;
}
vtype operator --(int)
{
vtype result = *this;
*this = result - 1;
return result;
}
bf_t& operator --()
{
return *this = *this - 1;
}
bf_t& operator +=(vtype right)
{
return *this = *this + right;
}
bf_t& operator -=(vtype right)
{
return *this = *this - right;
}
bf_t& operator *=(vtype right)
{
return *this = *this * right;
}
bf_t& operator &=(vtype right)
{
2016-02-01 21:55:43 +00:00
this->m_data &= (right & bf_t::vmask) << bitpos;
return *this;
}
bf_t& operator |=(vtype right)
{
2016-02-01 21:55:43 +00:00
this->m_data |= (right & bf_t::vmask) << bitpos;
return *this;
}
bf_t& operator ^=(vtype right)
{
2016-02-01 21:55:43 +00:00
this->m_data ^= (right & bf_t::vmask) << bitpos;
return *this;
}
};
2016-02-01 21:55:43 +00:00
// Field pack (concatenated from left to right)
template<typename F = void, typename... Fields>
struct cf_t : bf_base<typename F::type, F::bitsize + cf_t<Fields...>::bitsize>
{
using type = typename cf_t::type;
using vtype = typename cf_t::vtype;
2016-02-01 21:55:43 +00:00
// Get disjunction of all "data" masks of concatenated values
static constexpr vtype data_mask()
{
return F::data_mask() | cf_t<Fields...>::data_mask();
}
// Extract all bitfields and concatenate
static constexpr vtype extract(const type& data)
{
return F::extract(data) << cf_t<Fields...>::bitsize | cf_t<Fields...>::extract(data);
}
// Split bitfields and insert them
static constexpr vtype insert(vtype value)
{
return F::insert(value >> cf_t<Fields...>::bitsize) | cf_t<Fields...>::insert(value);
}
// Load value
constexpr operator vtype() const
{
return extract(this->m_data);
}
// Store value
cf_t& operator =(vtype value)
{
this->m_data = (this->m_data & ~data_mask()) | insert(value);
return *this;
}
};
// Empty field pack (recursion terminator)
template<>
struct cf_t<void>
{
static constexpr uint bitsize = 0;
static constexpr uint data_mask()
{
return 0;
}
template<typename T>
static constexpr auto extract(const T& data) -> decltype(+T())
{
return 0;
}
template<typename T>
static constexpr T insert(T value)
{
return 0;
}
};
// Fixed field (provides constant values in field pack)
template<typename T, T V, uint N>
struct ff_t : bf_base<T, N>
{
using type = typename ff_t::type;
using vtype = typename ff_t::vtype;
// Return constant value
static constexpr vtype extract(const type& data)
{
static_assert((V & ff_t::vmask) == V, "ff_t<> error: V out of bounds");
return V;
}
// Get value
operator vtype() const
{
return V;
}
};