SPIRV-Tools/test/opt/instruction_list_test.cpp
Steven Perron bb7802b18c Change BasicBlock to use InstructionList to hold instructions.
This is the first step in replacing the std::vector of Instruction
pointers to using and intrusive linked list.

To this end, we created the InstructionList class.  It inherites from
the IntrusiveList class, but add the extra concept of ownership.  An
InstructionList owns the instruction that are in it.  This is to be
consistent with the current ownership rules where the vector owns the
instruction that are in it.

The other larger change is that the inst_ member of the BasicBlock class
was changed to using the InstructionList class.

Added test for the InsertBefore functions, and making sure that the
InstructionList destructor will delete the elements that it contains.

I've also add extra comments to explain ownership a little better.
2017-10-20 12:37:44 -04:00

113 lines
4.1 KiB
C++

// Copyright (c) 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <memory>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "opt/instruction.h"
#include "opt/instruction_list.h"
namespace {
using Instruction = spvtools::ir::Instruction;
using InstructionList = spvtools::ir::InstructionList;
using ::testing::ContainerEq;
using ::testing::ElementsAre;
using InstructionListTest = ::testing::Test;
// A class that overrides the destructor, so we can trace it.
class TestInstruction : public Instruction {
public:
TestInstruction() : Instruction() { created_instructions_.push_back(this); }
~TestInstruction() { deleted_instructions_.push_back(this); }
static std::vector<TestInstruction*> created_instructions_;
static std::vector<TestInstruction*> deleted_instructions_;
};
std::vector<TestInstruction*> TestInstruction::created_instructions_;
std::vector<TestInstruction*> TestInstruction::deleted_instructions_;
// Test that the destructor for InstructionList is calling the destructor
// for every element that is in the list.
TEST(InstructionListTest, Destructor) {
InstructionList* list = new InstructionList();
list->push_back(new Instruction());
list->push_back(new Instruction());
delete list;
// Sorting because we do not care if the order of create and destruction is
// the same. Using generic sort just incase things are changed above.
std::sort(TestInstruction::created_instructions_.begin(),
TestInstruction::created_instructions_.end());
std::sort(TestInstruction::deleted_instructions_.begin(),
TestInstruction::deleted_instructions_.end());
EXPECT_THAT(TestInstruction::created_instructions_,
ContainerEq(TestInstruction::deleted_instructions_));
}
// Test the |InsertBefore| with a single instruction in the iterator class.
// Need to make sure the elements are inserted in the correct order, and the
// return value points to the correct location.
//
// Comparing addresses to make sure they remain stable, so other data structures
// can have pointers to instructions in InstructionList.
TEST(InstructionListTest, InsertBefore1) {
InstructionList list;
std::vector<Instruction*> inserted_instructions;
for (int i = 0; i < 4; i++) {
std::unique_ptr<Instruction> inst(new Instruction());
inserted_instructions.push_back(inst.get());
auto new_element = list.end().InsertBefore(std::move(inst));
EXPECT_EQ(&*new_element, inserted_instructions.back());
}
std::vector<Instruction*> output;
for (auto& i : list) {
output.push_back(&i);
}
EXPECT_THAT(output, ContainerEq(inserted_instructions));
}
// Test inserting an entire vector of instructions using InsertBefore. Checking
// the order of insertion and the return value.
//
// Comparing addresses to make sure they remain stable, so other data structures
// can have pointers to instructions in InstructionList.
TEST(InstructionListTest, InsertBefore2) {
InstructionList list;
std::vector<std::unique_ptr<Instruction>> new_instructions;
std::vector<Instruction*> created_instructions;
for (int i = 0; i < 4; i++) {
std::unique_ptr<Instruction> inst(new Instruction());
created_instructions.push_back(inst.get());
new_instructions.push_back(std::move(inst));
}
auto new_element = list.begin().InsertBefore(std::move(new_instructions));
EXPECT_TRUE(new_instructions.empty());
EXPECT_EQ(&*new_element, created_instructions.front());
std::vector<Instruction*> output;
for (auto& i : list) {
output.push_back(&i);
}
EXPECT_THAT(output, ContainerEq(created_instructions));
}
} // namespace