X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2Fsorted_vector_test.cpp;h=257b5dff56cc349a2a7df0408665229635cf40a9;hb=a60bf0bb374f4b57c0f00cd862e2861e1f381ed0;hp=ca806aa0a01f05584de80809358b2dfb3fcc02b6;hpb=7ce33845b2248016806757217e513cce1ee270b6;p=folly.git diff --git a/folly/test/sorted_vector_test.cpp b/folly/test/sorted_vector_test.cpp index ca806aa0..257b5dff 100644 --- a/folly/test/sorted_vector_test.cpp +++ b/folly/test/sorted_vector_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,16 +15,21 @@ */ #include -#include + +#include #include +#include + +#include +#include using folly::sorted_vector_set; using folly::sorted_vector_map; namespace { -template -struct less_invert : std::binary_function { +template +struct less_invert { bool operator()(const T& a, const T& b) const { return b < a; } @@ -139,6 +144,21 @@ TEST(SortedVectorTypes, SimpleSetTest) { EXPECT_TRUE(cpy2 == cpy); } +TEST(SortedVectorTypes, BadHints) { + for (int toInsert = -1; toInsert <= 7; ++toInsert) { + for (int hintPos = 0; hintPos <= 4; ++hintPos) { + sorted_vector_set s; + for (int i = 0; i <= 3; ++i) { + s.insert(i * 2); + } + s.insert(s.begin() + hintPos, toInsert); + size_t expectedSize = (toInsert % 2) == 0 ? 4 : 5; + EXPECT_EQ(s.size(), expectedSize); + check_invariant(s); + } + } +} + TEST(SortedVectorTypes, SimpleMapTest) { sorted_vector_map m; for (int i = 0; i < 1000; ++i) { @@ -149,10 +169,12 @@ TEST(SortedVectorTypes, SimpleMapTest) { m[32] = 100.0; check_invariant(m); EXPECT_TRUE(m.count(32) == 1); + EXPECT_DOUBLE_EQ(100.0, m.at(32)); EXPECT_FALSE(m.find(32) == m.end()); m.erase(32); EXPECT_TRUE(m.find(32) == m.end()); check_invariant(m); + EXPECT_THROW(m.at(32), std::out_of_range); sorted_vector_map m2 = m; EXPECT_TRUE(m2 == m); @@ -207,7 +229,7 @@ TEST(SortedVectorTypes, Sizes) { typedef sorted_vector_set, std::allocator,OneAtATimePolicy> SetT; typedef sorted_vector_map, - std::allocator,OneAtATimePolicy> MapT; + std::allocator>,OneAtATimePolicy> MapT; EXPECT_EQ(sizeof(SetT), sizeof(std::vector)); EXPECT_EQ(sizeof(MapT), sizeof(std::vector >)); @@ -278,7 +300,7 @@ TEST(SortedVectorTypes, GrowthPolicy) { std::list v; for (int i = 0; i < 20; ++i) { - v.push_back(CountCopyCtor(20 + i)); + v.emplace_back(20 + i); } a.insert(v.begin(), v.end()); check_invariant(a); @@ -300,6 +322,7 @@ TEST(SortedVectorTest, EmptyTest) { sorted_vector_map emptyMap; EXPECT_TRUE(emptyMap.lower_bound(10) == emptyMap.end()); EXPECT_TRUE(emptyMap.find(10) == emptyMap.end()); + EXPECT_THROW(emptyMap.at(10), std::out_of_range); } TEST(SortedVectorTest, MoveTest) { @@ -333,3 +356,219 @@ TEST(SortedVectorTest, ShrinkTest) { // vector::shrink_to_fit respects the caller. EXPECT_EQ(s.capacity(), s.size()); } + +TEST(SortedVectorTypes, EraseTest) { + sorted_vector_set s1; + s1.insert(1); + sorted_vector_set s2(s1); + EXPECT_EQ(0, s1.erase(0)); + EXPECT_EQ(s2, s1); +} + +std::vector extractValues(sorted_vector_set const& in) { + std::vector ret; + std::transform( + in.begin(), + in.end(), + std::back_inserter(ret), + [](const CountCopyCtor& c) { return c.val_; }); + return ret; +} + +template +std::vector makeVectorOfWrappers(std::vector ss) { + std::vector ts; + ts.reserve(ss.size()); + for (auto const& s : ss) { + ts.emplace_back(s); + } + return ts; +} + +TEST(SortedVectorTypes, TestSetBulkInsertionSortMerge) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add an unsorted range that will have to be merged in. + s = makeVectorOfWrappers({10, 7, 5, 1}); + + vset.insert(s.begin(), s.end()); + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 1); + + EXPECT_THAT( + extractValues(vset), + testing::ElementsAreArray({1, 2, 4, 5, 6, 7, 8, 10})); +} + +TEST(SortedVectorTypes, TestSetBulkInsertionSortMergeDups) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add an unsorted range that will have to be merged in. + s = makeVectorOfWrappers({10, 6, 5, 2}); + + vset.insert(s.begin(), s.end()); + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 1); + EXPECT_THAT( + extractValues(vset), testing::ElementsAreArray({2, 4, 5, 6, 8, 10})); +} + +TEST(SortedVectorTypes, TestSetInsertionDupsOneByOne) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add an unsorted range that will have to be merged in. + s = makeVectorOfWrappers({10, 6, 5, 2}); + + for (const auto& elem : s) { + vset.insert(elem); + } + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 3); + EXPECT_THAT( + extractValues(vset), testing::ElementsAreArray({2, 4, 5, 6, 8, 10})); +} + +TEST(SortedVectorTypes, TestSetBulkInsertionSortNoMerge) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add an unsorted range that will not have to be merged in. + s = makeVectorOfWrappers({20, 15, 16, 13}); + + vset.insert(s.begin(), s.end()); + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 1); + EXPECT_THAT( + extractValues(vset), + testing::ElementsAreArray({2, 4, 6, 8, 13, 15, 16, 20})); +} + +TEST(SortedVectorTypes, TestSetBulkInsertionNoSortMerge) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add a sorted range that will have to be merged in. + s = makeVectorOfWrappers({1, 3, 5, 9}); + + vset.insert(s.begin(), s.end()); + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 1); + EXPECT_THAT( + extractValues(vset), testing::ElementsAreArray({1, 2, 3, 4, 5, 6, 8, 9})); +} + +TEST(SortedVectorTypes, TestSetBulkInsertionNoSortNoMerge) { + auto s = makeVectorOfWrappers({6, 4, 8, 2}); + + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + // Add a sorted range that will not have to be merged in. + s = makeVectorOfWrappers({21, 22, 23, 24}); + + vset.insert(s.begin(), s.end()); + check_invariant(vset); + EXPECT_EQ(vset.rbegin()->count_, 1); + EXPECT_THAT( + extractValues(vset), + testing::ElementsAreArray({2, 4, 6, 8, 21, 22, 23, 24})); +} + +TEST(SortedVectorTypes, TestSetBulkInsertionEmptyRange) { + std::vector s; + EXPECT_TRUE(s.empty()); + + // insertion of empty range into empty container. + sorted_vector_set vset(s.begin(), s.end()); + check_invariant(vset); + + s = makeVectorOfWrappers({6, 4, 8, 2}); + + vset.insert(s.begin(), s.end()); + + // insertion of empty range into non-empty container. + s.clear(); + vset.insert(s.begin(), s.end()); + check_invariant(vset); + + EXPECT_THAT(extractValues(vset), testing::ElementsAreArray({2, 4, 6, 8})); +} + +// This is a test of compilation - the behavior has already been tested +// extensively above. +TEST(SortedVectorTypes, TestBulkInsertionUncopyableTypes) { + std::vector>> s; + s.emplace_back(1, std::make_unique(0)); + + sorted_vector_map> vmap( + std::make_move_iterator(s.begin()), std::make_move_iterator(s.end())); + + s.clear(); + s.emplace_back(3, std::make_unique(0)); + vmap.insert( + std::make_move_iterator(s.begin()), std::make_move_iterator(s.end())); +} + +// A moveable and copyable struct, which we use to make sure that no copy +// operations are performed during bulk insertion if moving is an option. +struct Movable { + int x_; + explicit Movable(int x) : x_(x) {} + Movable(const Movable&) { + ADD_FAILURE() << "Copy ctor should not be called"; + } + Movable& operator=(const Movable&) { + ADD_FAILURE() << "Copy assignment should not be called"; + return *this; + } + + Movable(Movable&&) = default; + Movable& operator=(Movable&&) = default; +}; + +TEST(SortedVectorTypes, TestBulkInsertionMovableTypes) { + std::vector> s; + s.emplace_back(3, Movable(2)); + s.emplace_back(1, Movable(0)); + + sorted_vector_map vmap( + std::make_move_iterator(s.begin()), std::make_move_iterator(s.end())); + + s.clear(); + s.emplace_back(4, Movable(3)); + s.emplace_back(2, Movable(1)); + vmap.insert( + std::make_move_iterator(s.begin()), std::make_move_iterator(s.end())); +} + +TEST(SortedVectorTypes, TestSetCreationFromVector) { + std::vector vec = {3, 1, -1, 5, 0}; + sorted_vector_set vset(std::move(vec)); + check_invariant(vset); + EXPECT_THAT(vset, testing::ElementsAreArray({-1, 0, 1, 3, 5})); +} + +TEST(SortedVectorTypes, TestMapCreationFromVector) { + std::vector> vec = { + {3, 1}, {1, 5}, {-1, 2}, {5, 3}, {0, 3}}; + sorted_vector_map vmap(std::move(vec)); + check_invariant(vmap); + auto contents = std::vector>(vmap.begin(), vmap.end()); + auto expected_contents = std::vector>({ + {-1, 2}, {0, 3}, {1, 5}, {3, 1}, {5, 3}, + }); + EXPECT_EQ(contents, expected_contents); +}