diff --git a/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.cpp b/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.cpp index 7474655a7..942c3cf5d 100644 --- a/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.cpp +++ b/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.cpp @@ -87,6 +87,33 @@ void multiSlsDetector::setupMultiDetector(bool verify, bool update) { updateUserdetails(); } + + +template +std::vector multiSlsDetector::serialCall(RT (slsDetector::*somefunc)(CT...), CT... Args) +{ + std::vector result; + for (size_t det_id = 0; det_id < thisMultiDetector->numberOfDetectors; ++det_id) { + result.push_back(((*this)[det_id]->*somefunc)(Args...)); + } + return result; +} + +template +std::vector multiSlsDetector::parallelCall(RT (slsDetector::*somefunc)(CT...), CT... Args) +{ + std::vector> 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 result; + for (auto& i : futures) + result.push_back(i.get()); + + return result; +} + + std::string multiSlsDetector::concatResultOrPos(std::string (slsDetector::*somefunc)(int), int pos) { if (pos >= 0 && pos < (int)detectors.size()) { return (detectors[pos]->*somefunc)(pos); diff --git a/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.h b/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.h index e9e085551..dae5e91b1 100644 --- a/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.h +++ b/slsDetectorSoftware/multiSlsDetector/multiSlsDetector.h @@ -149,6 +149,15 @@ public: */ void setupMultiDetector(bool verify = true, bool update = true); + + + + template + std::vector serialCall(RT (slsDetector::*somefunc)(CT...), CT... Args); + + template + std::vector parallelCall(RT (slsDetector::*somefunc)(CT...), CT... Args); + /** * If specific position, then provide result with that detector at position pos * else concatenate the result of all detectors diff --git a/slsSupportLib/CMakeLists.txt b/slsSupportLib/CMakeLists.txt new file mode 100644 index 000000000..a6ae2077f --- /dev/null +++ b/slsSupportLib/CMakeLists.txt @@ -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) + diff --git a/slsSupportLib/include/Timer.h b/slsSupportLib/include/Timer.h new file mode 100644 index 000000000..a16761081 --- /dev/null +++ b/slsSupportLib/include/Timer.h @@ -0,0 +1,40 @@ +#ifndef TIMER_H +#define TIMER_H +#include +#include +#include + +class Timer { + using clock = std::chrono::high_resolution_clock; + using time_point = std::chrono::time_point; + +public: + Timer(std::string name = "0") + : t0(clock::now()) + , name_(name) + { + } + + double elapsed_ms() + { + return std::chrono::duration(clock::now() - t0).count(); + } + double elapsed_s() + { + return std::chrono::duration(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 diff --git a/slsSupportLib/include/container_utils.h b/slsSupportLib/include/container_utils.h new file mode 100644 index 000000000..2bc4edcd0 --- /dev/null +++ b/slsSupportLib/include/container_utils.h @@ -0,0 +1,126 @@ +#ifndef CONTAINER_UTILS_H +#define CONTAINER_UTILS_H + +#include +#include +#include +#include +#include +#include + +namespace sls { + +template +bool allEqual(const std::vector& 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 std::enable_if::value, bool>::type +allEqualWithTol(const std::vector& 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 +bool allEqualTo(const std::vector& 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 +bool allEqualToWithTol(const std::vector& 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 +bool anyEqualTo(const std::vector& container, const T value) +{ + return std::any_of(container.cbegin(), container.cend(), + [value](const T& element) { return element == value; }); +} + +template +bool anyEqualToWithTol(const std::vector& 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 std::enable_if::value, T>::type +sum(const std::vector& container) +{ + return std::accumulate(container.cbegin(), container.cend(), T{ 0 }); +} + +template +T minusOneIfDifferent(const std::vector& container) +{ + if (allEqual(container)) { + return container.front(); + } else { + return static_cast(-1); + } +} + +//TODO!(Erik)Should try to move away from using this in the slsDetectorPackage +std::string concatenateIfDifferent(std::vector container) +{ + if (allEqual(container)) { + return container.front(); + } else { + std::string result; + for (const auto& s : container) + result += s + "+"; + return result; + } +} + +std::vector split(const std::string& strToSplit, char delimeter) +{ + std::stringstream ss(strToSplit); + std::string item; + std::vector splittedStrings; + while (std::getline(ss, item, delimeter)) { + splittedStrings.push_back(item); + } + return splittedStrings; +} + +std::string concatenateNonEmptyStrings(const std::vector& vec){ + std::string ret; + for (const auto& s : vec) + if (!s.empty()) + ret += s + "+"; + return ret; +} + +} // namespace sls + +#endif // CONTAINER_UTILS_H diff --git a/slsSupportLib/tests/test-container_utils.cpp b/slsSupportLib/tests/test-container_utils.cpp new file mode 100644 index 000000000..10c8c8b9a --- /dev/null +++ b/slsSupportLib/tests/test-container_utils.cpp @@ -0,0 +1,161 @@ +#include "catch.hpp" +#include "container_utils.h" +#include +#include +#include + +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 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 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 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 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 v; + REQUIRE(sls::sum(v) == Approx(0)); +} + +TEST_CASE("Sum of vector") { + std::vector v{1.2, 2., 4.2, 4, 1.13}; + REQUIRE(sls::sum(v) == Approx(12.53)); +} + +TEST_CASE("Minus one if different") { + std::vector 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 v{1,1,1}; + int i = sls::minusOneIfDifferent(v); + REQUIRE(i==1); + i=5; + REQUIRE(v[0]==1); +} + +TEST_CASE("Concat") { + std::vector v{"one", "one", "one"}; + std::vector 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 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 vec{"", "", ""}; + REQUIRE(vec.size()==3); + auto ret = sls::concatenateNonEmptyStrings(vec); + REQUIRE(ret.empty()); +} + +TEST_CASE("concatenate non empty strings with one element"){ + std::vector vec{"", "hej", "", "", ""}; + REQUIRE(vec.size()==5); + auto ret = sls::concatenateNonEmptyStrings(vec); + REQUIRE(ret=="hej+"); +} \ No newline at end of file diff --git a/slsSupportLib/tests/test.cpp b/slsSupportLib/tests/test.cpp new file mode 100644 index 000000000..8daed99c4 --- /dev/null +++ b/slsSupportLib/tests/test.cpp @@ -0,0 +1,3 @@ +// tests-main.cpp +#define CATCH_CONFIG_MAIN +#include "catch.hpp" \ No newline at end of file