diff --git a/slsDetectorSoftware/include/slsDetector.h b/slsDetectorSoftware/include/slsDetector.h index 3f35bbce7..d4264abfb 100755 --- a/slsDetectorSoftware/include/slsDetector.h +++ b/slsDetectorSoftware/include/slsDetector.h @@ -6,12 +6,14 @@ #include "logger.h" #include "sls_detector_defs.h" #include "network_utils.h" +#include "FixedCapacityContainer.h" class ClientInterface; #include #include #include + class multiSlsDetector; class ServerInterface; class MySocketTCP; @@ -62,11 +64,8 @@ struct sharedSlsDetector { /** path of the trimbits/settings files */ char settingsDir[MAX_STR_LENGTH]; - /** number of energies at which the detector has been trimmed */ - int nTrimEn; - /** list of the energies at which the detector has been trimmed */ - int trimEnergies[MAX_TRIMEN]; + sls::FixedCapacityContainer trimEnergies; /** number of channels per chip */ int nChans; diff --git a/slsDetectorSoftware/src/slsDetector.cpp b/slsDetectorSoftware/src/slsDetector.cpp index 05dd882ae..606d0e772 100755 --- a/slsDetectorSoftware/src/slsDetector.cpp +++ b/slsDetectorSoftware/src/slsDetector.cpp @@ -300,10 +300,6 @@ void slsDetector::initializeDetectorStructure(detectorType type) { shm()->controlPort = DEFAULT_PORTNO; shm()->stopPort = DEFAULT_PORTNO + 1; sls::strcpy_safe(shm()->settingsDir, getenv("HOME")); - shm()->nTrimEn = 0; - for (int &trimEnergie : shm()->trimEnergies) { - trimEnergie = 0; - } shm()->nROI = 0; memset(shm()->roiLimits, 0, MAX_ROIS * sizeof(ROI)); shm()->adcEnableMask = BIT32_MASK; @@ -1166,14 +1162,14 @@ int slsDetector::setThresholdEnergyAndSettings(int e_eV, ((isettings != GET_SETTINGS) ? isettings : shm()->currentSettings); // verify e_eV exists in trimEneregies[] - if ((shm()->nTrimEn == 0) || (e_eV < shm()->trimEnergies[0]) || - (e_eV > shm()->trimEnergies[shm()->nTrimEn - 1])) { + if (shm()->trimEnergies.empty() || (e_eV < shm()->trimEnergies.front()) || + (e_eV > shm()->trimEnergies.back())) { throw RuntimeError("This energy " + std::to_string(e_eV) + " not defined for this module!"); } bool interpolate = - std::all_of(shm()->trimEnergies, shm()->trimEnergies + shm()->nTrimEn, + std::all_of(shm()->trimEnergies.begin(), shm()->trimEnergies.end(), [e_eV](const int &e) { return e != e_eV; }); sls_detector_module myMod{shm()->myDetectorType}; @@ -1185,7 +1181,7 @@ int slsDetector::setThresholdEnergyAndSettings(int e_eV, } else { // find the trim values int trim1 = -1, trim2 = -1; - for (int i = 0; i < shm()->nTrimEn; ++i) { + for (size_t i = 0; i < shm()->trimEnergies.size(); ++i) { if (e_eV < shm()->trimEnergies[i]) { trim2 = shm()->trimEnergies[i]; trim1 = shm()->trimEnergies[i - 1]; @@ -2908,14 +2904,13 @@ int slsDetector::setTrimEn(std::vector energies) { << "\n"; throw RuntimeError(os.str()); } - std::copy(begin(energies), end(energies), shm()->trimEnergies); - shm()->nTrimEn = energies.size(); - return shm()->nTrimEn; + shm()->trimEnergies = energies; + return shm()->trimEnergies.size(); } std::vector slsDetector::getTrimEn() { - return std::vector(shm()->trimEnergies, - shm()->trimEnergies + shm()->nTrimEn); + return std::vector(shm()->trimEnergies.begin(), + shm()->trimEnergies.end()); } int slsDetector::pulsePixel(int n, int x, int y) { diff --git a/slsSupportLib/CMakeLists.txt b/slsSupportLib/CMakeLists.txt index ae44b93c6..6e2c640a6 100755 --- a/slsSupportLib/CMakeLists.txt +++ b/slsSupportLib/CMakeLists.txt @@ -32,6 +32,7 @@ set(PUBLICHEADERS include/ServerSocket.h include/ServerInterface.h include/network_utils.h + include/FixedCapacityContainer.h ) add_library(slsSupportLib SHARED diff --git a/slsSupportLib/include/FixedCapacityContainer.h b/slsSupportLib/include/FixedCapacityContainer.h new file mode 100644 index 000000000..046f5b1f3 --- /dev/null +++ b/slsSupportLib/include/FixedCapacityContainer.h @@ -0,0 +1,172 @@ + +#pragma once +#include +#include +#include +#include + +namespace sls { +template class FixedCapacityContainer { + public: + FixedCapacityContainer() = default; + explicit FixedCapacityContainer(std::initializer_list l); + explicit FixedCapacityContainer(const std::vector &v); + + FixedCapacityContainer &operator=(const std::vector &other); + + bool operator==(const std::vector &other) const; + bool operator!=(const std::vector &other) const; + + template + bool + operator==(const FixedCapacityContainer &other) const; + + template + bool + operator!=(const FixedCapacityContainer &other) const; + + T &operator[](size_t i) { return data_[i]; } + const T &operator[](size_t i) const { return data_[i]; } + + size_t size() const { return size_; } + bool empty() const{ return size_ == 0;} + size_t capacity() const { return Capacity; } + + void push_back(const T &value); + void resize(size_t new_size); + void erase(T *ptr); + T &front() { return data_.front(); } + T &back() { return data_[size_ - 1]; } + const T &front() const { return data_.front(); } + const T &back() const { return data_[size_ - 1]; } + + // iterators + T *begin() { return &data_[0]; } + T *end() { return &data_[size_]; } + const T *cbegin() const { return &data_[0]; } + const T *cend() const { return &data_[size_]; } + + private: + size_t size_{0}; + std::array data_; +} __attribute__((packed)); + +/* Member functions */ +template +FixedCapacityContainer::FixedCapacityContainer( + std::initializer_list l) { + size_ = l.size(); + std::copy(l.begin(), l.end(), data_.begin()); +} + +template +FixedCapacityContainer::FixedCapacityContainer( + const std::vector &v) { + size_ = v.size(); + std::copy(v.begin(), v.end(), data_.begin()); +} + +template +void FixedCapacityContainer::push_back(const T &value) { + if (size_ == Capacity) { + throw std::runtime_error("Container is full"); + } else { + data_[size_] = value; + ++size_; + } +} +template +void FixedCapacityContainer::resize(size_t new_size) { + if (new_size > Capacity) { + throw std::runtime_error("Cannot resize beyond capacity"); + } else { + size_ = new_size; + } +} + +template +FixedCapacityContainer &FixedCapacityContainer:: +operator=(const std::vector &other) { + std::copy(other.begin(), other.end(), data_.begin()); + size_ = other.size(); + return *this; +} + +template +bool FixedCapacityContainer:: +operator==(const std::vector &other) const { + if (size_ != other.size()) { + return false; + } else { + for (size_t i = 0; i != size_; ++i) { + if (data_[i] != other[i]) { + return false; + } + } + } + return true; +} + +template +bool FixedCapacityContainer:: +operator!=(const std::vector &other) const { + return !(*this == other); +} + +template +template +bool FixedCapacityContainer:: +operator==(const FixedCapacityContainer &other) const { + if (size_ != other.size()) { + return false; + } else { + for (size_t i = 0; i != size_; ++i) { + if (data_[i] != other[i]) { + return false; + } + } + } + return true; +} + +template +template +bool FixedCapacityContainer:: +operator!=(const FixedCapacityContainer &other) const { + return !(*this == other); +} + +template +void FixedCapacityContainer::erase(T *ptr) { + if (ptr >= begin() && ptr < end()) { + size_ = static_cast(ptr - begin()); + } else { + throw std::runtime_error("tried to erase with a ptr outside obj"); + } +} + +/* Free function concerning FixedCapacityContainer */ + +template +T *begin(FixedCapacityContainer &container) { + return container.begin(); +} + +template +T *end(FixedCapacityContainer &container) { + return container.end(); +} + +template +bool operator==(const std::vector &vec, + const FixedCapacityContainer &fixed_container) { + return fixed_container == vec; +} + +template +bool operator!=(const std::vector &vec, + const FixedCapacityContainer &fixed_container) { + return fixed_container != vec; +} + +} // namespace sls diff --git a/slsSupportLib/tests/CMakeLists.txt b/slsSupportLib/tests/CMakeLists.txt index be9ef61f3..e1a7e7d77 100755 --- a/slsSupportLib/tests/CMakeLists.txt +++ b/slsSupportLib/tests/CMakeLists.txt @@ -7,4 +7,5 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-Timer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-sls_detector_defs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-Sockets.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-FixedCapacityContainer.cpp ) \ No newline at end of file diff --git a/slsSupportLib/tests/test-FixedCapacityContainer.cpp b/slsSupportLib/tests/test-FixedCapacityContainer.cpp new file mode 100644 index 000000000..78215d336 --- /dev/null +++ b/slsSupportLib/tests/test-FixedCapacityContainer.cpp @@ -0,0 +1,205 @@ +#include "FixedCapacityContainer.h" +#include "catch.hpp" + +using sls::FixedCapacityContainer; + +SCENARIO("FixedCapacityContainers can be sized and resized", "[support]") { + + GIVEN("A default constructed container") { + constexpr size_t n_elem = 5; + FixedCapacityContainer vec; + + REQUIRE(vec.empty()); + REQUIRE(vec.size() == 0); + REQUIRE(vec.capacity() == n_elem); + REQUIRE(sizeof(vec) == sizeof(int) * n_elem + sizeof(size_t)); + + WHEN("an item is pushed back") { + vec.push_back(42); + + THEN("the element is stored and the size increases but the " + "capacity remains fixed") { + REQUIRE(vec[0] == 42); + REQUIRE(vec.size() == 1); + REQUIRE_FALSE(vec.empty()); + REQUIRE(vec.capacity() == 5); + } + } + + WHEN("We try to push back more elements than the capcity") { + for (size_t i = 0; i != vec.capacity(); ++i) + vec.push_back(static_cast(i)); + THEN("It throws") { REQUIRE_THROWS(vec.push_back(92)); } + } + + WHEN("a vector is assigned to the fixed container") { + std::vector standard_vector{1, 2, 8, 0}; + vec = standard_vector; + THEN("their values and size match") { + REQUIRE(vec.size() == standard_vector.size()); + for (size_t i = 0; i != vec.size(); ++i) { + REQUIRE(vec[i] == standard_vector[i]); + } + } + } + } + + GIVEN("A FixedCapacityContainer constructed form a std::initializer list") { + FixedCapacityContainer vec{23, 52, 11}; + REQUIRE(vec.size() == 3); + REQUIRE(vec.capacity() == 10); + REQUIRE(vec[0] == 23); + REQUIRE(vec[1] == 52); + REQUIRE(vec[2] == 11); + + WHEN("The container is resized to a smaller size") { + vec.resize(2); + THEN("The size changes but not the values or capacity") { + REQUIRE(vec.size() == 2); + REQUIRE(vec[0] == 23); + REQUIRE(vec[1] == 52); + } + } + + WHEN("The container is resized to a larger size") { + vec.resize(7); + THEN("The size changes but not the values") { + REQUIRE(vec.size() == 7); + REQUIRE(vec[0] == 23); + REQUIRE(vec[1] == 52); + REQUIRE(vec[2] == 11); + } + } + + WHEN("We try to resize beyond the capacity") { + THEN("it throws") { CHECK_THROWS(vec.resize(25)); } + } + WHEN("We call front and back"){ + THEN("They return referenced to the first and last element"){ + REQUIRE(vec.front() == 23); + REQUIRE(&vec.front() == &vec[0]); + REQUIRE(vec.back() == 11); + REQUIRE(&vec.back() == &vec[2]); + + } + } + } + + GIVEN("An std::vector of size 3") { + std::vector standard_vector{5, 2, 1}; + WHEN("we construct a fixed capacity container from it") { + FixedCapacityContainer vec(standard_vector); + THEN("size and data matches") { + REQUIRE(vec.size() == 3); + REQUIRE(vec[0] == 5); + REQUIRE(vec[1] == 2); + REQUIRE(vec[2] == 1); + } + THEN("we can compare the vector and fixed container") { + REQUIRE(vec == standard_vector); + } + } + } +} + +SCENARIO("Comparison of FixedCapacityContainers", "[support]") { + GIVEN("Two containers containers that are equal at the start") { + FixedCapacityContainer a{0, 1, 2}; + FixedCapacityContainer b{0, 1, 2}; + REQUIRE(a == b); + REQUIRE_FALSE(a != b); + + WHEN("We push back one element") { + a.push_back(4); + THEN("they are not equal anymore") { REQUIRE(a != b); } + } + WHEN("Compared to a FixedCapacityContainer with different capacity") { + FixedCapacityContainer c{0, 1, 2}; + THEN("The comparison still holds") { + REQUIRE(a == c); + REQUIRE_FALSE(a != c); + } + } + WHEN("we make a copy of one container") { + auto c = a; + THEN("The comparison holds") { + REQUIRE(c == a); + REQUIRE(&c != &a); + REQUIRE(&a[0] != &c[0]); + } + } + WHEN("Compared to an std::vector") { + std::vector standard_vector{0, 1, 2}; + THEN("The comparison also holds for both orderings") { + REQUIRE(a == standard_vector); + REQUIRE(standard_vector == a); + REQUIRE_FALSE(a != standard_vector); + REQUIRE_FALSE(standard_vector != a); + + standard_vector.push_back(3); + REQUIRE(a != standard_vector); + } + } + } +} + +SCENARIO("Sorting, removing and other manipulation of a container", "[support]") { + GIVEN("An unsorted container") { + FixedCapacityContainer a{14, 12, 90, 12}; + WHEN("We sort it") { + std::sort(a.begin(), a.end()); + THEN("Elements appear sorted") { + REQUIRE(a[0] == 12); + REQUIRE(a[1] == 12); + REQUIRE(a[2] == 14); + REQUIRE(a[3] == 90); + } + } + WHEN("Sorting is done using free function for begin and end") { + std::sort(begin(a), end(a)); + THEN("it also works") { + REQUIRE(a[0] == 12); + REQUIRE(a[1] == 12); + REQUIRE(a[2] == 14); + REQUIRE(a[3] == 90); + } + } + WHEN("Erasing elements of a certain value") { + a.erase(std::remove(begin(a), end(a), 12)); + THEN("all elements of that value are removed") { + REQUIRE(a.size() == 2); + REQUIRE(a[0] == 14); + REQUIRE(a[1] == 90); + } + } + } +} + +SCENARIO("Assigning containers to each other", "[support]") { + GIVEN("Two containers") { + FixedCapacityContainer a{1, 2, 3}; + FixedCapacityContainer b{4, 5, 6}; + WHEN("a is assigned to b") { + a = b; + THEN("A deep copy is made and both containers are equal") { + REQUIRE(a == b); + REQUIRE(&a != &b); + REQUIRE(&a[0] != &b[0]); + REQUIRE(a[0] == 4); + REQUIRE(a[1] == 5); + REQUIRE(a[2] == 6); + } + } + WHEN("A new object is create from an old one") { + FixedCapacityContainer c(a); + THEN("A deep copy is also made") { + REQUIRE(c == a); + REQUIRE(&c != &a); + REQUIRE(&c[0] != &a[0]); + REQUIRE(c[0] == 1); + REQUIRE(c[1] == 2); + REQUIRE(c[2] == 3); + } + } + } +} \ No newline at end of file