diff --git a/CMakeLists.txt b/CMakeLists.txt index c1c28f61..3bf31637 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR) include(GNUInstallDirs) -project(mcl LANGUAGES CXX VERSION 0.1.3) +project(mcl LANGUAGES CXX VERSION 0.1.7) # Project options option(MCL_WARNINGS_AS_ERRORS "Warnings as errors" ON) diff --git a/include/mcl/bit/bit_field.hpp b/include/mcl/bit/bit_field.hpp index e4fca8ef..b967ed4b 100644 --- a/include/mcl/bit/bit_field.hpp +++ b/include/mcl/bit/bit_field.hpp @@ -31,7 +31,7 @@ constexpr T ones(size_t count) { if (count == 0) { return 0; } - return ~static_cast(0) >> (bitsizeof - count); + return static_cast(~static_cast(0)) >> (bitsizeof - count); } /// Create a mask of type T for bits [begin_bit, end_bit] inclusive. @@ -143,11 +143,9 @@ template constexpr T sign_extend(T value) { static_assert(bit_count != 0, "cannot sign-extend zero-sized value"); - constexpr T m = ones(); - if (get_bit(value)) { - return value | ~m; - } - return value; + using S = std::make_signed_t; + constexpr size_t shift_amount = bitsizeof - bit_count; + return static_cast(static_cast(value << shift_amount) >> shift_amount); } /// Sign-extends a value that has bit_count bits to the full bitwidth of type T. @@ -155,11 +153,9 @@ template constexpr T sign_extend(size_t bit_count, T value) { ASSERT_MSG(bit_count != 0, "cannot sign-extend zero-sized value"); - const T m = ones(bit_count); - if (get_bit(bit_count - 1, value)) { - return value | ~m; - } - return value; + using S = std::make_signed_t; + const size_t shift_amount = bitsizeof - bit_count; + return static_cast(static_cast(value << shift_amount) >> shift_amount); } /// Replicate an element across a value of type T. @@ -192,7 +188,7 @@ constexpr T replicate_element(size_t element_size, T value) { if (element_size == bitsizeof) { return value; } - return replicate_element(static_cast(value | (value << element_size)), element_size * 2); + return replicate_element(element_size * 2, static_cast(value | (value << element_size))); } template diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a25392b3..92d2d8e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ target_include_directories(mcl ) target_compile_options(mcl PRIVATE ${MCL_CXX_FLAGS}) target_link_libraries(mcl PUBLIC $) +set_property(TARGET mcl PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(merry::mcl ALIAS mcl) include(CreateTargetDirectoryGroups) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1b60518d..1619f34c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(mcl-tests + bit/bit_field_tests.cpp main.cpp mp/metavalue_tests.cpp mp/typelist_tests.cpp diff --git a/tests/bit/bit_field_tests.cpp b/tests/bit/bit_field_tests.cpp new file mode 100644 index 00000000..fba31eb5 --- /dev/null +++ b/tests/bit/bit_field_tests.cpp @@ -0,0 +1,41 @@ +// This file is part of the mcl project. +// Copyright (c) 2022 merryhime +// SPDX-License-Identifier: MIT + +#include +#include + +#include +#include +#include + +TEST_CASE("mcl::bit::ones", "[bit]") { + const std::array cases{ + std::make_tuple(0, 0x00), + std::make_tuple(1, 0x01), + std::make_tuple(2, 0x03), + std::make_tuple(3, 0x07), + std::make_tuple(4, 0x0f), + std::make_tuple(5, 0x1f), + std::make_tuple(6, 0x3f), + std::make_tuple(7, 0x7f), + std::make_tuple(8, 0xff), + }; + + for (const auto [count, expected] : cases) { + REQUIRE(mcl::bit::ones(count) == expected); + REQUIRE(mcl::bit::ones(count) == expected); + REQUIRE(mcl::bit::ones(count) == expected); + REQUIRE(mcl::bit::ones(count) == expected); + REQUIRE(mcl::bit::ones(count) == expected); + REQUIRE(mcl::bit::ones(count) == expected); + } +} + +static_assert(mcl::bit::ones<3, u8>() == 0x7); +static_assert(mcl::bit::ones<15, u16>() == 0x7fff); +static_assert(mcl::bit::ones<16, u16>() == 0xffff); +static_assert(mcl::bit::ones<31, u32>() == 0x7fff'ffff); +static_assert(mcl::bit::ones<32, u32>() == 0xffff'ffff); +static_assert(mcl::bit::ones<63, u64>() == 0x7fff'ffff'ffff'ffff); +static_assert(mcl::bit::ones<64, u64>() == 0xffff'ffff'ffff'ffff);