#define KBLIB_DEF_MACROS 1 #include "kblib/bits.h" #include "catch.hpp" #include "kblib/hash.h" template struct print; // These tests are POSIX-based, so spell out that requirement. static_assert(CHAR_BIT == 8, "8-bit bytes"); static_assert(sizeof(short) == 2, "16-bit shorts"); static_assert(sizeof(int) == 4, "32-bit ints"); static_assert(sizeof(long) == 8, "64-bit longs"); static_assert(std::is_same, unsigned char>::value, "uint_smallest_t"); static_assert(std::is_same, unsigned char>::value, "uint_smallest_t"); static_assert(std::is_same, unsigned char>::value, "uint_smallest_t"); static_assert(std::is_same, unsigned short>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned short>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned short>::value, "uint_smallest_t"); static_assert(std::is_same, unsigned int>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned int>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned int>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned long>::value, "uint_smallest_t"); static_assert( std::is_same, unsigned long>::value, "uint_smallest_t"); // print> t{}; static_assert(std::is_same, signed char>::value, "int_smallest_t"); static_assert(std::is_same, signed char>::value, "int_smallest_t"); static_assert(std::is_same, signed short>::value, "int_smallest_t"); static_assert(std::is_same, signed short>::value, "int_smallest_t"); static_assert(std::is_same, signed int>::value, "int_smallest_t"); static_assert(std::is_same, signed int>::value, "int_smallest_t"); static_assert(std::is_same, signed int>::value, "int_smallest_t"); static_assert( std::is_same, signed long>::value, "int_smallest_t"); #if KBLIB_USE_CXX17 TEST_CASE("test_trie") { kblib::compact_bit_trie test; REQUIRE(test.insert({0b1000100010000000, 10}, 1)); // has UB, so I hardcoded a test failure as a reminder // std::cout<::value, int>::type = 0> operator T() const { T t; std::memcpy(&t, buf, sizeof(T)); return t; } }; std::vector buf; KBLIB_NODISCARD auto operator[](std::size_t p) -> ret_proxy { return {&buf[p]}; } }; using kblib::bitfield; union Addr1 { bitfield<0, 16, uint16_t> raw{}; bitfield<0, 5, uint16_t> cX; bitfield<5, 5, uint16_t> cY; bitfield<10, 2, uint16_t> nt; bitfield<12, 3, uint16_t> fY; bitfield<0, 8, uint16_t> l; bitfield<8, 7, uint16_t> h; bitfield<0, 14, uint16_t> addr; }; TEST_CASE("bitfields1") { static_assert(sizeof(Addr1) == 2, ""); Addr1 a; a.l = 0b1100'1100; a.h(0b001'1001); REQUIRE(a.raw == 0b0001'1001'1100'1100); REQUIRE(a.cX() == 0b0'1100); REQUIRE(a.cY == 0b0'1110); REQUIRE(a.nt == 0b10); REQUIRE(a.fY == 0b001); } // Loopy's VRAM address struct Addr { std::uint16_t raw{}; BITFIELD(0, 5, cX, raw) BITFIELD(5, 5, cY, raw) BITFIELD(10, 2, nt, raw) BITFIELD(12, 3, fY, raw) BITFIELD(0, 8, l, raw) BITFIELD(8, 7, h, raw) BITFIELD(0, 14, addr, raw) }; KBLIB_NODISCARD constexpr auto test_bitfield() -> Addr { Addr a; a.l() = 0b1100'1100; a.h(0b001'1001); return a; } TEST_CASE("bitfields") { static_assert(sizeof(Addr) == 2, ""); constexpr Addr a = test_bitfield(); static_assert(a.raw == 0b0001'1001'1100'1100, ""); static_assert(a.cX() == 0b0'1100, ""); static_assert(a.cY() == 0b0'1110, ""); static_assert(a.nt() == 0b10, ""); static_assert(a.fY() == 0b001, ""); static_assert(Addr::get_cX_v == 0b0'1100, ""); static_assert(Addr::get_cY_v == 0b0'1110, ""); static_assert(Addr::get_nt_v == 0b10, ""); static_assert(Addr::get_fY_v == 0b001, ""); constexpr Addr b = {Addr::set_h_v<0b001'1001, Addr::set_l_v<0b1100'1100>>}; static_assert(Addr::get_cX_v == 0b0'1100, ""); static_assert(Addr::get_cY_v == 0b0'1110, ""); static_assert(Addr::get_nt_v == 0b10, ""); static_assert(Addr::get_fY_v == 0b001, ""); } #if KBLIB_USE_CXX17 union punner { char storage[sizeof(char*)]{}; kblib::union_pun ptr; kblib::union_pun val; kblib::union_pun s; }; TEST_CASE("union_punning") { punner pun; std::uintptr_t ival = 0xABCD; kblib::to_bytes_le(ival, pun.storage); REQUIRE(std::equal(std::begin(pun.storage), std::begin(pun.storage) + 4, "\xCD\xAB\0\0")); REQUIRE(pun.val == ival); std::array ustr{u'\xABCD', u'\0'}; decltype(ustr) t = pun.s; REQUIRE(t == ustr); REQUIRE(decltype(ustr)(pun.s) == ustr); pun.val = 0; const char* c = ""; pun.ptr = c; REQUIRE(pun.val == kblib::byte_cast(c)); } TEST_CASE("punning") { kblib::punner pun{}; void(kblib::get<0>(pun)); void(pun.get<1>()); std::uintptr_t ival = 0xABCD; kblib::to_bytes_le(ival, pun.get<0>()); REQUIRE(std::equal(std::begin(pun.get<0>()), std::begin(pun.get<0>()) + 4, "\xCD\xAB\0\0")); REQUIRE(pun.get<2>() == ival); std::array ustr{u'\xABCD', u'\0'}; decltype(ustr) t = pun.get<3>(); REQUIRE(t == ustr); REQUIRE(decltype(ustr)(pun.get<3>()) == ustr); pun.get<2>() = 0; const char* c = ""; pun.get<1>() = c; REQUIRE(pun.get<2>() == kblib::byte_cast(c)); } #endif