| /* | |
| * Copyright 2014 Google, Inc. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| * Authors: Gabe Black | |
| */ | |
| #include <gtest/gtest.h> | |
| #include <cassert> | |
| #include <iostream> | |
| #include <type_traits> | |
| #include "base/bitunion.hh" | |
| #include "base/cprintf.hh" | |
| using namespace std; | |
| namespace { | |
| BitUnion64(SixtyFour) | |
| Bitfield<39, 32> byte5; | |
| Bitfield<2> bit2; | |
| BitfieldRO<39, 32> byte5RO; | |
| BitfieldWO<39, 32> byte5WO; | |
| SubBitUnion(byte6, 47, 40) | |
| Bitfield<43, 42> bits43To42; | |
| Bitfield<41> bit41; | |
| SignedBitfield<41> bit41Signed; | |
| EndSubBitUnion(byte6) | |
| SignedBitfield<47, 40> byte6Signed; | |
| SignedBitfieldRO<47, 40> byte6SignedRO; | |
| SignedBitfieldWO<47, 40> byte6SignedWO; | |
| EndBitUnion(SixtyFour) | |
| BitUnion64(EmptySixtyFour) | |
| EndBitUnion(EmptySixtyFour) | |
| BitUnion32(EmptyThirtyTwo) | |
| EndBitUnion(EmptyThirtyTwo) | |
| BitUnion16(EmptySixteen) | |
| EndBitUnion(EmptySixteen) | |
| BitUnion8(EmptyEight) | |
| EndBitUnion(EmptyEight) | |
| class SplitField | |
| { | |
| protected: | |
| BitUnion64(In) | |
| Bitfield<15, 12> high; | |
| Bitfield<7, 4> low; | |
| EndBitUnion(In) | |
| BitUnion64(Out) | |
| Bitfield<7, 4> high; | |
| Bitfield<3, 0> low; | |
| EndBitUnion(Out) | |
| public: | |
| uint64_t | |
| getter(const uint64_t &storage) const | |
| { | |
| Out out = 0; | |
| In in = storage; | |
| out.high = in.high; | |
| out.low = in.low; | |
| return out; | |
| } | |
| void | |
| setter(uint64_t &storage, uint64_t val) | |
| { | |
| Out out = val; | |
| In in = 0; | |
| in.high = out.high; | |
| in.low = out.low; | |
| storage = in; | |
| } | |
| }; | |
| BitUnion64(Split) | |
| BitfieldType<SplitField> split; | |
| EndBitUnion(Split) | |
| struct ContainingStruct | |
| { | |
| BitUnion64(Contained) | |
| Bitfield<63, 60> topNibble; | |
| EndBitUnion(Contained) | |
| Contained contained; | |
| }; | |
| uint64_t | |
| containingFunc(uint64_t init_val, uint64_t fieldVal) | |
| { | |
| BitUnion32(Contained) | |
| Bitfield<16, 15> field; | |
| EndBitUnion(Contained) | |
| Contained contained = init_val; | |
| contained.field = fieldVal; | |
| return contained; | |
| } | |
| } // anonymous namespace | |
| // Declare these as global so g++ doesn't ignore them. Initialize them in | |
| // various ways. | |
| EmptySixtyFour emptySixtyFour = 0; | |
| EmptyThirtyTwo emptyThirtyTwo; | |
| EmptySixteen emptySixteen; | |
| EmptyEight emptyEight(0); | |
| class BitUnionData : public testing::Test { | |
| protected: | |
| SixtyFour sixtyFour; | |
| Split split; | |
| void SetUp() override { sixtyFour = 0; split = 0; } | |
| template <typename T> | |
| uint64_t templatedFunction(T) { return 0; } | |
| template <typename T> | |
| uint64_t | |
| templatedFunction(BitUnionType<T> u) | |
| { | |
| BitUnionBaseType<T> b = u; | |
| return b; | |
| } | |
| }; | |
| TEST_F(BitUnionData, NormalBitfield) | |
| { | |
| EXPECT_EQ(sixtyFour.byte5, 0); | |
| sixtyFour.byte5 = 0xff; | |
| EXPECT_EQ(sixtyFour, 0xff00000000); | |
| sixtyFour.byte5 = 0xfff; | |
| EXPECT_EQ(sixtyFour, 0xff00000000); | |
| EXPECT_EQ(sixtyFour.byte5, 0xff); | |
| } | |
| TEST_F(BitUnionData, SingleBitfield) | |
| { | |
| EXPECT_EQ(sixtyFour.bit2, 0); | |
| sixtyFour.bit2 = 0x1; | |
| EXPECT_EQ(sixtyFour, 0x4); | |
| EXPECT_EQ(sixtyFour.bit2, 0x1); | |
| } | |
| TEST_F(BitUnionData, ReadOnlyBitfield) | |
| { | |
| EXPECT_EQ(sixtyFour.byte5RO, 0); | |
| sixtyFour.byte5 = 0xff; | |
| EXPECT_EQ(sixtyFour.byte5RO, 0xff); | |
| } | |
| TEST_F(BitUnionData, WriteOnlyBitfield) | |
| { | |
| sixtyFour.byte5WO = 0xff; | |
| EXPECT_EQ(sixtyFour, 0xff00000000); | |
| } | |
| TEST_F(BitUnionData, SubBitUnions) | |
| { | |
| EXPECT_EQ(sixtyFour.byte6.bit41, 0); | |
| sixtyFour.byte6 = 0x2; | |
| EXPECT_EQ(sixtyFour.byte6.bit41, 1); | |
| sixtyFour.byte6.bits43To42 = 0x3; | |
| EXPECT_EQ(sixtyFour.byte6, 0xe); | |
| sixtyFour.byte6 = 0xff; | |
| sixtyFour.byte6.bit41 = 0; | |
| EXPECT_EQ(sixtyFour, 0xfd0000000000); | |
| } | |
| TEST_F(BitUnionData, SignedBitfields) | |
| { | |
| sixtyFour.byte6 = 0xff; | |
| EXPECT_EQ(sixtyFour.byte6Signed, -1); | |
| EXPECT_EQ(sixtyFour.byte6SignedRO, -1); | |
| sixtyFour.byte6SignedWO = 0; | |
| EXPECT_EQ(sixtyFour.byte6Signed, 0); | |
| EXPECT_EQ(sixtyFour.byte6SignedRO, 0); | |
| EXPECT_EQ(sixtyFour.byte6, 0); | |
| } | |
| TEST_F(BitUnionData, InsideStruct) | |
| { | |
| ContainingStruct containing; | |
| containing.contained = 0; | |
| containing.contained.topNibble = 0xd; | |
| EXPECT_EQ(containing.contained, 0xd000000000000000); | |
| } | |
| TEST_F(BitUnionData, InsideFunction) | |
| { | |
| EXPECT_EQ(containingFunc(0xfffff, 0), 0xe7fff); | |
| } | |
| TEST_F(BitUnionData, BitfieldToBitfieldAssignment) | |
| { | |
| SixtyFour otherSixtyFour = 0; | |
| sixtyFour.bit2 = 1; | |
| otherSixtyFour.byte6.bit41 = sixtyFour.bit2; | |
| EXPECT_EQ(otherSixtyFour, 0x20000000000); | |
| otherSixtyFour.bit2 = sixtyFour.bit2; | |
| EXPECT_EQ(otherSixtyFour, 0x20000000004); | |
| } | |
| TEST_F(BitUnionData, Operators) | |
| { | |
| SixtyFour otherSixtyFour = 0x4; | |
| sixtyFour = otherSixtyFour; | |
| EXPECT_EQ(sixtyFour, 0x4); | |
| sixtyFour = 0; | |
| EXPECT_TRUE(sixtyFour < otherSixtyFour); | |
| EXPECT_TRUE(otherSixtyFour > sixtyFour); | |
| EXPECT_TRUE(sixtyFour != otherSixtyFour); | |
| sixtyFour = otherSixtyFour; | |
| EXPECT_TRUE(sixtyFour == otherSixtyFour); | |
| } | |
| TEST_F(BitUnionData, Custom) | |
| { | |
| EXPECT_EQ(split, 0); | |
| split.split = 0xfff; | |
| EXPECT_EQ(split, 0xf0f0); | |
| EXPECT_EQ((uint64_t)split.split, 0xff); | |
| } | |
| TEST_F(BitUnionData, Templating) | |
| { | |
| sixtyFour = 0xff; | |
| EXPECT_EQ(templatedFunction(sixtyFour), 0xff); | |
| EXPECT_EQ(templatedFunction((uint64_t)sixtyFour), 0); | |
| BitUnion(uint64_t, Dummy64) | |
| EndBitUnion(Dummy64); | |
| BitUnion(uint32_t, Dummy32) | |
| EndBitUnion(Dummy32); | |
| bool is64; | |
| is64 = std::is_same<BitUnionBaseType<Dummy64>, uint64_t>::value; | |
| EXPECT_TRUE(is64); | |
| is64 = std::is_same<BitUnionBaseType<Dummy32>, uint64_t>::value; | |
| EXPECT_FALSE(is64); | |
| } | |
| TEST_F(BitUnionData, Output) | |
| { | |
| sixtyFour = 1234567812345678; | |
| std::stringstream ss; | |
| ss << sixtyFour; | |
| EXPECT_EQ(ss.str(), "1234567812345678"); | |
| ss.str(""); | |
| EmptyEight eight = 65; | |
| ss << eight; | |
| EXPECT_EQ(ss.str(), "65"); | |
| ss.str(""); | |
| } |