blob: 6987aa9ec370d837d9000313f52ab36b5e08f5c5 [file] [log] [blame]
//===--- 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 <random>
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<int> randomEightBitValueGenerator{
0, std::numeric_limits<uint8_t>::max()};
std::uniform_int_distribution<uint16_t> 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<ParentType> &Stack,
std::vector<TwoByteType> &TwoByteVector,
std::vector<ThreeByteType> &ThreeByteVector,
std::vector<ValueKind> &ControlVector) {
uint8_t value = randomEightBitValueGenerator(gen) % 2;
if (value) {
auto Next = TwoByteType(randomEightBitValueGenerator(gen));
Stack.push<TwoByteType>(Next);
ControlVector.emplace_back(ValueKind::TwoByte);
TwoByteVector.push_back(Next);
return;
}
auto Next = ThreeByteType(randomSixteenBitValueGenerator(gen));
Stack.push<ThreeByteType>(Next);
ControlVector.emplace_back(ValueKind::ThreeByte);
ThreeByteVector.push_back(Next);
}
void push(DiverseStackImpl<ParentType> &Stack) {
uint8_t value = randomEightBitValueGenerator(gen) % 2;
if (value) {
auto Next = TwoByteType(randomEightBitValueGenerator(gen));
Stack.push<TwoByteType>(Next);
return;
}
auto Next = ThreeByteType(randomSixteenBitValueGenerator(gen));
Stack.push<ThreeByteType>(Next);
}
};
} // end anonymous namespace
TEST(DiverseStack, MonomorphicPushPop) {
DiverseStack<ParentType, 128> 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>(TwoByteType(InputData[i]));
}
EXPECT_FALSE(Stack.empty());
for (int i = TwoByteDataSize - 1; i >= 0; --i) {
TwoByteType T = reinterpret_cast<TwoByteType &>(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<ParentType, 128> 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>(TwoByteType(InputData[i]));
}
const uint8_t *Ptr = &InputData[TwoByteDataSize - 1];
for (auto II = Stack.begin(), IE = Stack.end(); II != IE;) {
TwoByteType T = reinterpret_cast<TwoByteType &>(*II);
EXPECT_EQ(T.Value, *Ptr);
--Ptr;
++II;
}
}
TEST(DiverseStack, PolymorphicPushPop) {
RandomValueGenerator RandomGen;
DiverseStack<ParentType, 128> Stack;
std::vector<TwoByteType> TwoByteVector;
std::vector<ThreeByteType> ThreeByteVector;
std::vector<ValueKind> 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<TwoByteType &>(Stack.top());
Stack.pop<TwoByteType>();
EXPECT_EQ(Expected.Value, Actual.Value);
continue;
}
assert(VectorSwitch == ValueKind::ThreeByte);
ThreeByteType Expected = ThreeByteVector.back();
ThreeByteVector.pop_back();
ThreeByteType Actual = static_cast<ThreeByteType &>(Stack.top());
EXPECT_EQ(Expected.Value, Actual.Value);
Stack.pop<ThreeByteType>();
}
EXPECT_TRUE(ControlVector.empty());
EXPECT_TRUE(TwoByteVector.empty());
EXPECT_TRUE(ThreeByteVector.empty());
EXPECT_TRUE(Stack.empty());
}
TEST(DiverseStack, StableIndexLookup) {
RandomValueGenerator RandomGen;
DiverseStack<ParentType, sizeof(unsigned) * 4 * 8> 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<TwoByteType &>(Parent).Value;
} else {
SavedValue = static_cast<ThreeByteType &>(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<TwoByteType &>(Parent).Value);
} else {
EXPECT_EQ(SavedValue, static_cast<ThreeByteType &>(Parent).Value);
}
}
TEST(DiverseStack, PopMany) {
RandomValueGenerator RandomGen;
DiverseStack<ParentType, sizeof(unsigned) * 4 * 8> 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<TwoByteType &>(Parent).Value;
} else {
SavedValue = static_cast<ThreeByteType &>(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<TwoByteType &>(Parent).Value);
} else {
EXPECT_EQ(SavedValue, static_cast<ThreeByteType &>(Parent).Value);
}
EXPECT_EQ(Iter, Stack.stable_begin());
}