diff --git a/src/common/marshal/bitfield.h b/src/common/marshal/bitfield.h new file mode 100755 index 00000000000..9207978ab21 --- /dev/null +++ b/src/common/marshal/bitfield.h @@ -0,0 +1,157 @@ +#include +#include +#include + +namespace marshal +{ + typedef std::uint64_t max_bit_type; + + template + struct bitsection + { + static_assert(sizeof(T) <= sizeof(marshal::max_bit_type), "Type size exceeds highest allowed type size."); +#if !defined(__GNUC__) || __GNUC__ > 5 + static_assert(std::is_trivially_copyable::value, "The type of a bit section needs to be trivially copyable."); +#endif + + static std::size_t const size = Size; + typedef T type; + }; + + template + class bitfield + { + private: + + unsigned char buffer[Bytes] = {}; + + template + struct section_at + { + typedef typename section_at::section section; + }; + + template + struct section_at<0, Section, Rest...> + { + typedef Section section; + }; + + template + struct offset_at + { + static std::size_t const value = offset_at::value + section_at::section::size; + }; + + template + struct offset_at<0, Section, Rest...> + { + static std::size_t const value = 0; + }; + + template + class mirror + { + private: + typedef typename section_at::section section; + static std::size_t const bit_offset = offset_at::value; + static std::size_t const bit_shift = bit_offset % 8; + static std::size_t const byte_offset = bit_offset / 8; + static std::size_t const byte_length = ((bit_shift + section::size + 7) & ~7) / 8; + + unsigned char* buffer; + union + { + marshal::max_bit_type value; + std::array array; + }; + + static_assert(Index < sizeof...(Sections), "Index out of bit field range."); + static_assert(byte_length <= sizeof(marshal::max_bit_type), "Invalid type with size larger than the maximum allowed."); + + public: + mirror(unsigned char* original) + : buffer{original + byte_offset}, value{0} + {} + + typename section::type operator =(typename section::type const& other) + { + std::copy_n(buffer, byte_length, array.data()); + value &= ~(((1 << section::size) - 1) << bit_shift); + value |= (other & ((1 << section::size) - 1)) << bit_shift; + std::copy_n(array.data(), byte_length, buffer); + return other; + } + + operator typename section::type() + { + std::copy_n(buffer, byte_length, array.data()); + return static_cast((value >> bit_shift) & ((1 << section::size) - 1)); + } + }; + + public: + + static_assert(offset_at::value <= 8 * Bytes, "Provided bit sections exceed available space."); + + bitfield() + {} + + template + bitfield(C const& cont) + : bitfield(cont.begin(), cont.end()) + {} + + template + bitfield(char(&other)[N]) + : bitfield(other, other + N) + {} + + template + bitfield(unsigned char(&other)[N]) + : bitfield(other, other + N) + {} + + template + bitfield(It const& start, It const& end) + { + static_assert(sizeof(*start) == 1, "Invalid range constructor. Underlying iterator type needs to be char or unsigned char."); + + std::copy(start, end, buffer); + } + + template + typename section_at::section::type set(R value) + { + return mirror{buffer} = value; + } + + template + typename section_at::section::type get() + { + return mirror(buffer); + } + + std::size_t size() const + { + return Bytes; + } + + unsigned char* data() + { + return buffer; + } + }; + + template + auto set(bitfield bf) -> decltype(bf.template set()) + { + return bf.template set(); + } + + template + auto get(bitfield bf) -> decltype(bf.template get()) + { + return bf.template get(); + } +} diff --git a/win32/DSGame-server/DSGame-server.vcxproj b/win32/DSGame-server/DSGame-server.vcxproj index 995b222402f..c832927129e 100644 --- a/win32/DSGame-server/DSGame-server.vcxproj +++ b/win32/DSGame-server/DSGame-server.vcxproj @@ -196,6 +196,7 @@ + diff --git a/win32/DSGame-server/DSGame-server.vcxproj.filters b/win32/DSGame-server/DSGame-server.vcxproj.filters index c37e7e49308..fb5c370de6f 100644 --- a/win32/DSGame-server/DSGame-server.vcxproj.filters +++ b/win32/DSGame-server/DSGame-server.vcxproj.filters @@ -830,6 +830,9 @@ Header Files\common\marshal + + Header Files\common\marshal +