blob: 3062d5d7f293c3e9a6b076e6258daf7777ddd204 [file] [log] [blame]
//===- 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