Commit db74f3e9 by Christian Kern

Merge branch 'development' into embb6_use_bin_sh

parents 59354d40 ad71c970
......@@ -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) {
......
......@@ -213,23 +213,24 @@ class MergeSortFunctor {
}
};
} // namespace internal
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(
void MergeSortIteratorCheck(
RAI first,
RAI last,
RAITemp temporary_first,
ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size
size_t block_size,
std::random_access_iterator_tag
) {
typedef typename std::iterator_traits<RAI>::difference_type difference_type;
typedef internal::MergeSortFunctor<RAI, RAITemp, ComparisonFunction>
typedef MergeSortFunctor<RAI, RAITemp, ComparisonFunction>
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) {
......@@ -247,7 +248,7 @@ void MergeSort(
"Not enough MTAPI tasks available to perform merge sort");
}
internal::BlockSizePartitioner<RAI> partitioner(first, last, block_size);
BlockSizePartitioner<RAI> partitioner(first, last, block_size);
functor_t functor(0,
partitioner.Size() - 1,
temporary_first,
......@@ -264,7 +265,16 @@ void MergeSort(
task.Wait(MTAPI_INFINITE);
}
// @NOTE: Why is there no type guard for RAI?
} // namespace internal
template<typename RAI, typename RAITemp, typename ComparisonFunction>
void MergeSort(RAI first, RAI last, RAITemp temporary_first,
ComparisonFunction comparison, const embb::mtapi::ExecutionPolicy& policy,
size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::MergeSortIteratorCheck(first, last, temporary_first, comparison,
policy, block_size, category());
}
} // namespace algorithms
} // namespace embb
......
......@@ -186,16 +186,19 @@ class QuickSortFunctor {
QuickSortFunctor(const QuickSortFunctor&);
};
} // namespace internal
template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
void QuickSortIteratorCheck(RAI first, RAI last,
ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy,
size_t block_size,
std::random_access_iterator_tag) {
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) {
......@@ -210,13 +213,23 @@ void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
EMBB_THROW(embb::base::ErrorException,
"Not enough MTAPI tasks available for performing quick sort");
}
internal::QuickSortFunctor<RAI, ComparisonFunction> functor(
QuickSortFunctor<RAI, ComparisonFunction> functor(
first, last, comparison, policy, block_size);
mtapi::Task task = node.Spawn(mtapi::Action(base::MakeFunction(
functor, &internal::QuickSortFunctor<RAI, ComparisonFunction>::Action)));
functor, &QuickSortFunctor<RAI, ComparisonFunction>::Action)));
task.Wait(MTAPI_INFINITE);
}
} // namespace internal
template <typename RAI, typename ComparisonFunction>
void QuickSort(RAI first, RAI last, ComparisonFunction comparison,
const embb::mtapi::ExecutionPolicy& policy, size_t block_size) {
typedef typename std::iterator_traits<RAI>::iterator_category category;
internal::QuickSortIteratorCheck(first, last, comparison,
policy, block_size, category());
}
} // namespace algorithms
} // namespace embb
......
......@@ -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,14 +173,16 @@ 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) {
EMBB_THROW(embb::base::ErrorException, "No cores in execution policy");
}
ReturnType values[MTAPI_NODE_MAX_TASKS_DEFAULT];
if (block_size == 0) {
block_size = static_cast<size_t>(distance) / num_cores;
......
......@@ -58,7 +58,7 @@ typedef embb::base::Function<void> InvokeFunctionType;
template<typename Function1, ...>
void Invoke(
Function1 func1,
/**< [in] First function to invoke */
/**< [in] First function object to invoke */
...);
/**
......@@ -72,7 +72,7 @@ void Invoke(
template<typename Function1, ...>
void Invoke(
Function1 func1,
/**< [in] Function to invoke */
/**< [in] Function object to invoke */
...,
const embb::mtapi::ExecutionPolicy & policy
/**< [in] embb::mtapi::ExecutionPolicy to use */
......
......@@ -167,9 +167,20 @@ 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)));
MergeSort(first, last, temporary, comparison, policy, block_size);
EMBB_TRY {
MergeSort(first, last, temporary, comparison, policy, block_size);
} EMBB_CATCH (embb::base::ErrorException & e) {
// embb exception handling does not support catch(...) and rethrow yet.
Alloc::Free(temporary);
EMBB_THROW(embb::base::ErrorException, e.what());
}
Alloc::Free(temporary);
}
......
......@@ -68,10 +68,10 @@ namespace algorithms {
* \tparam RAI Random access iterator
* \tparam ReturnType Type of result of reduction operation, deduced from
* \c neutral
* \tparam ReductionFunction Binary reduction function with signature
* \tparam ReductionFunction Binary reduction function object with signature
* <tt>ReturnType ReductionFunction(ReturnType, ReturnType)</tt>.
* \tparam TransformationFunction Unary transformation function with signature
* <tt>ReturnType TransformationFunction(typename
* \tparam TransformationFunction Unary transformation function object with
* signature <tt>ReturnType TransformationFunction(typename
* std::iterator_traits<RAI>::value_type)</tt>
*/
template<typename RAI, typename ReturnType, typename ReductionFunction,
......
......@@ -71,10 +71,10 @@ namespace algorithms {
* \tparam RAIOut Random access iterator type of output range
* \tparam ReturnType Type of output elements of scan operation, deduced from
* \c neutral
* \tparam ScanFunction Binary scan function with signature
* \tparam ScanFunction Binary scan function object with signature
* <tt>ReturnType ScanFunction(ReturnType, ReturnType)</tt>
* \tparam TransformationFunction Unary transformation function with signature
* <tt>ReturnType TransformationFunction(typename
* \tparam TransformationFunction Unary transformation function object with
* signature <tt>ReturnType TransformationFunction(typename
* std::iterator_traits<RAIIn>::value_type)</tt>.
*/
template<typename RAIIn, typename RAIOut, typename ReturnType,
......
......@@ -205,12 +205,37 @@ void ForEachTest::TestPolicy() {
for (size_t i = 0; i < count; i++) {
PT_EXPECT_EQ(vector[i], init[i]*init[i]);
}
vector = init;
ForEach(vector.begin(), vector.end(), Square(), ExecutionPolicy(true, 1));
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() {
......
......@@ -36,8 +36,8 @@ namespace internal {
/**
* Thread closure for thread start function with no arguments.
*
* Provides a thread start function calling a callable entity such as a function
* pointer or functor.
* Provides a thread start function from which a priorly stored function object
* is called.
*/
template<typename Function>
struct ThreadClosure {
......@@ -56,8 +56,8 @@ struct ThreadClosure {
/**
* Thread closure for thread start function with one argument.
*
* Provides a thread start function calling a callable entity such as a function
* pointer or functor.
* Provides a thread start function from which a priorly stored function object
* is called.
*/
template<typename Function, typename Arg1>
struct ThreadClosureArg1 {
......@@ -78,8 +78,8 @@ struct ThreadClosureArg1 {
/**
* Thread closure for thread start function with two arguments.
*
* Provides a thread start function calling a callable entity such as a function
* pointer or functor.
* Provides a thread start function from which a priorly stored function object
* is called.
*/
template<typename Function, typename Arg1, typename Arg2>
struct ThreadClosureArg2 {
......
......@@ -154,12 +154,12 @@ class Thread {
* \memory A small constant amount of memory to store the function. This
* memory is freed the thread is joined.
* \notthreadsafe
* \tparam Function Type of callable
* \tparam Function Function object type
*/
template<typename Function>
explicit Thread(
Function function
/**< [IN] Callable (without arguments, must be copyable) */
/**< [IN] Copyable function object, callable without arguments */
);
/**
......@@ -174,14 +174,14 @@ class Thread {
* \memory A small constant amount of memory to store the function. This
* memory is freed the thread is joined.
* \notthreadsafe
* \tparam Function Type of callable
* \tparam Function Function object type
*/
template<typename Function>
explicit Thread(
CoreSet& core_set,
/**< [IN] Set of cores on which the thread shall be executed. */
Function function
/**< [IN] Callable (without arguments, must be copyable) */
/**< [IN] Copyable function object, callable without arguments */
);
/**
......@@ -196,13 +196,13 @@ class Thread {
* \memory A small constant amount of memory to store the function. This
* memory is freed the thread is joined.
* \notthreadsafe
* \tparam Function Type of callable
* \tparam Function Function object type
* \tparam Argument Type of argument
*/
template<typename Function, typename Arg>
Thread(
Function function,
/**< [IN] Callable (with one argument, must be copyable) */
/**< [IN] Copyable function object, callable with one argument */
Arg arg
/**< [IN] Argument for function (must be copyable) */
);
......@@ -219,14 +219,14 @@ class Thread {
* \memory A small constant amount of memory to store the function. This
* memory is freed the thread is joined.
* \notthreadsafe
* \tparam Function Type of callable
* \tparam Function Function object type
* \tparam Arg1 Type of first argument
* \tparam Arg2 Type of second argument
*/
template<typename Function, typename Arg1, typename Arg2>
Thread(
Function function,
/**< [IN] Callable (with two arguments, must be copyable) */
/**< [IN] Copyable function object, callable with two arguments */
Arg1 arg1,
/**< [IN] First argument for function (must be copyable) */
Arg2 arg2
......
......@@ -68,7 +68,7 @@
* </tr>
* <tr>
* <td>Action Function</td>
* <td>The callable, an executable function of an action, invoked by the
* <td>The executable function of an action, invoked by the
* MTAPI runtime when a task is started.</td>
* </tr>
* <tr>
......
......@@ -51,13 +51,13 @@ class Action {
}
/**
* Constructs an Action from any entity that provides an
* operator() (TaskContext &).
* Constructs an Action from a function object.
*
* \tparam Function Function object
*/
template <typename Function>
Action(
Function func /**< [in] Anything that provides an
operator() (TaskContext &). */
Function func /**< [in] Function object */
)
: function_(func)
, execution_policy_() {
......@@ -65,13 +65,13 @@ class Action {
}
/**
* Constructs an Action from any entity that provides an
* operator() (TaskContext &) and an Affinity.
* Constructs an Action from a function object and an Affinity.
*
* \tparam Function Function object
*/
template <typename Function>
Action(
Function func, /**< [in] Anything that provides an
operator() (TaskContext &). */
Function func, /**< [in] Function object */
ExecutionPolicy execution_policy /**< [in] Execution policy */
)
: function_(func)
......
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