#pragma once #include "assert.h" #include #include #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 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>> BS_CONSTEXPR out& operator=(U&& arg) noexcept(std::is_nothrow_assignable_v) { m_Value = std::forward(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 class out { public: BS_CONSTEXPR out(T& value) noexcept : m_Value(value) {} out(const out&) = delete; out(out&&) = delete; template>> BS_CONSTEXPR out& operator=(U&& arg) noexcept(std::is_nothrow_assignable_v) { m_Value = std::forward(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 using in = std::conditional_t<(sizeof(T) <= 16 && std::is_trivially_copy_constructible_v), std::add_const_t, std::add_lvalue_reference_t>>; /** * @brief Passes by reference */ template using inout = std::conditional_t, std::add_lvalue_reference_t>; /** * @brief Test type */ template class finally { public: constexpr finally(Lambda func) noexcept : m_Lambda(func) {} ~finally() { m_Lambda(); } private: Lambda m_Lambda; }; template finally(Lambda func) -> finally; }