//===- llvm/unittests/ADT/BitFieldsTest.cpp - BitFields unit tests --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ADT/Bitfields.h" #include "gtest/gtest.h" using namespace llvm; namespace { TEST(BitfieldsTest, Example) { uint8_t Storage = 0; // Store and retrieve a single bit as bool. using Bool = Bitfield::Element; Bitfield::set(Storage, true); EXPECT_EQ(Storage, 0b00000001); // ^ EXPECT_EQ(Bitfield::get(Storage), true); // Store and retrieve a 2 bit typed enum. // Note: enum underlying type must be unsigned. enum class SuitEnum : uint8_t { CLUBS, DIAMONDS, HEARTS, SPADES }; // Note: enum maximum value needs to be passed in as last parameter. using Suit = Bitfield::Element; Bitfield::set(Storage, SuitEnum::HEARTS); EXPECT_EQ(Storage, 0b00000101); // ^^ EXPECT_EQ(Bitfield::get(Storage), SuitEnum::HEARTS); // Store and retrieve a 5 bit value as unsigned. using Value = Bitfield::Element; Bitfield::set(Storage, 10); EXPECT_EQ(Storage, 0b01010101); // ^^^^^ EXPECT_EQ(Bitfield::get(Storage), 10U); // Interpret the same 5 bit value as signed. using SignedValue = Bitfield::Element; Bitfield::set(Storage, -2); EXPECT_EQ(Storage, 0b11110101); // ^^^^^ EXPECT_EQ(Bitfield::get(Storage), -2); // Ability to efficiently test if a field is non zero. EXPECT_TRUE(Bitfield::test(Storage)); // Alter Storage changes value. Storage = 0; EXPECT_EQ(Bitfield::get(Storage), false); EXPECT_EQ(Bitfield::get(Storage), SuitEnum::CLUBS); EXPECT_EQ(Bitfield::get(Storage), 0U); EXPECT_EQ(Bitfield::get(Storage), 0); Storage = 255; EXPECT_EQ(Bitfield::get(Storage), true); EXPECT_EQ(Bitfield::get(Storage), SuitEnum::SPADES); EXPECT_EQ(Bitfield::get(Storage), 31U); EXPECT_EQ(Bitfield::get(Storage), -1); } TEST(BitfieldsTest, FirstBit) { uint8_t Storage = 0; using FirstBit = Bitfield::Element; // Set true Bitfield::set(Storage, true); EXPECT_EQ(Bitfield::get(Storage), true); EXPECT_EQ(Storage, 0x1ULL); // Set false Bitfield::set(Storage, false); EXPECT_EQ(Bitfield::get(Storage), false); EXPECT_EQ(Storage, 0x0ULL); } TEST(BitfieldsTest, SecondBit) { uint8_t Storage = 0; using SecondBit = Bitfield::Element; // Set true Bitfield::set(Storage, true); EXPECT_EQ(Bitfield::get(Storage), true); EXPECT_EQ(Storage, 0x2ULL); // Set false Bitfield::set(Storage, false); EXPECT_EQ(Bitfield::get(Storage), false); EXPECT_EQ(Storage, 0x0ULL); } TEST(BitfieldsTest, LastBit) { uint8_t Storage = 0; using LastBit = Bitfield::Element; // Set true Bitfield::set(Storage, true); EXPECT_EQ(Bitfield::get(Storage), true); EXPECT_EQ(Storage, 0x80ULL); // Set false Bitfield::set(Storage, false); EXPECT_EQ(Bitfield::get(Storage), false); EXPECT_EQ(Storage, 0x0ULL); } TEST(BitfieldsTest, LastBitUint64) { uint64_t Storage = 0; using LastBit = Bitfield::Element; // Set true Bitfield::set(Storage, true); EXPECT_EQ(Bitfield::get(Storage), true); EXPECT_EQ(Storage, 0x8000000000000000ULL); // Set false Bitfield::set(Storage, false); EXPECT_EQ(Bitfield::get(Storage), false); EXPECT_EQ(Storage, 0x0ULL); } TEST(BitfieldsTest, Enum) { enum Enum : unsigned { Zero = 0, Two = 2, LAST = Two }; uint8_t Storage = 0; using OrderingField = Bitfield::Element; EXPECT_EQ(Bitfield::get(Storage), Zero); Bitfield::set(Storage, Two); EXPECT_EQ(Bitfield::get(Storage), Two); EXPECT_EQ(Storage, 0b00000100); // value 2 in ^^ } TEST(BitfieldsTest, EnumClass) { enum class Enum : unsigned { Zero = 0, Two = 2, LAST = Two }; uint8_t Storage = 0; using OrderingField = Bitfield::Element; EXPECT_EQ(Bitfield::get(Storage), Enum::Zero); Bitfield::set(Storage, Enum::Two); EXPECT_EQ(Bitfield::get(Storage), Enum::Two); EXPECT_EQ(Storage, 0b00000100); // value 2 in ^^ } TEST(BitfieldsTest, OneBitSigned) { uint8_t Storage = 0; using SignedField = Bitfield::Element; EXPECT_EQ(Bitfield::get(Storage), 0); EXPECT_EQ(Storage, 0b00000000); // value 0 in ^ Bitfield::set(Storage, -1); EXPECT_EQ(Bitfield::get(Storage), -1); EXPECT_EQ(Storage, 0b00000010); // value 1 in ^ } TEST(BitfieldsTest, TwoBitSigned) { uint8_t Storage = 0; using SignedField = Bitfield::Element; EXPECT_EQ(Bitfield::get(Storage), 0); EXPECT_EQ(Storage, 0b00000000); // value 0 in ^^ Bitfield::set(Storage, 1); EXPECT_EQ(Bitfield::get(Storage), 1); EXPECT_EQ(Storage, 0b00000010); // value 1 in ^^ Bitfield::set(Storage, -1); EXPECT_EQ(Bitfield::get(Storage), -1); EXPECT_EQ(Storage, 0b00000110); // value -1 in ^^ Bitfield::set(Storage, -2); EXPECT_EQ(Bitfield::get(Storage), -2); EXPECT_EQ(Storage, 0b00000100); // value -2 in ^^ } TEST(BitfieldsTest, isOverlapping) { // 01234567 // A: -------- // B: --- // C: --- // D: --- using A = Bitfield::Element; using B = Bitfield::Element; using C = Bitfield::Element; using D = Bitfield::Element; EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_TRUE((Bitfield::isOverlapping())); EXPECT_FALSE((Bitfield::isOverlapping())); } TEST(BitfieldsTest, areContiguous) { using A = Bitfield::Element; // Next Bit:1 using B = Bitfield::Element; // Next Bit:5 using C = Bitfield::Element; // Next Bit:8 EXPECT_TRUE((Bitfield::areContiguous())); EXPECT_TRUE((Bitfield::areContiguous())); EXPECT_FALSE((Bitfield::areContiguous())); EXPECT_FALSE((Bitfield::areContiguous())); EXPECT_FALSE((Bitfield::areContiguous())); } TEST(BitfieldsTest, FullUint64) { uint64_t Storage = 0; using Value = Bitfield::Element; Bitfield::set(Storage, -1ULL); EXPECT_EQ(Bitfield::get(Storage), -1ULL); Bitfield::set(Storage, 0ULL); EXPECT_EQ(Bitfield::get(Storage), 0ULL); } TEST(BitfieldsTest, FullInt64) { uint64_t Storage = 0; using Value = Bitfield::Element; Bitfield::set(Storage, -1); EXPECT_EQ(Bitfield::get(Storage), -1); Bitfield::set(Storage, 0); EXPECT_EQ(Bitfield::get(Storage), 0); } #ifdef EXPECT_DEBUG_DEATH TEST(BitfieldsTest, ValueTooBigBool) { uint64_t Storage = 0; using A = Bitfield::Element; Bitfield::set(Storage, true); Bitfield::set(Storage, false); EXPECT_DEBUG_DEATH(Bitfield::set(Storage, 2), "value is too big"); } TEST(BitfieldsTest, ValueTooBigInt) { uint64_t Storage = 0; using A = Bitfield::Element; Bitfield::set(Storage, 3); EXPECT_DEBUG_DEATH(Bitfield::set(Storage, 4), "value is too big"); EXPECT_DEBUG_DEATH(Bitfield::set(Storage, -1), "value is too big"); } TEST(BitfieldsTest, ValueTooBigBounded) { uint8_t Storage = 0; using A = Bitfield::Element; Bitfield::set(Storage, 1); Bitfield::set(Storage, 0); Bitfield::set(Storage, -1); Bitfield::set(Storage, -2); EXPECT_DEBUG_DEATH(Bitfield::set(Storage, 2), "value is too big"); EXPECT_DEBUG_DEATH(Bitfield::set(Storage, -3), "value is too small"); } #endif } // namespace