Skip to content

Commit

Permalink
Implement additional set operators: STLSetUnion, STLSetIntersection a…
Browse files Browse the repository at this point in the history
…nd STLIncludes.

BUG=336824
TBR=willchan@chromium.org, jyasskin@chromium.org
(lgtm'ed in https://codereview.chromium.org/145663004/)

Review URL: https://codereview.chromium.org/148183012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247711 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rpaquay@chromium.org committed Jan 29, 2014
1 parent e200bac commit 9a53ade
Show file tree
Hide file tree
Showing 2 changed files with 200 additions and 3 deletions.
43 changes: 40 additions & 3 deletions base/stl_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,11 @@ namespace base {
// Returns true if the container is sorted.
template <typename Container>
bool STLIsSorted(const Container& cont) {
return std::adjacent_find(cont.begin(), cont.end(),
std::greater<typename Container::value_type>())
== cont.end();
// Note: Use reverse iterator on container to ensure we only require
// value_type to implement operator<.
return std::adjacent_find(cont.rbegin(), cont.rend(),
std::less<typename Container::value_type>())
== cont.rend();
}

// Returns a new ResultType containing the difference of two sorted containers.
Expand All @@ -218,6 +220,41 @@ ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
return difference;
}

// Returns a new ResultType containing the union of two sorted containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
ResultType result;
std::set_union(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}

// Returns a new ResultType containing the intersection of two sorted
// containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
ResultType result;
std::set_intersection(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}

// Returns true if the sorted container |a1| contains all elements of the sorted
// container |a2|.
template <typename Arg1, typename Arg2>
bool STLIncludes(const Arg1& a1, const Arg2& a2) {
DCHECK(STLIsSorted(a1));
DCHECK(STLIsSorted(a2));
return std::includes(a1.begin(), a1.end(),
a2.begin(), a2.end());
}

} // namespace base

#endif // BASE_STL_UTIL_H_
160 changes: 160 additions & 0 deletions base/stl_util_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@

#include "testing/gtest/include/gtest/gtest.h"

namespace {

// Used as test case to ensure the various base::STLXxx functions don't require
// more than operators "<" and "==" on values stored in containers.
class ComparableValue {
public:
explicit ComparableValue(int value) : value_(value) {}

bool operator==(const ComparableValue& rhs) const {
return value_ == rhs.value_;
}

bool operator<(const ComparableValue& rhs) const {
return value_ < rhs.value_;
}

private:
int value_;
};

}

namespace base {
namespace {

Expand All @@ -20,6 +42,14 @@ TEST(STLUtilTest, STLIsSorted) {
EXPECT_TRUE(STLIsSorted(set));
}

{
std::set<ComparableValue> set;
set.insert(ComparableValue(24));
set.insert(ComparableValue(1));
set.insert(ComparableValue(12));
EXPECT_TRUE(STLIsSorted(set));
}

{
std::vector<int> vector;
vector.push_back(1);
Expand Down Expand Up @@ -78,5 +108,135 @@ TEST(STLUtilTest, STLSetDifference) {
}
}

TEST(STLUtilTest, STLSetUnion) {
std::set<int> a1;
a1.insert(1);
a1.insert(2);
a1.insert(3);
a1.insert(4);

std::set<int> a2;
a2.insert(3);
a2.insert(4);
a2.insert(5);
a2.insert(6);
a2.insert(7);

{
std::set<int> result;
result.insert(1);
result.insert(2);
result.insert(3);
result.insert(4);
result.insert(5);
result.insert(6);
result.insert(7);
EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2));
}

{
std::set<int> result;
result.insert(1);
result.insert(2);
result.insert(3);
result.insert(4);
result.insert(5);
result.insert(6);
result.insert(7);
EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1));
}

{
std::vector<int> result;
result.push_back(1);
result.push_back(2);
result.push_back(3);
result.push_back(4);
result.push_back(5);
result.push_back(6);
result.push_back(7);
EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2));
}

{
std::vector<int> result;
result.push_back(1);
result.push_back(2);
result.push_back(3);
result.push_back(4);
result.push_back(5);
result.push_back(6);
result.push_back(7);
EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1));
}
}

TEST(STLUtilTest, STLSetIntersection) {
std::set<int> a1;
a1.insert(1);
a1.insert(2);
a1.insert(3);
a1.insert(4);

std::set<int> a2;
a2.insert(3);
a2.insert(4);
a2.insert(5);
a2.insert(6);
a2.insert(7);

{
std::set<int> result;
result.insert(3);
result.insert(4);
EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2));
}

{
std::set<int> result;
result.insert(3);
result.insert(4);
EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1));
}

{
std::vector<int> result;
result.push_back(3);
result.push_back(4);
EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2));
}

{
std::vector<int> result;
result.push_back(3);
result.push_back(4);
EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1));
}
}

TEST(STLUtilTest, STLIncludes) {
std::set<int> a1;
a1.insert(1);
a1.insert(2);
a1.insert(3);
a1.insert(4);

std::set<int> a2;
a2.insert(3);
a2.insert(4);

std::set<int> a3;
a3.insert(3);
a3.insert(4);
a3.insert(5);

EXPECT_TRUE(STLIncludes<std::set<int> >(a1, a2));
EXPECT_FALSE(STLIncludes<std::set<int> >(a1, a3));
EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a1));
EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a3));
EXPECT_FALSE(STLIncludes<std::set<int> >(a3, a1));
EXPECT_TRUE(STLIncludes<std::set<int> >(a3, a2));
}

} // namespace
} // namespace base

0 comments on commit 9a53ade

Please sign in to comment.