Attempting to use an external library to handle bitstreams. Isn't going the grreatest.
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef BS_DEBUG_BREAK
|
||||
#if defined(_WIN32) // Windows
|
||||
#define BS_BREAKPOINT() __debugbreak()
|
||||
#elif defined(__linux__) // Linux
|
||||
#include <csignal>
|
||||
#define BS_BREAKPOINT() std::raise(SIGTRAP)
|
||||
#else // Non-supported
|
||||
#define BS_BREAKPOINT() throw
|
||||
#endif
|
||||
|
||||
#define BS_ASSERT(...) if (!(__VA_ARGS__)) { BS_BREAKPOINT(); return false; }
|
||||
#else // BS_DEBUG_BREAK
|
||||
#define BS_ASSERT(...) if (!(__VA_ARGS__)) { return false; }
|
||||
|
||||
#define BS_BREAKPOINT() throw
|
||||
#endif // BS_DEBUG_BREAK
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace bitstream::utility
|
||||
{
|
||||
constexpr inline uint32_t bits_to_represent(uintmax_t n)
|
||||
{
|
||||
uint32_t r = 0;
|
||||
|
||||
if (n >> 32) { r += 32U; n >>= 32U; }
|
||||
if (n >> 16) { r += 16U; n >>= 16U; }
|
||||
if (n >> 8) { r += 8U; n >>= 8U; }
|
||||
if (n >> 4) { r += 4U; n >>= 4U; }
|
||||
if (n >> 2) { r += 2U; n >>= 2U; }
|
||||
if (n >> 1) { r += 1U; n >>= 1U; }
|
||||
|
||||
return r + static_cast<uint32_t>(n);
|
||||
}
|
||||
|
||||
constexpr inline uint32_t bits_in_range(intmax_t min, intmax_t max)
|
||||
{
|
||||
return bits_to_represent(static_cast<uintmax_t>(max) - static_cast<uintmax_t>(min));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace bitstream::utility
|
||||
{
|
||||
inline constexpr auto CHECKSUM_TABLE = []()
|
||||
{
|
||||
constexpr uint32_t POLYNOMIAL = 0xEDB88320;
|
||||
|
||||
std::array<uint32_t, 0x100> table{};
|
||||
|
||||
for (uint32_t i = 0; i < 0x100; ++i)
|
||||
{
|
||||
uint32_t item = i;
|
||||
for (uint32_t bit = 0; bit < 8; ++bit)
|
||||
item = ((item & 1) != 0) ? (POLYNOMIAL ^ (item >> 1)) : (item >> 1);
|
||||
table[i] = item;
|
||||
}
|
||||
|
||||
return table;
|
||||
}();
|
||||
|
||||
inline constexpr uint32_t crc_uint32(const uint8_t* bytes, uint32_t size)
|
||||
{
|
||||
uint32_t result = 0xFFFFFFFF;
|
||||
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
result = CHECKSUM_TABLE[(result & 0xFF) ^ *(bytes + i)] ^ (result >> 8);
|
||||
|
||||
return ~result;
|
||||
}
|
||||
|
||||
inline constexpr uint32_t crc_uint32(const uint8_t* checksum, const uint8_t* bytes, uint32_t size)
|
||||
{
|
||||
uint32_t result = 0xFFFFFFFF;
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
result = CHECKSUM_TABLE[(result & 0xFF) ^ *(checksum + i)] ^ (result >> 8);
|
||||
|
||||
for (uint32_t i = 0; i < size; i++)
|
||||
result = CHECKSUM_TABLE[(result & 0xFF) ^ *(bytes + i)] ^ (result >> 8);
|
||||
|
||||
return ~result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L
|
||||
#include <bit>
|
||||
#else // __cpp_lib_endian
|
||||
#ifndef BS_LITTLE_ENDIAN
|
||||
// Detect with GCC 4.6's macro.
|
||||
#if defined(__BYTE_ORDER__)
|
||||
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define BS_LITTLE_ENDIAN true
|
||||
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define BS_LITTLE_ENDIAN false
|
||||
#else
|
||||
#error "Unknown machine byteorder endianness detected. Need to manually define BS_LITTLE_ENDIAN."
|
||||
#endif
|
||||
// Detect with GLIBC's endian.h.
|
||||
#elif defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
#define BS_LITTLE_ENDIAN true
|
||||
#elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||
#define BS_LITTLE_ENDIAN false
|
||||
#else
|
||||
#error "Unknown machine byteorder endianness detected. Need to manually define BS_LITTLE_ENDIAN."
|
||||
#endif
|
||||
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro.
|
||||
#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||
#define BS_LITTLE_ENDIAN true
|
||||
#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||
#define BS_LITTLE_ENDIAN false
|
||||
// Detect with architecture macros.
|
||||
#elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
|
||||
#define BS_LITTLE_ENDIAN false
|
||||
#elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||
#define BS_LITTLE_ENDIAN true
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||
#define BS_LITTLE_ENDIAN true
|
||||
#else
|
||||
#error "Unknown machine byteorder endianness detected. Need to manually define BS_LITTLE_ENDIAN."
|
||||
#endif
|
||||
#endif // BS_LITTLE_ENDIAN
|
||||
#endif // __cpp_lib_endian
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace bitstream::utility
|
||||
{
|
||||
inline constexpr bool little_endian()
|
||||
{
|
||||
#ifdef BS_LITTLE_ENDIAN
|
||||
#if BS_LITTLE_ENDIAN
|
||||
return true;
|
||||
#else // BS_LITTLE_ENDIAN
|
||||
return false;
|
||||
#endif // BS_LITTLE_ENDIAN
|
||||
#else // defined(BS_LITTLE_ENDIAN)
|
||||
return std::endian::native == std::endian::little;
|
||||
#endif // defined(BS_LITTLE_ENDIAN)
|
||||
}
|
||||
|
||||
inline uint32_t endian_swap32(uint32_t value)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return _byteswap_ulong(value);
|
||||
#elif defined(__linux__)
|
||||
return __builtin_bswap32(value);
|
||||
#else
|
||||
const uint32_t first = (value << 24) & 0xFF000000;
|
||||
const uint32_t second = (value << 8) & 0x00FF0000;
|
||||
const uint32_t third = (value >> 8) & 0x0000FF00;
|
||||
const uint32_t fourth = (value >> 24) & 0x000000FF;
|
||||
|
||||
return first | second | third | fourth;
|
||||
#endif // _WIN32 || __linux__
|
||||
}
|
||||
|
||||
inline uint32_t to_big_endian32(uint32_t value)
|
||||
{
|
||||
if constexpr (little_endian())
|
||||
return endian_swap32(value);
|
||||
else
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "../stream/serialize_traits.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace bitstream::utility
|
||||
{
|
||||
// Check if type has a serializable trait
|
||||
template<typename Void, typename T, typename Stream, typename... Args>
|
||||
struct has_serialize : std::false_type {};
|
||||
|
||||
template<typename T, typename Stream, typename... Args>
|
||||
struct has_serialize<std::void_t<decltype(serialize_traits<T>::serialize(std::declval<Stream&>(), std::declval<Args>()...))>, T, Stream, Args...> : std::true_type {};
|
||||
|
||||
template<typename T, typename Stream, typename... Args>
|
||||
using has_serialize_t = std::void_t<decltype(serialize_traits<T>::serialize(std::declval<Stream&>(), std::declval<Args>()...))>;
|
||||
|
||||
template<typename T, typename Stream, typename... Args>
|
||||
constexpr bool has_serialize_v = has_serialize<void, T, Stream, Args...>::value;
|
||||
|
||||
|
||||
// Check if stream is writing or reading
|
||||
template<typename T, typename R = bool>
|
||||
using is_writing_t = std::enable_if_t<T::writing, R>;
|
||||
|
||||
template<typename T, typename R = bool>
|
||||
using is_reading_t = std::enable_if_t<T::reading, R>;
|
||||
|
||||
|
||||
// Check if type is noexcept, if it exists
|
||||
template<typename Void, typename T, typename Stream, typename... Args>
|
||||
struct is_serialize_noexcept : std::false_type {};
|
||||
|
||||
template<typename T, typename Stream, typename... Args>
|
||||
struct is_serialize_noexcept<std::enable_if_t<has_serialize_v<T, Stream, Args...>>, T, Stream, Args...> :
|
||||
std::bool_constant<noexcept(serialize_traits<T>::serialize(std::declval<Stream&>(), std::declval<Args>()...))> {};
|
||||
|
||||
template<typename T, typename Stream, typename... Args>
|
||||
constexpr bool is_serialize_noexcept_v = is_serialize_noexcept<void, T, Stream, Args...>::value;
|
||||
|
||||
|
||||
// Get the underlying type without &, &&, * or const
|
||||
template<typename T>
|
||||
using base_t = typename std::remove_const_t<std::remove_pointer_t<std::decay_t<T>>>;
|
||||
|
||||
|
||||
// Meta functions for guessing the trait type from the first argument
|
||||
template<typename Void, typename Trait, typename Stream, typename... Args>
|
||||
struct deduce_trait
|
||||
{
|
||||
using type = Trait;
|
||||
};
|
||||
|
||||
// Non-const value
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
struct deduce_trait<std::enable_if_t<
|
||||
!std::is_pointer_v<std::decay_t<Trait>> &&
|
||||
has_serialize_v<base_t<Trait>, Stream, Trait, Args...>>,
|
||||
Trait, Stream, Args...>
|
||||
{
|
||||
using type = base_t<Trait>;
|
||||
};
|
||||
|
||||
// Const value
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
struct deduce_trait<std::enable_if_t<
|
||||
!std::is_pointer_v<std::decay_t<Trait>> &&
|
||||
has_serialize_v<std::add_const_t<base_t<Trait>>, Stream, Trait, Args...>>,
|
||||
Trait, Stream, Args...>
|
||||
{
|
||||
using type = std::add_const_t<base_t<Trait>>;
|
||||
};
|
||||
|
||||
// Non-const pointer
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
struct deduce_trait<std::enable_if_t<
|
||||
std::is_pointer_v<std::decay_t<Trait>> &&
|
||||
has_serialize_v<std::add_pointer_t<base_t<Trait>>, Stream, Trait, Args...>>,
|
||||
Trait, Stream, Args...>
|
||||
{
|
||||
using type = std::add_pointer_t<base_t<Trait>>;
|
||||
};
|
||||
|
||||
// Const pointer
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
struct deduce_trait<std::enable_if_t<
|
||||
std::is_pointer_v<std::decay_t<Trait>> &&
|
||||
has_serialize_v<std::add_pointer_t<std::add_const_t<base_t<Trait>>>, Stream, Trait, Args...>>,
|
||||
Trait, Stream, Args...>
|
||||
{
|
||||
using type = std::add_pointer_t<std::add_const_t<base_t<Trait>>>;
|
||||
};
|
||||
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
using deduce_trait_t = typename deduce_trait<void, Trait, Stream, Args...>::type;
|
||||
|
||||
|
||||
// Shorthands for deduced type_traits
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
using has_deduce_serialize_t = has_serialize_t<deduce_trait_t<Trait, Stream, Args...>, Stream, Trait, Args...>;
|
||||
|
||||
template<typename Trait, typename Stream, typename... Args>
|
||||
constexpr bool is_deduce_serialize_noexcept_v = is_serialize_noexcept_v<deduce_trait_t<Trait, Stream, Args...>, Stream, Trait, Args...>;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
|
||||
#include "assert.h"
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __cpp_constexpr_dynamic_alloc
|
||||
#define BS_CONSTEXPR constexpr
|
||||
#else // __cpp_constexpr_dynamic_alloc
|
||||
#define BS_CONSTEXPR
|
||||
#endif // __cpp_constexpr_dynamic_alloc
|
||||
|
||||
namespace bitstream
|
||||
{
|
||||
#ifdef BS_DEBUG_BREAK
|
||||
template<typename T>
|
||||
class out
|
||||
{
|
||||
public:
|
||||
BS_CONSTEXPR out(T& value) noexcept :
|
||||
m_Value(value),
|
||||
m_Constructed(false) {}
|
||||
|
||||
out(const out&) = delete;
|
||||
|
||||
out(out&&) = delete;
|
||||
|
||||
BS_CONSTEXPR ~out()
|
||||
{
|
||||
if (!m_Constructed)
|
||||
BS_BREAKPOINT();
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_assignable_v<T&, U>>>
|
||||
BS_CONSTEXPR out& operator=(U&& arg) noexcept(std::is_nothrow_assignable_v<T&, U>)
|
||||
{
|
||||
m_Value = std::forward<U>(arg);
|
||||
|
||||
m_Constructed = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BS_CONSTEXPR T* operator->() noexcept
|
||||
{
|
||||
m_Constructed = true;
|
||||
return &m_Value;
|
||||
}
|
||||
|
||||
BS_CONSTEXPR T& operator*() noexcept
|
||||
{
|
||||
m_Constructed = true;
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
private:
|
||||
T& m_Value;
|
||||
bool m_Constructed;
|
||||
};
|
||||
#else
|
||||
template<typename T>
|
||||
class out
|
||||
{
|
||||
public:
|
||||
BS_CONSTEXPR out(T& value) noexcept :
|
||||
m_Value(value) {}
|
||||
|
||||
out(const out&) = delete;
|
||||
|
||||
out(out&&) = delete;
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_assignable_v<T&, U>>>
|
||||
BS_CONSTEXPR out& operator=(U&& arg) noexcept(std::is_nothrow_assignable_v<T&, U>)
|
||||
{
|
||||
m_Value = std::forward<U>(arg);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BS_CONSTEXPR T* operator->() noexcept { return &m_Value; }
|
||||
|
||||
BS_CONSTEXPR T& operator*() noexcept { return m_Value; }
|
||||
|
||||
private:
|
||||
T& m_Value;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Passes by const or const reference depending on size
|
||||
*/
|
||||
template<typename T>
|
||||
using in = std::conditional_t<(sizeof(T) <= 16 && std::is_trivially_copy_constructible_v<T>), std::add_const_t<T>, std::add_lvalue_reference_t<std::add_const_t<T>>>;
|
||||
|
||||
/**
|
||||
* @brief Passes by reference
|
||||
*/
|
||||
template<typename Stream, typename T>
|
||||
using inout = std::conditional_t<Stream::writing, in<T>, std::add_lvalue_reference_t<T>>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test type
|
||||
*/
|
||||
template<typename Lambda>
|
||||
class finally
|
||||
{
|
||||
public:
|
||||
constexpr finally(Lambda func) noexcept :
|
||||
m_Lambda(func) {}
|
||||
|
||||
~finally()
|
||||
{
|
||||
m_Lambda();
|
||||
}
|
||||
|
||||
private:
|
||||
Lambda m_Lambda;
|
||||
};
|
||||
|
||||
template<typename Lambda>
|
||||
finally(Lambda func) -> finally<Lambda>;
|
||||
}
|
||||
Reference in New Issue
Block a user