blob: bc4ad80fe9068ca80f7d25c4d1267783130e51a4 [file] [log] [blame]
// Copyright 2017-2020 The Verible Authors.
//
// 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 "common/util/interval_map.h"
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "absl/strings/string_view.h"
#include "common/util/range.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace verible {
namespace {
typedef DisjointIntervalMap<int, std::unique_ptr<int>> IntIntervalMap;
typedef DisjointIntervalMap<int, std::unique_ptr<std::string>>
StringIntervalMap;
TEST(DisjointIntervalMapTest, DefaultCtor) {
const IntIntervalMap imap;
EXPECT_TRUE(imap.empty());
}
TEST(DisjointIntervalMapTest, FindEmpty) {
const IntIntervalMap imap;
EXPECT_EQ(imap.find(3), imap.end());
}
TEST(DisjointIntervalMapTest, EmplaceOne) {
IntIntervalMap imap;
const auto p = imap.emplace({3, 4}, std::make_unique<int>(5));
EXPECT_TRUE(p.second);
EXPECT_EQ(p.first->first, std::make_pair(3, 4));
EXPECT_EQ(*p.first->second, 5);
EXPECT_FALSE(imap.empty());
}
TEST(DisjointIntervalMapTest, EmplaceOneEnsureMove) {
StringIntervalMap imap;
auto s = std::make_unique<std::string>("Gruetzi!");
const absl::string_view sv(*s);
const auto p = imap.emplace({3, 7}, std::move(s));
EXPECT_TRUE(p.second);
EXPECT_EQ(p.first->first, std::make_pair(3, 7));
// ownership transferred, string_view range is still valid
const absl::string_view new_sv(*p.first->second);
EXPECT_TRUE(BoundsEqual(new_sv, sv)) << "got: " << new_sv << " vs. " << sv;
}
TEST(DisjointIntervalMapTest, EmplaceNonoverlappingAbutting) {
IntIntervalMap imap;
{
const auto p = imap.emplace({3, 4}, std::make_unique<int>(5));
EXPECT_TRUE(p.second);
}
{
// insert new leftmost range
const auto p = imap.emplace({1, 3}, std::make_unique<int>(9));
EXPECT_TRUE(p.second);
}
{
// insert new rightmost range
const auto p = imap.emplace({4, 7}, std::make_unique<int>(2));
EXPECT_TRUE(p.second);
}
EXPECT_EQ(imap.find(0), imap.end());
for (int i = 1; i < 3; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 9);
}
for (int i = 3; i < 4; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 5);
}
for (int i = 4; i < 7; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 2);
}
EXPECT_EQ(imap.find(7), imap.end());
}
TEST(DisjointIntervalMapTest, EmplaceNonoverlappingWithGaps) {
IntIntervalMap imap;
{
const auto p = imap.emplace({20, 25}, std::make_unique<int>(4));
EXPECT_TRUE(p.second);
}
{
// insert new rightmost range
const auto p = imap.emplace({30, 40}, std::make_unique<int>(2));
EXPECT_TRUE(p.second);
}
{
// insert new leftmost range
const auto p = imap.emplace({10, 15}, std::make_unique<int>(8));
EXPECT_TRUE(p.second);
}
for (int i = 0; i < 10; ++i) {
EXPECT_EQ(imap.find(i), imap.end());
}
for (int i = 10; i < 15; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 8);
}
for (int i = 15; i < 20; ++i) {
EXPECT_EQ(imap.find(i), imap.end());
}
for (int i = 20; i < 25; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 4);
}
for (int i = 25; i < 30; ++i) {
EXPECT_EQ(imap.find(i), imap.end());
}
for (int i = 30; i < 40; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 2);
}
EXPECT_EQ(imap.find(40), imap.end());
{
// fill a gap completely
const auto p = imap.emplace({15, 20}, std::make_unique<int>(77));
EXPECT_TRUE(p.second);
EXPECT_EQ(*imap.find(14)->second, 8);
for (int i = 15; i < 20; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 77);
}
EXPECT_EQ(*imap.find(20)->second, 4);
}
{
// fill a gap partially
const auto p = imap.emplace({27, 29}, std::make_unique<int>(44));
EXPECT_TRUE(p.second);
for (int i = 25; i < 27; ++i) {
EXPECT_EQ(imap.find(i), imap.end());
}
for (int i = 27; i < 29; ++i) {
const auto f = imap.find(i);
ASSERT_NE(f, imap.end());
EXPECT_EQ(*f->second, 44);
}
for (int i = 29; i < 30; ++i) {
EXPECT_EQ(imap.find(i), imap.end());
}
}
}
TEST(DisjointIntervalMapTest, EmplaceBackwardsRange) {
IntIntervalMap imap;
EXPECT_DEATH(imap.emplace({4, 3}, std::make_unique<int>(5)), "");
}
TEST(DisjointIntervalMapTest, MustEmplaceSuccess) {
IntIntervalMap imap;
constexpr std::tuple<int, int, int> kTestValues[] = {
{3, 4, 5}, {1, 3, 9}, {4, 7, 2}, {-10, -5, 0}, {10, 15, 33},
};
for (const auto& t : kTestValues) {
const auto iter = imap.must_emplace({std::get<0>(t), std::get<1>(t)},
std::make_unique<int>(std::get<2>(t)));
// Ensure that inserted value is the expected key and value.
EXPECT_EQ(iter->first.first, std::get<0>(t));
EXPECT_EQ(iter->first.second, std::get<1>(t));
EXPECT_EQ(*iter->second, std::get<2>(t));
}
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapLeft) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({20, 31}, std::make_unique<int>(9)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapRight) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({39, 45}, std::make_unique<int>(22)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapInterior) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({31, 39}, std::make_unique<int>(12)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapEnveloped) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({29, 40}, std::make_unique<int>(29)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceSpanningTwo) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
imap.must_emplace({50, 60}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({35, 55}, std::make_unique<int>(99)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapsLower) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
imap.must_emplace({50, 60}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({35, 45}, std::make_unique<int>(55)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, MustEmplaceOverlapsUpper) {
IntIntervalMap imap;
imap.must_emplace({30, 40}, std::make_unique<int>(5));
imap.must_emplace({50, 60}, std::make_unique<int>(5));
EXPECT_DEATH(imap.must_emplace({45, 55}, std::make_unique<int>(66)),
"Failed to emplace");
}
TEST(DisjointIntervalMapTest, FindInterval) {
IntIntervalMap imap;
imap.must_emplace({20, 25}, std::make_unique<int>(1));
for (int i = 19; i < 26; ++i) {
for (int j = i + 1; j < 26; ++j) {
const auto found = imap.find({i, j});
if (i >= 20 && j <= 25) {
ASSERT_NE(found, imap.end());
EXPECT_EQ(found->first.first, 20);
EXPECT_EQ(found->first.second, 25);
EXPECT_EQ(*found->second, 1);
} else {
EXPECT_EQ(found, imap.end());
}
}
}
}
TEST(DisjointIntervalMapTest, BeginEndRangeConstIterators) {
IntIntervalMap imap;
// values chosen to be == interval size
imap.must_emplace({50, 60}, std::make_unique<int>(10));
imap.must_emplace({30, 35}, std::make_unique<int>(5));
imap.must_emplace({39, 46}, std::make_unique<int>(7));
for (const auto& pair : imap) {
EXPECT_EQ(pair.first.second - pair.first.first, *pair.second);
}
}
// std::vector is moveable and guaranteed to transfer ownership over its
// internal array, i.e. no small/inline-vector optimization.
typedef DisjointIntervalMap<std::vector<int>::const_iterator, std::vector<int>>
VectorIntervalMap;
static VectorIntervalMap::iterator AllocateVectorBlock(VectorIntervalMap* vmap,
int min, int max) {
std::vector<int> v(max - min);
int i = min;
for (auto& e : v) {
e = i;
++i;
}
// Caution: do not reference v and move(v) in the same set of call parameters
// [sequence-point].
const auto key(std::make_pair(v.cbegin(), v.cend()));
const auto new_iter = vmap->must_emplace(key, std::move(v));
EXPECT_EQ(new_iter->first, key);
return new_iter;
}
static void VerifyVectorBlock(const VectorIntervalMap& vmap,
VectorIntervalMap::const_iterator block) {
for (auto left = block->first.first; left != std::prev(block->first.second);
++left) {
// Verify scalar find.
EXPECT_TRUE(vmap.find(left) == block);
// Verify range find.
for (auto right = std::next(left); right != block->first.second; ++right) {
EXPECT_TRUE(vmap.find({left, right}) == block);
}
}
}
TEST(DisjointIntervalMapTest, VectorDemo) {
VectorIntervalMap vmap;
const auto block1 = AllocateVectorBlock(&vmap, 10, 20);
VerifyVectorBlock(vmap, block1);
const auto block2 = AllocateVectorBlock(&vmap, 30, 40);
VerifyVectorBlock(vmap, block1);
VerifyVectorBlock(vmap, block2);
const auto block3 = AllocateVectorBlock(&vmap, 20, 30);
VerifyVectorBlock(vmap, block1);
VerifyVectorBlock(vmap, block2);
VerifyVectorBlock(vmap, block3);
}
} // namespace
} // namespace verible