257 lines
8.4 KiB
C++
257 lines
8.4 KiB
C++
|
//===- 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<bool, 0, 1>;
|
||
|
Bitfield::set<Bool>(Storage, true);
|
||
|
EXPECT_EQ(Storage, 0b00000001);
|
||
|
// ^
|
||
|
EXPECT_EQ(Bitfield::get<Bool>(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<SuitEnum, 1, 2, SuitEnum::SPADES>;
|
||
|
Bitfield::set<Suit>(Storage, SuitEnum::HEARTS);
|
||
|
EXPECT_EQ(Storage, 0b00000101);
|
||
|
// ^^
|
||
|
EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::HEARTS);
|
||
|
|
||
|
// Store and retrieve a 5 bit value as unsigned.
|
||
|
using Value = Bitfield::Element<unsigned, 3, 5>;
|
||
|
Bitfield::set<Value>(Storage, 10);
|
||
|
EXPECT_EQ(Storage, 0b01010101);
|
||
|
// ^^^^^
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), 10U);
|
||
|
|
||
|
// Interpret the same 5 bit value as signed.
|
||
|
using SignedValue = Bitfield::Element<int, 3, 5>;
|
||
|
Bitfield::set<SignedValue>(Storage, -2);
|
||
|
EXPECT_EQ(Storage, 0b11110101);
|
||
|
// ^^^^^
|
||
|
EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -2);
|
||
|
|
||
|
// Ability to efficiently test if a field is non zero.
|
||
|
EXPECT_TRUE(Bitfield::test<Value>(Storage));
|
||
|
|
||
|
// Alter Storage changes value.
|
||
|
Storage = 0;
|
||
|
EXPECT_EQ(Bitfield::get<Bool>(Storage), false);
|
||
|
EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::CLUBS);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), 0U);
|
||
|
EXPECT_EQ(Bitfield::get<SignedValue>(Storage), 0);
|
||
|
|
||
|
Storage = 255;
|
||
|
EXPECT_EQ(Bitfield::get<Bool>(Storage), true);
|
||
|
EXPECT_EQ(Bitfield::get<Suit>(Storage), SuitEnum::SPADES);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), 31U);
|
||
|
EXPECT_EQ(Bitfield::get<SignedValue>(Storage), -1);
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, FirstBit) {
|
||
|
uint8_t Storage = 0;
|
||
|
using FirstBit = Bitfield::Element<bool, 0, 1>;
|
||
|
// Set true
|
||
|
Bitfield::set<FirstBit>(Storage, true);
|
||
|
EXPECT_EQ(Bitfield::get<FirstBit>(Storage), true);
|
||
|
EXPECT_EQ(Storage, 0x1ULL);
|
||
|
// Set false
|
||
|
Bitfield::set<FirstBit>(Storage, false);
|
||
|
EXPECT_EQ(Bitfield::get<FirstBit>(Storage), false);
|
||
|
EXPECT_EQ(Storage, 0x0ULL);
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, SecondBit) {
|
||
|
uint8_t Storage = 0;
|
||
|
using SecondBit = Bitfield::Element<bool, 1, 1>;
|
||
|
// Set true
|
||
|
Bitfield::set<SecondBit>(Storage, true);
|
||
|
EXPECT_EQ(Bitfield::get<SecondBit>(Storage), true);
|
||
|
EXPECT_EQ(Storage, 0x2ULL);
|
||
|
// Set false
|
||
|
Bitfield::set<SecondBit>(Storage, false);
|
||
|
EXPECT_EQ(Bitfield::get<SecondBit>(Storage), false);
|
||
|
EXPECT_EQ(Storage, 0x0ULL);
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, LastBit) {
|
||
|
uint8_t Storage = 0;
|
||
|
using LastBit = Bitfield::Element<bool, 7, 1>;
|
||
|
// Set true
|
||
|
Bitfield::set<LastBit>(Storage, true);
|
||
|
EXPECT_EQ(Bitfield::get<LastBit>(Storage), true);
|
||
|
EXPECT_EQ(Storage, 0x80ULL);
|
||
|
// Set false
|
||
|
Bitfield::set<LastBit>(Storage, false);
|
||
|
EXPECT_EQ(Bitfield::get<LastBit>(Storage), false);
|
||
|
EXPECT_EQ(Storage, 0x0ULL);
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, LastBitUint64) {
|
||
|
uint64_t Storage = 0;
|
||
|
using LastBit = Bitfield::Element<bool, 63, 1>;
|
||
|
// Set true
|
||
|
Bitfield::set<LastBit>(Storage, true);
|
||
|
EXPECT_EQ(Bitfield::get<LastBit>(Storage), true);
|
||
|
EXPECT_EQ(Storage, 0x8000000000000000ULL);
|
||
|
// Set false
|
||
|
Bitfield::set<LastBit>(Storage, false);
|
||
|
EXPECT_EQ(Bitfield::get<LastBit>(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<Enum, 1, 2, LAST>;
|
||
|
EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Zero);
|
||
|
Bitfield::set<OrderingField>(Storage, Two);
|
||
|
EXPECT_EQ(Bitfield::get<OrderingField>(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<Enum, 1, 2, Enum::LAST>;
|
||
|
EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Enum::Zero);
|
||
|
Bitfield::set<OrderingField>(Storage, Enum::Two);
|
||
|
EXPECT_EQ(Bitfield::get<OrderingField>(Storage), Enum::Two);
|
||
|
EXPECT_EQ(Storage, 0b00000100);
|
||
|
// value 2 in ^^
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, OneBitSigned) {
|
||
|
uint8_t Storage = 0;
|
||
|
using SignedField = Bitfield::Element<int, 1, 1>;
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), 0);
|
||
|
EXPECT_EQ(Storage, 0b00000000);
|
||
|
// value 0 in ^
|
||
|
Bitfield::set<SignedField>(Storage, -1);
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), -1);
|
||
|
EXPECT_EQ(Storage, 0b00000010);
|
||
|
// value 1 in ^
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, TwoBitSigned) {
|
||
|
uint8_t Storage = 0;
|
||
|
using SignedField = Bitfield::Element<int, 1, 2>;
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), 0);
|
||
|
EXPECT_EQ(Storage, 0b00000000);
|
||
|
// value 0 in ^^
|
||
|
Bitfield::set<SignedField>(Storage, 1);
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), 1);
|
||
|
EXPECT_EQ(Storage, 0b00000010);
|
||
|
// value 1 in ^^
|
||
|
Bitfield::set<SignedField>(Storage, -1);
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), -1);
|
||
|
EXPECT_EQ(Storage, 0b00000110);
|
||
|
// value -1 in ^^
|
||
|
Bitfield::set<SignedField>(Storage, -2);
|
||
|
EXPECT_EQ(Bitfield::get<SignedField>(Storage), -2);
|
||
|
EXPECT_EQ(Storage, 0b00000100);
|
||
|
// value -2 in ^^
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, isOverlapping) {
|
||
|
// 01234567
|
||
|
// A: --------
|
||
|
// B: ---
|
||
|
// C: ---
|
||
|
// D: ---
|
||
|
using A = Bitfield::Element<unsigned, 0, 8>;
|
||
|
using B = Bitfield::Element<unsigned, 3, 3>;
|
||
|
using C = Bitfield::Element<unsigned, 1, 3>;
|
||
|
using D = Bitfield::Element<unsigned, 4, 3>;
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<A, B>()));
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<A, C>()));
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<A, B>()));
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<A, D>()));
|
||
|
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<B, C>()));
|
||
|
EXPECT_TRUE((Bitfield::isOverlapping<B, D>()));
|
||
|
EXPECT_FALSE((Bitfield::isOverlapping<C, D>()));
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, areContiguous) {
|
||
|
using A = Bitfield::Element<unsigned, 0, 1>; // Next Bit:1
|
||
|
using B = Bitfield::Element<unsigned, 1, 4>; // Next Bit:5
|
||
|
using C = Bitfield::Element<unsigned, 5, 3>; // Next Bit:8
|
||
|
EXPECT_TRUE((Bitfield::areContiguous<A, B>()));
|
||
|
EXPECT_TRUE((Bitfield::areContiguous<A, B, C>()));
|
||
|
|
||
|
EXPECT_FALSE((Bitfield::areContiguous<A, C>()));
|
||
|
EXPECT_FALSE((Bitfield::areContiguous<A, A>()));
|
||
|
EXPECT_FALSE((Bitfield::areContiguous<B, A>()));
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, FullUint64) {
|
||
|
uint64_t Storage = 0;
|
||
|
using Value = Bitfield::Element<uint64_t, 0, 64>;
|
||
|
Bitfield::set<Value>(Storage, -1ULL);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), -1ULL);
|
||
|
Bitfield::set<Value>(Storage, 0ULL);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), 0ULL);
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, FullInt64) {
|
||
|
uint64_t Storage = 0;
|
||
|
using Value = Bitfield::Element<int64_t, 0, 64>;
|
||
|
Bitfield::set<Value>(Storage, -1);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), -1);
|
||
|
Bitfield::set<Value>(Storage, 0);
|
||
|
EXPECT_EQ(Bitfield::get<Value>(Storage), 0);
|
||
|
}
|
||
|
|
||
|
#ifdef EXPECT_DEBUG_DEATH
|
||
|
|
||
|
TEST(BitfieldsTest, ValueTooBigBool) {
|
||
|
uint64_t Storage = 0;
|
||
|
using A = Bitfield::Element<unsigned, 0, 1>;
|
||
|
Bitfield::set<A>(Storage, true);
|
||
|
Bitfield::set<A>(Storage, false);
|
||
|
EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is too big");
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, ValueTooBigInt) {
|
||
|
uint64_t Storage = 0;
|
||
|
using A = Bitfield::Element<unsigned, 0, 2>;
|
||
|
Bitfield::set<A>(Storage, 3);
|
||
|
EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 4), "value is too big");
|
||
|
EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -1), "value is too big");
|
||
|
}
|
||
|
|
||
|
TEST(BitfieldsTest, ValueTooBigBounded) {
|
||
|
uint8_t Storage = 0;
|
||
|
using A = Bitfield::Element<int, 1, 2>;
|
||
|
Bitfield::set<A>(Storage, 1);
|
||
|
Bitfield::set<A>(Storage, 0);
|
||
|
Bitfield::set<A>(Storage, -1);
|
||
|
Bitfield::set<A>(Storage, -2);
|
||
|
EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is too big");
|
||
|
EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -3), "value is too small");
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
} // namespace
|