Commit c85e738a by Tobias Fuchs

algorithms_cpp: unified behavior on empty input, added unit tests on empty and…

algorithms_cpp: unified behavior on empty input, added unit tests on empty and negative input ranges
parent fcf7144f
...@@ -107,6 +107,8 @@ void ForEachRecursive(RAI first, RAI last, Function unary, ...@@ -107,6 +107,8 @@ void ForEachRecursive(RAI first, RAI last, Function unary,
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance == 0) { if (distance == 0) {
return; return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for ForEach");
} }
unsigned int num_cores = policy.GetCoreCount(); unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) { if (num_cores == 0) {
......
...@@ -229,7 +229,9 @@ void MergeSort( ...@@ -229,7 +229,9 @@ void MergeSort(
functor_t; functor_t;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance == 0) { if (distance == 0) {
EMBB_THROW(embb::base::ErrorException, "Distance for ForEach is 0"); return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for MergeSort");
} }
unsigned int num_cores = policy.GetCoreCount(); unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) { if (num_cores == 0) {
...@@ -264,8 +266,6 @@ void MergeSort( ...@@ -264,8 +266,6 @@ void MergeSort(
task.Wait(MTAPI_INFINITE); task.Wait(MTAPI_INFINITE);
} }
// @NOTE: Why is there no type guard for RAI?
} // namespace algorithms } // namespace algorithms
} // namespace embb } // namespace embb
......
...@@ -194,8 +194,10 @@ void QuickSort(RAI first, RAI last, ComparisonFunction comparison, ...@@ -194,8 +194,10 @@ void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance(); embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
typedef typename std::iterator_traits<RAI>::difference_type difference_type; typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance <= 0) { if (distance == 0) {
return; return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for QuickSort");
} }
unsigned int num_cores = policy.GetCoreCount(); unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) { if (num_cores == 0) {
......
...@@ -129,7 +129,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral, ...@@ -129,7 +129,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
typedef typename std::iterator_traits<RAI>::difference_type difference_type; typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance == 0) { if (distance == 0) {
EMBB_THROW(embb::base::ErrorException, "Distance for Reduce is 0"); return neutral;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for Reduce");
} }
unsigned int num_cores = policy.GetCoreCount(); unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) { if (num_cores == 0) {
......
...@@ -173,8 +173,10 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator, ...@@ -173,8 +173,10 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
std::random_access_iterator_tag) { std::random_access_iterator_tag) {
typedef typename std::iterator_traits<RAIIn>::difference_type difference_type; typedef typename std::iterator_traits<RAIIn>::difference_type difference_type;
difference_type distance = std::distance(first, last); difference_type distance = std::distance(first, last);
if (distance <= 0) { if (distance == 0) {
return; return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for Scan");
} }
unsigned int num_cores = policy.GetCoreCount(); unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) { if (num_cores == 0) {
......
...@@ -167,6 +167,11 @@ void MergeSortAllocate( ...@@ -167,6 +167,11 @@ void MergeSortAllocate(
typedef base::Allocation Alloc; typedef base::Allocation Alloc;
typename std::iterator_traits<RAI>::difference_type distance = last - first; typename std::iterator_traits<RAI>::difference_type distance = last - first;
typedef typename std::iterator_traits<RAI>::value_type value_type; typedef typename std::iterator_traits<RAI>::value_type value_type;
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for MergeSort");
}
value_type* temporary = static_cast<value_type*>( value_type* temporary = static_cast<value_type*>(
Alloc::Allocate(distance * sizeof(value_type))); Alloc::Allocate(distance * sizeof(value_type)));
EMBB_TRY { EMBB_TRY {
......
...@@ -211,6 +211,31 @@ void ForEachTest::TestPolicy() { ...@@ -211,6 +211,31 @@ void ForEachTest::TestPolicy() {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]); PT_EXPECT_EQ(vector[i], init[i]*init[i]);
} }
// ForEach on empty list should not throw:
ForEach(vector.begin(), vector.begin(), Square());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
ForEach(second, vector.begin(), Square());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
} }
void ForEachTest::StressTest() { void ForEachTest::StressTest() {
......
...@@ -156,28 +156,28 @@ void MergeSortTest::TestRanges() { ...@@ -156,28 +156,28 @@ void MergeSortTest::TestRanges() {
} }
} }
//void MergeSortTest::TestBlockSizes() { void MergeSortTest::TestBlockSizes() {
// using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
// using embb::algorithms::ExecutionPolicy; using embb::mtapi::ExecutionPolicy;
// size_t count = 4; size_t count = 4;
// std::vector<int> init(count); std::vector<int> init(count);
// std::vector<int> vector(count); std::vector<int> vector(count);
// std::vector<int> vector_copy(count); std::vector<int> vector_copy(count);
// for (size_t i = count - 1; i > 0; i--) { for (size_t i = count - 1; i > 0; i--) {
// init[i] = static_cast<int>(i+2); init[i] = static_cast<int>(i+2);
// } }
// vector_copy = init; vector_copy = init;
// std::sort(vector_copy.begin(), vector_copy.end()); std::sort(vector_copy.begin(), vector_copy.end());
//
// for (size_t block_size = 1; block_size < count + 2; block_size++) { for (size_t block_size = 1; block_size < count + 2; block_size++) {
// vector = init; vector = init;
// MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(), MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
// ExecutionPolicy(), block_size); ExecutionPolicy(), block_size);
// for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
// PT_EXPECT_EQ(vector[i], vector_copy[i]); PT_EXPECT_EQ(vector[i], vector_copy[i]);
// } }
// } }
//} }
void MergeSortTest::TestPolicy() { void MergeSortTest::TestPolicy() {
using embb::algorithms::MergeSortAllocate; using embb::algorithms::MergeSortAllocate;
...@@ -201,17 +201,43 @@ void MergeSortTest::TestPolicy() { ...@@ -201,17 +201,43 @@ void MergeSortTest::TestPolicy() {
vector = init; vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(), MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true)); ExecutionPolicy(true));
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]); PT_EXPECT_EQ(vector_copy[i], vector[i]);
} }
vector = init; vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(), MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true, 1)); ExecutionPolicy(true, 1));
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]); PT_EXPECT_EQ(vector_copy[i], vector[i]);
} }
// MergeSort on empty list should not throw:
MergeSortAllocate(vector.begin(), vector.begin(), std::less<int>());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
MergeSortAllocate(second, vector.begin(), std::less<int>());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
} }
void MergeSortTest::StressTest() { void MergeSortTest::StressTest() {
......
...@@ -58,7 +58,7 @@ class MergeSortTest : public partest::TestCase { ...@@ -58,7 +58,7 @@ class MergeSortTest : public partest::TestCase {
/** /**
* Tests various block sizes for the workers. * Tests various block sizes for the workers.
*/ */
//void TestBlockSizes(); void TestBlockSizes();
/** /**
* Tests setting policies (without checking their actual execution). * Tests setting policies (without checking their actual execution).
......
...@@ -218,6 +218,32 @@ void QuickSortTest::TestPolicy() { ...@@ -218,6 +218,32 @@ void QuickSortTest::TestPolicy() {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]); PT_EXPECT_EQ(vector_copy[i], vector[i]);
} }
// MergeSort on empty list should not throw:
QuickSort(vector.begin(), vector.begin(), std::less<int>());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
QuickSort(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
QuickSort(second, vector.begin(), std::less<int>());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
} }
void QuickSortTest::StressTest() { void QuickSortTest::StressTest() {
......
...@@ -181,6 +181,31 @@ void ReduceTest::TestPolicy() { ...@@ -181,6 +181,31 @@ void ReduceTest::TestPolicy() {
Identity(), ExecutionPolicy(true)), sum); Identity(), ExecutionPolicy(true)), sum);
PT_EXPECT_EQ(Reduce(vector.begin(), vector.end(), 0, std::plus<int>(), PT_EXPECT_EQ(Reduce(vector.begin(), vector.end(), 0, std::plus<int>(),
Identity(), ExecutionPolicy(true, 1)), sum); Identity(), ExecutionPolicy(true, 1)), sum);
// Empty list should return neutral element:
PT_EXPECT_EQ(Reduce(vector.begin(), vector.begin(), 41, std::plus<int>(),
Identity(), ExecutionPolicy(true, 1)), 41);
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
Reduce(vector.begin(), vector.end(), 0,
std::plus<int>(), Identity(),
ExecutionPolicy(false));
} catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
Reduce(second, vector.begin(), 0, std::plus<int>());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
} }
void ReduceTest::StressTest() { void ReduceTest::StressTest() {
......
...@@ -290,6 +290,35 @@ void ScanTest::TestPolicy() { ...@@ -290,6 +290,35 @@ void ScanTest::TestPolicy() {
expected += vector[i]; expected += vector[i];
PT_EXPECT_EQ(expected, outputVector[i]); PT_EXPECT_EQ(expected, outputVector[i]);
} }
// Empty list should not throw and not change output:
outputVector = init;
std::vector<int>::iterator out_it = outputVector.begin();
Scan(vector.begin(), vector.begin(), out_it, 0, std::plus<int>());
PT_EXPECT(out_it == outputVector.begin());
#ifdef EMBB_USE_EXCEPTIONS
bool empty_core_set_thrown = false;
try {
Scan(vector.begin(), vector.end(), outputVector.begin(),
0, std::plus<int>(), Identity(),
ExecutionPolicy(false));
}
catch (embb::base::ErrorException &) {
empty_core_set_thrown = true;
}
PT_EXPECT_MSG(empty_core_set_thrown,
"Empty core set should throw ErrorException");
bool negative_range_thrown = false;
try {
std::vector<int>::iterator second = vector.begin() + 1;
Scan(second, vector.begin(), outputVector.begin(), 0, std::plus<int>());
}
catch (embb::base::ErrorException &) {
negative_range_thrown = true;
}
PT_EXPECT_MSG(negative_range_thrown,
"Negative range should throw ErrorException");
#endif
} }
void ScanTest::StressTest() { void ScanTest::StressTest() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment