mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-16 19:32:07 +00:00
541 lines
18 KiB
C++
541 lines
18 KiB
C++
|
#include <gtest/gtest.h>
|
||
|
|
||
|
#include <set>
|
||
|
#include <map>
|
||
|
|
||
|
#include <base/types.h>
|
||
|
#include <Common/IntervalTree.h>
|
||
|
|
||
|
|
||
|
using namespace DB;
|
||
|
using Int64Interval = Interval<Int64>;
|
||
|
|
||
|
template <typename IntervalType>
|
||
|
std::set<IntervalType> intervalSetToSet(const IntervalSet<IntervalType> & interval_set)
|
||
|
{
|
||
|
std::set<IntervalType> result;
|
||
|
|
||
|
for (const auto & interval : interval_set)
|
||
|
result.insert(interval);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
template <typename IntervalType, typename Value>
|
||
|
std::map<IntervalType, Value> intervalMapToMap(const IntervalMap<IntervalType, Value> & interval_map)
|
||
|
{
|
||
|
std::map<IntervalType, Value> result;
|
||
|
|
||
|
for (const auto & [interval, value] : interval_map)
|
||
|
result.emplace(interval, value);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
template <typename IntervalType>
|
||
|
struct CollectIntervalsSetCallback
|
||
|
{
|
||
|
explicit CollectIntervalsSetCallback(std::set<IntervalType> & result_intervals_)
|
||
|
: result_intervals(result_intervals_)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool operator()(IntervalType interval)
|
||
|
{
|
||
|
result_intervals.insert(interval);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::set<IntervalType> & result_intervals;
|
||
|
};
|
||
|
|
||
|
using CollectIntervalsSetInt64Callback = CollectIntervalsSetCallback<Int64Interval>;
|
||
|
|
||
|
template <typename IntervalType>
|
||
|
std::set<IntervalType> intervalSetFindIntervals(const IntervalSet<IntervalType> & interval_set, typename IntervalType::IntervalStorageType point)
|
||
|
{
|
||
|
std::set<IntervalType> result;
|
||
|
CollectIntervalsSetCallback<IntervalType> callback(result);
|
||
|
|
||
|
interval_set.find(point, callback);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
template <typename IntervalType, typename Value>
|
||
|
struct CollectIntervalsMapCallback
|
||
|
{
|
||
|
explicit CollectIntervalsMapCallback(std::map<IntervalType, Value> & result_intervals_)
|
||
|
: result_intervals(result_intervals_)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool operator()(IntervalType interval, const Value & value)
|
||
|
{
|
||
|
result_intervals.emplace(interval, value);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::map<IntervalType, Value> & result_intervals;
|
||
|
};
|
||
|
|
||
|
|
||
|
template <typename IntervalType, typename Value>
|
||
|
std::map<IntervalType, Value> intervalMapFindIntervals(const IntervalMap<IntervalType, Value> & interval_set, typename IntervalType::IntervalStorageType point)
|
||
|
{
|
||
|
std::map<IntervalType, Value> result;
|
||
|
CollectIntervalsMapCallback callback(result);
|
||
|
|
||
|
interval_set.find(point, callback);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalSetBasic)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::set<Int64Interval> expected;
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index * 2, interval_index * 2 + 1);
|
||
|
expected.insert(interval);
|
||
|
set.insert(interval);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
std::set<Int64Interval> expected_intervals = {{expected_interval}};
|
||
|
|
||
|
auto actual_intervals = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalSetFindIntervals(set, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
set.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
auto actual_interval = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_interval.size() == 1);
|
||
|
ASSERT_TRUE(actual_interval == std::set<Int64Interval>{expected_interval});
|
||
|
|
||
|
actual_interval = intervalSetFindIntervals(set, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_interval.size() == 1);
|
||
|
ASSERT_TRUE(actual_interval == std::set<Int64Interval>{expected_interval});
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalSetPoints)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::set<Int64Interval> expected;
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index, interval_index);
|
||
|
expected.insert(interval);
|
||
|
set.insert(interval);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
std::set<Int64Interval> expected_intervals = {{expected_interval}};
|
||
|
|
||
|
auto actual_intervals = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalSetFindIntervals(set, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
set.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
auto actual_interval = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_interval.size() == 1);
|
||
|
ASSERT_TRUE(actual_interval == std::set<Int64Interval>{expected_interval});
|
||
|
|
||
|
actual_interval = intervalSetFindIntervals(set, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_interval.size() == 1);
|
||
|
ASSERT_TRUE(actual_interval == std::set<Int64Interval>{expected_interval});
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalSetIntersectingIntervals)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::set<Int64Interval> expected;
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(0, interval_index * 2 + 1);
|
||
|
expected.insert(interval);
|
||
|
set.insert(interval);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(set.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
auto actual_intervals = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == expected.size());
|
||
|
ASSERT_TRUE(actual_intervals == expected);
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
set.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalSetToSet(set) == expected);
|
||
|
|
||
|
for (const auto & expected_interval : expected)
|
||
|
{
|
||
|
auto actual_intervals = intervalSetFindIntervals(set, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == expected.size());
|
||
|
ASSERT_TRUE(actual_intervals == expected);
|
||
|
|
||
|
ASSERT_TRUE(set.has(expected_interval.left));
|
||
|
ASSERT_TRUE(set.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalSetIterators)
|
||
|
{
|
||
|
{
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
ASSERT_TRUE(set.begin() == set.end());
|
||
|
ASSERT_TRUE(set.cbegin() == set.cend());
|
||
|
set.construct();
|
||
|
ASSERT_TRUE(set.begin() == set.end());
|
||
|
ASSERT_TRUE(set.cbegin() == set.cend());
|
||
|
}
|
||
|
{
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
set.emplace(Int64Interval(0, 5));
|
||
|
ASSERT_TRUE(set.begin() != set.end());
|
||
|
ASSERT_TRUE((*set.begin()).left == 0);
|
||
|
ASSERT_TRUE((*set.begin()).right == 5);
|
||
|
ASSERT_TRUE(set.begin()->left == 0);
|
||
|
ASSERT_TRUE(set.begin()->right == 5);
|
||
|
auto begin = set.begin();
|
||
|
++begin;
|
||
|
ASSERT_TRUE(begin == set.end());
|
||
|
|
||
|
begin = set.begin();
|
||
|
begin++;
|
||
|
ASSERT_TRUE(begin == set.end());
|
||
|
|
||
|
auto end = set.end();
|
||
|
--end;
|
||
|
ASSERT_TRUE(set.begin() == end);
|
||
|
|
||
|
end = set.end();
|
||
|
end--;
|
||
|
ASSERT_TRUE(set.begin() == end);
|
||
|
}
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::set<Int64Interval> expected;
|
||
|
IntervalSet<Int64Interval> set;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index * 2, interval_index * 2 + 1);
|
||
|
set.insert(interval);
|
||
|
expected.insert(interval);
|
||
|
}
|
||
|
|
||
|
auto end = set.end();
|
||
|
auto begin = set.begin();
|
||
|
|
||
|
std::set<Int64Interval> actual;
|
||
|
|
||
|
while (end != begin)
|
||
|
{
|
||
|
--end;
|
||
|
actual.insert(*end);
|
||
|
}
|
||
|
|
||
|
if (end != begin)
|
||
|
actual.insert(*end);
|
||
|
|
||
|
ASSERT_TRUE(actual == expected);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalMapBasic)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected;
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index * 2, interval_index * 2 + 1);
|
||
|
auto value = std::to_string(interval.left);
|
||
|
expected.emplace(interval, value);
|
||
|
map.emplace(interval, value);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected_intervals = {{expected_interval, std::to_string(expected_interval.left)}};
|
||
|
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalMapFindIntervals(map, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
map.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected_intervals = {{expected_interval, std::to_string(expected_interval.left)}};
|
||
|
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalMapFindIntervals(map, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalMapPoints)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected;
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index, interval_index);
|
||
|
auto value = std::to_string(interval.left);
|
||
|
expected.emplace(interval, value);
|
||
|
map.emplace(interval, value);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected_intervals = {{expected_interval, std::to_string(expected_interval.left)}};
|
||
|
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalMapFindIntervals(map, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
map.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected_intervals = {{expected_interval, std::to_string(expected_interval.left)}};
|
||
|
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
actual_intervals = intervalMapFindIntervals(map, expected_interval.right);
|
||
|
ASSERT_TRUE(actual_intervals.size() == 1);
|
||
|
ASSERT_TRUE(actual_intervals == expected_intervals);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalMapIntersectingIntervals)
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected;
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(0, interval_index * 2 + 1);
|
||
|
auto value = std::to_string(interval.left);
|
||
|
expected.emplace(interval, value);
|
||
|
map.emplace(interval, value);
|
||
|
}
|
||
|
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == expected.size());
|
||
|
ASSERT_TRUE(map.getIntervalsSize() == intervals_size);
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
|
||
|
ASSERT_TRUE(actual_intervals.size() == expected.size());
|
||
|
ASSERT_TRUE(actual_intervals == expected);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
|
||
|
map.construct();
|
||
|
|
||
|
ASSERT_TRUE(intervalMapToMap(map) == expected);
|
||
|
|
||
|
for (const auto & [expected_interval, value] : expected)
|
||
|
{
|
||
|
auto actual_intervals = intervalMapFindIntervals(map, expected_interval.left);
|
||
|
|
||
|
ASSERT_TRUE(actual_intervals.size() == expected.size());
|
||
|
ASSERT_TRUE(actual_intervals == expected);
|
||
|
|
||
|
ASSERT_TRUE(map.has(expected_interval.left));
|
||
|
ASSERT_TRUE(map.has(expected_interval.right));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TEST(IntervalTree, IntervalMapIterators)
|
||
|
{
|
||
|
{
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
ASSERT_TRUE(map.begin() == map.end());
|
||
|
ASSERT_TRUE(map.cbegin() == map.cend());
|
||
|
map.construct();
|
||
|
ASSERT_TRUE(map.begin() == map.end());
|
||
|
ASSERT_TRUE(map.cbegin() == map.cend());
|
||
|
}
|
||
|
{
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
map.emplace(Int64Interval(0, 5), "value");
|
||
|
ASSERT_TRUE(map.begin() != map.end());
|
||
|
ASSERT_TRUE((*map.begin()).first.left == 0);
|
||
|
ASSERT_TRUE((*map.begin()).first.right == 5);
|
||
|
ASSERT_TRUE((*map.begin()).second == "value");
|
||
|
ASSERT_TRUE(map.begin()->first.left == 0);
|
||
|
ASSERT_TRUE(map.begin()->first.right == 5);
|
||
|
ASSERT_TRUE(map.begin()->second == "value");
|
||
|
auto begin = map.begin();
|
||
|
++begin;
|
||
|
ASSERT_TRUE(begin == map.end());
|
||
|
|
||
|
begin = map.begin();
|
||
|
begin++;
|
||
|
ASSERT_TRUE(begin == map.end());
|
||
|
|
||
|
auto end = map.end();
|
||
|
--end;
|
||
|
ASSERT_TRUE(map.begin() == end);
|
||
|
|
||
|
end = map.end();
|
||
|
end--;
|
||
|
ASSERT_TRUE(map.begin() == end);
|
||
|
}
|
||
|
{
|
||
|
for (size_t intervals_size = 0; intervals_size < 120; ++intervals_size)
|
||
|
{
|
||
|
std::map<Int64Interval, std::string> expected;
|
||
|
IntervalMap<Int64Interval, std::string> map;
|
||
|
|
||
|
for (size_t interval_index = 0; interval_index < intervals_size; ++interval_index)
|
||
|
{
|
||
|
auto interval = Int64Interval(interval_index * 2, interval_index * 2 + 1);
|
||
|
auto value = std::to_string(interval.left);
|
||
|
map.emplace(interval, value);
|
||
|
expected.emplace(interval, value);
|
||
|
}
|
||
|
|
||
|
auto end = map.end();
|
||
|
auto begin = map.begin();
|
||
|
|
||
|
std::map<Int64Interval, std::string> actual;
|
||
|
|
||
|
while (end != begin)
|
||
|
{
|
||
|
--end;
|
||
|
actual.insert(*end);
|
||
|
}
|
||
|
|
||
|
if (end != begin)
|
||
|
actual.insert(*end);
|
||
|
|
||
|
ASSERT_TRUE(actual == expected);
|
||
|
}
|
||
|
}
|
||
|
}
|