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,
difference_type distance = std::distance(first, last);
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for ForEach");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
......
......@@ -229,7 +229,9 @@ void MergeSort(
functor_t;
difference_type distance = std::distance(first, last);
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();
if (num_cores == 0) {
......@@ -264,8 +266,6 @@ void MergeSort(
task.Wait(MTAPI_INFINITE);
}
// @NOTE: Why is there no type guard for RAI?
} // namespace algorithms
} // namespace embb
......
......@@ -194,8 +194,10 @@ void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
embb::mtapi::Node& node = embb::mtapi::Node::GetInstance();
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance <= 0) {
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for QuickSort");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
......
......@@ -129,7 +129,9 @@ ReturnType ReduceRecursive(RAI first, RAI last, ReturnType neutral,
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
difference_type distance = std::distance(first, last);
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();
if (num_cores == 0) {
......
......@@ -173,8 +173,10 @@ void ScanIteratorCheck(RAIIn first, RAIIn last, RAIOut output_iterator,
std::random_access_iterator_tag) {
typedef typename std::iterator_traits<RAIIn>::difference_type difference_type;
difference_type distance = std::distance(first, last);
if (distance <= 0) {
if (distance == 0) {
return;
} else if (distance < 0) {
EMBB_THROW(embb::base::ErrorException, "Negative range for Scan");
}
unsigned int num_cores = policy.GetCoreCount();
if (num_cores == 0) {
......
......@@ -167,6 +167,11 @@ void MergeSortAllocate(
typedef base::Allocation Alloc;
typename std::iterator_traits<RAI>::difference_type distance = last - first;
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*>(
Alloc::Allocate(distance * sizeof(value_type)));
EMBB_TRY {
......
......@@ -211,6 +211,31 @@ void ForEachTest::TestPolicy() {
for (size_t i = 0; i < count; 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() {
......
......@@ -156,28 +156,28 @@ void MergeSortTest::TestRanges() {
}
}
//void MergeSortTest::TestBlockSizes() {
// using embb::algorithms::MergeSortAllocate;
// using embb::algorithms::ExecutionPolicy;
// size_t count = 4;
// std::vector<int> init(count);
// std::vector<int> vector(count);
// std::vector<int> vector_copy(count);
// for (size_t i = count - 1; i > 0; i--) {
// init[i] = static_cast<int>(i+2);
// }
// vector_copy = init;
// std::sort(vector_copy.begin(), vector_copy.end());
//
// for (size_t block_size = 1; block_size < count + 2; block_size++) {
// vector = init;
// MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
// ExecutionPolicy(), block_size);
// for (size_t i = 0; i < count; i++) {
// PT_EXPECT_EQ(vector[i], vector_copy[i]);
// }
// }
//}
void MergeSortTest::TestBlockSizes() {
using embb::algorithms::MergeSortAllocate;
using embb::mtapi::ExecutionPolicy;
size_t count = 4;
std::vector<int> init(count);
std::vector<int> vector(count);
std::vector<int> vector_copy(count);
for (size_t i = count - 1; i > 0; i--) {
init[i] = static_cast<int>(i+2);
}
vector_copy = init;
std::sort(vector_copy.begin(), vector_copy.end());
for (size_t block_size = 1; block_size < count + 2; block_size++) {
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(), block_size);
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], vector_copy[i]);
}
}
}
void MergeSortTest::TestPolicy() {
using embb::algorithms::MergeSortAllocate;
......@@ -201,17 +201,43 @@ void MergeSortTest::TestPolicy() {
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true));
ExecutionPolicy(true));
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector_copy[i], vector[i]);
}
vector = init;
MergeSortAllocate(vector.begin(), vector.end(), std::less<int>(),
ExecutionPolicy(true, 1));
ExecutionPolicy(true, 1));
for (size_t i = 0; i < count; 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() {
......
......@@ -58,7 +58,7 @@ class MergeSortTest : public partest::TestCase {
/**
* Tests various block sizes for the workers.
*/
//void TestBlockSizes();
void TestBlockSizes();
/**
* Tests setting policies (without checking their actual execution).
......
......@@ -218,6 +218,32 @@ void QuickSortTest::TestPolicy() {
for (size_t i = 0; i < count; 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() {
......
......@@ -181,6 +181,31 @@ void ReduceTest::TestPolicy() {
Identity(), ExecutionPolicy(true)), sum);
PT_EXPECT_EQ(Reduce(vector.begin(), vector.end(), 0, std::plus<int>(),
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() {
......
......@@ -290,6 +290,35 @@ void ScanTest::TestPolicy() {
expected += vector[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() {
......
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