124 lines
2.3 KiB
C
124 lines
2.3 KiB
C
|
#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>;
|
||
|
}
|