//===--- DiverseStackTest.cpp ---------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/Basic/DiverseStack.h" #include "gtest/gtest.h" #include using namespace swift; namespace { enum class ValueKind { TwoByte = 0, ThreeByte = 1, }; struct ParentType { uint8_t allocatedSize; ValueKind kind; public: ParentType(uint8_t allocatedSize, ValueKind kind) : allocatedSize(allocatedSize), kind(kind) {} unsigned allocated_size() const { return allocatedSize; } ValueKind getKind() const { return kind; } }; struct TwoByteType : ParentType { uint8_t Value; TwoByteType(uint8_t Value) : ParentType(sizeof(*this), ValueKind::TwoByte), Value(Value) {} }; struct ThreeByteType : ParentType { uint16_t Value; ThreeByteType(uint16_t Value) : ParentType(sizeof(*this), ValueKind::ThreeByte), Value(Value) {} }; struct RandomValueGenerator { std::mt19937 gen; std::uniform_int_distribution randomEightBitValueGenerator{ 0, std::numeric_limits::max()}; std::uniform_int_distribution randomSixteenBitValueGenerator; // Randomly generated bits. This is frozen to ensure that the test doesn't // change in between runs. static constexpr unsigned seed() { return 0xb2f2c1c8; } RandomValueGenerator() : gen(seed()), randomEightBitValueGenerator(), randomSixteenBitValueGenerator() {} ~RandomValueGenerator() = default; RandomValueGenerator(const RandomValueGenerator &) = delete; RandomValueGenerator(RandomValueGenerator &&) = delete; RandomValueGenerator &operator=(const RandomValueGenerator &) = delete; RandomValueGenerator &operator=(RandomValueGenerator &&) = delete; void push(DiverseStackImpl &Stack, std::vector &TwoByteVector, std::vector &ThreeByteVector, std::vector &ControlVector) { uint8_t value = randomEightBitValueGenerator(gen) % 2; if (value) { auto Next = TwoByteType(randomEightBitValueGenerator(gen)); Stack.push(Next); ControlVector.emplace_back(ValueKind::TwoByte); TwoByteVector.push_back(Next); return; } auto Next = ThreeByteType(randomSixteenBitValueGenerator(gen)); Stack.push(Next); ControlVector.emplace_back(ValueKind::ThreeByte); ThreeByteVector.push_back(Next); } void push(DiverseStackImpl &Stack) { uint8_t value = randomEightBitValueGenerator(gen) % 2; if (value) { auto Next = TwoByteType(randomEightBitValueGenerator(gen)); Stack.push(Next); return; } auto Next = ThreeByteType(randomSixteenBitValueGenerator(gen)); Stack.push(Next); } }; } // end anonymous namespace TEST(DiverseStack, MonomorphicPushPop) { DiverseStack Stack; EXPECT_TRUE(Stack.empty()); constexpr size_t TwoByteDataSize = 5; uint8_t InputData[TwoByteDataSize] = {5, 9, 1, 2, 10}; for (unsigned i = 0; i < TwoByteDataSize; ++i) { Stack.push(TwoByteType(InputData[i])); } EXPECT_FALSE(Stack.empty()); for (int i = TwoByteDataSize - 1; i >= 0; --i) { TwoByteType T = reinterpret_cast(Stack.top()); Stack.pop(); EXPECT_EQ(T.Value, InputData[i]); } EXPECT_TRUE(Stack.empty()); } // We test the property here that iterating forward through the stack iterates // in stack order. This is a bit counter-intuitive for people used to vector // stacks. TEST(DiverseStack, Iterate) { DiverseStack Stack; constexpr size_t TwoByteDataSize = 5; uint8_t InputData[TwoByteDataSize] = {5, 9, 1, 2, 10}; for (unsigned i = 0; i < TwoByteDataSize; ++i) { Stack.push(TwoByteType(InputData[i])); } const uint8_t *Ptr = &InputData[TwoByteDataSize - 1]; for (auto II = Stack.begin(), IE = Stack.end(); II != IE;) { TwoByteType T = reinterpret_cast(*II); EXPECT_EQ(T.Value, *Ptr); --Ptr; ++II; } } TEST(DiverseStack, PolymorphicPushPop) { RandomValueGenerator RandomGen; DiverseStack Stack; std::vector TwoByteVector; std::vector ThreeByteVector; std::vector ControlVector; EXPECT_TRUE(Stack.empty()); unsigned NumValues = 1024; for (unsigned i = 0; i < NumValues; ++i) { RandomGen.push(Stack, TwoByteVector, ThreeByteVector, ControlVector); } EXPECT_EQ(ControlVector.size(), NumValues); EXPECT_GE(ControlVector.size(), TwoByteVector.size()); EXPECT_GE(ControlVector.size(), ThreeByteVector.size()); while (!ControlVector.empty()) { EXPECT_FALSE(Stack.empty()); ValueKind VectorSwitch = ControlVector.back(); ControlVector.pop_back(); if (VectorSwitch == ValueKind::TwoByte) { TwoByteType Expected = TwoByteVector.back(); TwoByteVector.pop_back(); TwoByteType Actual = static_cast(Stack.top()); Stack.pop(); EXPECT_EQ(Expected.Value, Actual.Value); continue; } assert(VectorSwitch == ValueKind::ThreeByte); ThreeByteType Expected = ThreeByteVector.back(); ThreeByteVector.pop_back(); ThreeByteType Actual = static_cast(Stack.top()); EXPECT_EQ(Expected.Value, Actual.Value); Stack.pop(); } EXPECT_TRUE(ControlVector.empty()); EXPECT_TRUE(TwoByteVector.empty()); EXPECT_TRUE(ThreeByteVector.empty()); EXPECT_TRUE(Stack.empty()); } TEST(DiverseStack, StableIndexLookup) { RandomValueGenerator RandomGen; DiverseStack Stack; unsigned FirstStop = 3; unsigned NumValues = 1024; for (unsigned i = 0; i < FirstStop; ++i) { RandomGen.push(Stack); } decltype(Stack)::stable_iterator Iter = Stack.stable_begin(); ParentType &Parent = *Stack.find(Iter); ValueKind SavedKind = Parent.getKind(); unsigned SavedValue; if (SavedKind == ValueKind::TwoByte) { SavedValue = static_cast(Parent).Value; } else { SavedValue = static_cast(Parent).Value; } for (unsigned i = FirstStop; i < NumValues; ++i) { RandomGen.push(Stack); } Stack.pop(); Stack.pop(); Stack.pop(); Parent = *Stack.find(Iter); EXPECT_EQ(SavedKind, Parent.getKind()); if (SavedKind == ValueKind::TwoByte) { EXPECT_EQ(SavedValue, static_cast(Parent).Value); } else { EXPECT_EQ(SavedValue, static_cast(Parent).Value); } } TEST(DiverseStack, PopMany) { RandomValueGenerator RandomGen; DiverseStack Stack; unsigned FirstStop = 3; unsigned NumValues = 1024; for (unsigned i = 0; i < FirstStop; ++i) { RandomGen.push(Stack); } decltype(Stack)::stable_iterator Iter = Stack.stable_begin(); ParentType &Parent = *Stack.find(Iter); ValueKind SavedKind = Parent.getKind(); unsigned SavedValue; if (SavedKind == ValueKind::TwoByte) { SavedValue = static_cast(Parent).Value; } else { SavedValue = static_cast(Parent).Value; } for (unsigned i = FirstStop; i < NumValues; ++i) { RandomGen.push(Stack); } // Pop until Iter is the top of the stack. Stack.pop(Iter); Parent = *Stack.find(Iter); EXPECT_EQ(SavedKind, Parent.getKind()); if (SavedKind == ValueKind::TwoByte) { EXPECT_EQ(SavedValue, static_cast(Parent).Value); } else { EXPECT_EQ(SavedValue, static_cast(Parent).Value); } EXPECT_EQ(Iter, Stack.stable_begin()); }