slsSupportLib and parallel call using variadic templates

This commit is contained in:
Erik Frojdh 2018-10-03 14:02:41 +02:00
parent 6bfc212f19
commit fefdf8e7d6
7 changed files with 420 additions and 0 deletions

View File

@ -87,6 +87,33 @@ void multiSlsDetector::setupMultiDetector(bool verify, bool update) {
updateUserdetails(); updateUserdetails();
} }
template <typename RT, typename... CT>
std::vector<RT> multiSlsDetector::serialCall(RT (slsDetector::*somefunc)(CT...), CT... Args)
{
std::vector<RT> result;
for (size_t det_id = 0; det_id < thisMultiDetector->numberOfDetectors; ++det_id) {
result.push_back(((*this)[det_id]->*somefunc)(Args...));
}
return result;
}
template <typename RT, typename... CT>
std::vector<RT> multiSlsDetector::parallelCall(RT (slsDetector::*somefunc)(CT...), CT... Args)
{
std::vector<std::future<RT>> futures;
for (size_t det_id = 0; det_id < thisMultiDetector->numberOfDetectors; ++det_id) {
futures.push_back(std::async(somefunc, (*this)[det_id], Args...));
}
std::vector<RT> result;
for (auto& i : futures)
result.push_back(i.get());
return result;
}
std::string multiSlsDetector::concatResultOrPos(std::string (slsDetector::*somefunc)(int), int pos) { std::string multiSlsDetector::concatResultOrPos(std::string (slsDetector::*somefunc)(int), int pos) {
if (pos >= 0 && pos < (int)detectors.size()) { if (pos >= 0 && pos < (int)detectors.size()) {
return (detectors[pos]->*somefunc)(pos); return (detectors[pos]->*somefunc)(pos);

View File

@ -149,6 +149,15 @@ public:
*/ */
void setupMultiDetector(bool verify = true, bool update = true); void setupMultiDetector(bool verify = true, bool update = true);
template <typename RT, typename... CT>
std::vector<RT> serialCall(RT (slsDetector::*somefunc)(CT...), CT... Args);
template <typename RT, typename... CT>
std::vector<RT> parallelCall(RT (slsDetector::*somefunc)(CT...), CT... Args);
/** /**
* If specific position, then provide result with that detector at position pos * If specific position, then provide result with that detector at position pos
* else concatenate the result of all detectors * else concatenate the result of all detectors

View File

@ -0,0 +1,54 @@
MESSAGE( STATUS "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR} )
MESSAGE( STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR} )
# set(SOURCES
# slsDetectorClient.cpp
# )
include_directories(
include
tests
${PROJECT_SOURCE_DIR}/catch
)
if(USE_TESTS)
set(LOCAL_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests)
set(TEST_SOURCES
# ${BASE_TEST_DIR}/test-MultiDetectorCaller.cpp
${LOCAL_TEST_DIR}/test-container_utils.cpp
${LOCAL_TEST_DIR}/test.cpp
# PARENT_SCOPE
)
add_executable(t2 ${TEST_SOURCES})
set_target_properties(t2 PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
)
endif()
#option(USE_TESTS "Determines whether to build tests." OFF)
# if(USE_TESTS)
# # Prepare "Catch" library for other executables
# set(CATCH_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/catch)
# add_library(Catch INTERFACE)
# target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
# # Make test executable
# add_executable(tests ${BASE_TEST_SOURCES})
# target_link_libraries(tests Catch)
# set_target_properties(tests PROPERTIES
# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
# )
# #enable_testing()
# #add_test(NAME CommandLineClient COMMAND tests)
# endif()
# install(TARGETS sls_client DESTINATION bin)

View File

@ -0,0 +1,40 @@
#ifndef TIMER_H
#define TIMER_H
#include <chrono>
#include <iostream>
#include <string>
class Timer {
using clock = std::chrono::high_resolution_clock;
using time_point = std::chrono::time_point<clock>;
public:
Timer(std::string name = "0")
: t0(clock::now())
, name_(name)
{
}
double elapsed_ms()
{
return std::chrono::duration<double, std::milli>(clock::now() - t0).count();
}
double elapsed_s()
{
return std::chrono::duration<double>(clock::now() - t0).count();
}
void print_elapsed()
{
std::cout << "Timer \"" << name_ << "\": Elapsed time " << elapsed_ms() << " ms\n";
}
void restart()
{
t0 = clock::now();
}
private:
time_point t0;
std::string name_;
};
#endif // TIMER_H

View File

@ -0,0 +1,126 @@
#ifndef CONTAINER_UTILS_H
#define CONTAINER_UTILS_H
#include <algorithm>
#include <numeric>
#include <string>
#include <type_traits>
#include <vector>
#include <sstream>
namespace sls {
template <typename T>
bool allEqual(const std::vector<T>& container)
{
if (container.empty())
return false;
const auto& first = container[0];
return std::all_of(container.cbegin(), container.cend(),
[first](const T& element) { return element == first; });
}
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
allEqualWithTol(const std::vector<T>& container, const T tol)
{
if (container.empty())
return false;
const auto& first = container[0];
return std::all_of(container.cbegin(), container.cend(),
[first, tol](const T& element) {
return (std::abs(element - first) < tol);
});
}
template <typename T>
bool allEqualTo(const std::vector<T>& container, const T value)
{
if (container.empty())
return false;
return std::all_of(container.cbegin(), container.cend(),
[value](const T& element) { return element == value; });
}
template <typename T>
bool allEqualToWithTol(const std::vector<T>& container, const T value,
const T tol)
{
if (container.empty())
return false;
return std::all_of(container.cbegin(), container.cend(),
[value, tol](const T& element) {
return (std::abs(element - value) < tol);
});
}
template <typename T>
bool anyEqualTo(const std::vector<T>& container, const T value)
{
return std::any_of(container.cbegin(), container.cend(),
[value](const T& element) { return element == value; });
}
template <typename T>
bool anyEqualToWithTol(const std::vector<T>& container, const T value,
const T tol)
{
return std::any_of(container.cbegin(), container.cend(),
[value, tol](const T& element) { return (std::abs(element - value) < tol); });
}
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
sum(const std::vector<T>& container)
{
return std::accumulate(container.cbegin(), container.cend(), T{ 0 });
}
template <typename T>
T minusOneIfDifferent(const std::vector<T>& container)
{
if (allEqual(container)) {
return container.front();
} else {
return static_cast<T>(-1);
}
}
//TODO!(Erik)Should try to move away from using this in the slsDetectorPackage
std::string concatenateIfDifferent(std::vector<std::string> container)
{
if (allEqual(container)) {
return container.front();
} else {
std::string result;
for (const auto& s : container)
result += s + "+";
return result;
}
}
std::vector<std::string> split(const std::string& strToSplit, char delimeter)
{
std::stringstream ss(strToSplit);
std::string item;
std::vector<std::string> splittedStrings;
while (std::getline(ss, item, delimeter)) {
splittedStrings.push_back(item);
}
return splittedStrings;
}
std::string concatenateNonEmptyStrings(const std::vector<std::string>& vec){
std::string ret;
for (const auto& s : vec)
if (!s.empty())
ret += s + "+";
return ret;
}
} // namespace sls
#endif // CONTAINER_UTILS_H

View File

@ -0,0 +1,161 @@
#include "catch.hpp"
#include "container_utils.h"
#include <exception>
#include <string>
#include <vector>
using sls::allEqual;
using sls::allEqualTo;
using sls::anyEqualTo;
using sls::allEqualToWithTol;
using sls::allEqualWithTol;
using sls::anyEqualToWithTol;
using sls::sum;
TEST_CASE("Equality of an empty vector") {
std::vector<int> v;
REQUIRE(v.empty());
REQUIRE_FALSE(allEqual(v));
REQUIRE_FALSE(allEqualWithTol(v, 2));
REQUIRE_FALSE(allEqualTo(v, 5));
REQUIRE_FALSE(anyEqualTo(v, 5));
REQUIRE_FALSE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("Equality of a vector with one element") {
std::vector<int> v{5};
REQUIRE(v.size() == 1);
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(allEqualToWithTol(v, 5, 2));
REQUIRE(anyEqualTo(v, 5));
REQUIRE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("A larger vector of the same elements") {
std::vector<int> v(101, 5);
REQUIRE(v.size() == 101);
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(anyEqualTo(v, 5));
SECTION(
"Push back another element to create a vector where not all are equal") {
v.push_back(7);
REQUIRE(v.size() == 102);
REQUIRE_FALSE(allEqual(v));
REQUIRE_FALSE(allEqualWithTol(v, 1));
REQUIRE(allEqualWithTol(v, 3));
REQUIRE_FALSE(allEqualTo(v, 5));
REQUIRE_FALSE(allEqualToWithTol(v, 5, 1));
REQUIRE(allEqualToWithTol(v, 5, 3));
REQUIRE(anyEqualTo(v, 5));
}
}
TEST_CASE("A vector of double with different values") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.1};
REQUIRE(allEqual(v) == false);
REQUIRE(allEqualWithTol(v, 0.3) == false);
REQUIRE(allEqualWithTol(v, 3.2));
}
TEST_CASE("Sum of empty vector") {
std::vector<float> v;
REQUIRE(sls::sum(v) == Approx(0));
}
TEST_CASE("Sum of vector") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.13};
REQUIRE(sls::sum(v) == Approx(12.53));
}
TEST_CASE("Minus one if different") {
std::vector<double> v;
REQUIRE(v.empty());
double d = -1;
REQUIRE(sls::minusOneIfDifferent(v) == d);
SECTION("single element") {
v.push_back(7.3);
REQUIRE(v.size() == 1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(7.3));
}
SECTION("different elements") {
v.push_back(7.3);
v.push_back(1.0);
v.push_back(62.1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(-1.0));
}
}
TEST_CASE("minus one does not have side effects"){
std::vector<int> v{1,1,1};
int i = sls::minusOneIfDifferent(v);
REQUIRE(i==1);
i=5;
REQUIRE(v[0]==1);
}
TEST_CASE("Concat") {
std::vector<std::string> v{"one", "one", "one"};
std::vector<std::string> v2{"one", "one", "one"};
auto r = sls::concatenateIfDifferent(v);
REQUIRE(r == std::string("one"));
r.clear();
// make sure we didn't modify the string
REQUIRE(v == v2);
SECTION("add a different value"){
v.push_back("two");
REQUIRE(v!=v2);
REQUIRE( sls::concatenateIfDifferent(v) == "one+one+one+two+");
}
}
TEST_CASE("split a string with end delimiter"){
std::string s("abra+kadabra+");
auto r =sls::split(s, '+');
REQUIRE(r.size()==2);
REQUIRE(r[0]=="abra");
REQUIRE(r[1]=="kadabra");
}
TEST_CASE("split a string without end delimiter"){
std::string s("abra+kadabra+filibom");
auto r =sls::split(s, '+');
REQUIRE(r.size()==3);
REQUIRE(r[0]=="abra");
REQUIRE(r[1]=="kadabra");
REQUIRE(r[2]=="filibom");
}
TEST_CASE("concatenate non empty strings"){
std::vector<std::string> vec{"hej", "kalas", "", "foto"};
REQUIRE(vec.size()==4);
auto ret = sls::concatenateNonEmptyStrings(vec);
REQUIRE(ret == "hej+kalas+foto+");
}
TEST_CASE("concatenate non empty strings with only emty"){
std::vector<std::string> vec{"", "", ""};
REQUIRE(vec.size()==3);
auto ret = sls::concatenateNonEmptyStrings(vec);
REQUIRE(ret.empty());
}
TEST_CASE("concatenate non empty strings with one element"){
std::vector<std::string> vec{"", "hej", "", "", ""};
REQUIRE(vec.size()==5);
auto ret = sls::concatenateNonEmptyStrings(vec);
REQUIRE(ret=="hej+");
}

View File

@ -0,0 +1,3 @@
// tests-main.cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"