diff --git a/include/bbp/sonata/reports.h b/include/bbp/sonata/reports.h index 7d0a9f8..e1fd049 100644 --- a/include/bbp/sonata/reports.h +++ b/include/bbp/sonata/reports.h @@ -192,4 +192,21 @@ char* sonata_restore(uint64_t node_id, const int* piece_count, const int* length #if defined(__cplusplus) } + +#include + +/** + * \brief Add an element value to an existing node on a report + * + * C++-only analogue of sonata_add_element that takes a generic handle to element_value instead of a + * raw pointer. + * + * \return 0 if operator succeeded, -2 if the report doesn't exist, -3 if the specified node + * doesn't exist, -1 for other errors. + */ +int sonata_add_element_handle(const char* report_name, + const char* population_name, + uint64_t node_id, + uint32_t element_id, + std::function element_value); #endif diff --git a/src/data/node.cpp b/src/data/node.cpp index 69cc7ed..38851b7 100644 --- a/src/data/node.cpp +++ b/src/data/node.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "node.h" @@ -9,14 +11,37 @@ Node::Node(uint64_t node_id) : node_id_(node_id) {} void Node::add_element(double* element_value, uint32_t element_id) { + if (!element_handles_.empty()) { + throw std::runtime_error( + "bbp::sonata::Node::add_element: mixing raw pointers and generic handles is not " + "supported"); + } elements_.push_back(element_value); element_ids_.push_back(element_id); } +void Node::add_element(std::function element_value, uint32_t element_id) { + if (!elements_.empty()) { + throw std::runtime_error( + "bbp::sonata::Node::add_element: mixing raw pointers and generic handles is not " + "supported"); + } + element_handles_.push_back(std::move(element_value)); + element_ids_.push_back(element_id); +} + void Node::fill_data(std::vector::iterator it) { - std::transform(elements_.begin(), elements_.end(), it, [](auto elem) { - return static_cast(*elem); - }); + assert(elements_.empty() || element_handles_.empty()); + if (!elements_.empty()) { + std::transform(elements_.begin(), elements_.end(), it, [](auto elem) -> float { + return *elem; + }); + } else if (!element_handles_.empty()) { + std::transform(element_handles_.begin(), + element_handles_.end(), + it, + [](auto const& elem) -> float { return elem(); }); + } } void Node::refresh_pointers(std::function refresh_function) { diff --git a/src/data/node.h b/src/data/node.h index 9d1d317..a715e9a 100644 --- a/src/data/node.h +++ b/src/data/node.h @@ -16,12 +16,13 @@ class Node void fill_data(std::vector::iterator it); void refresh_pointers(std::function refresh_function); virtual void add_element(double* element_value, uint32_t element_id); + virtual void add_element(std::function element_value, uint32_t element_id); uint64_t get_node_id() const noexcept { return node_id_; } virtual size_t get_num_elements() const noexcept { - return elements_.size(); + return element_ids_.size(); } const std::vector& get_element_ids() const noexcept { return element_ids_; @@ -33,6 +34,7 @@ class Node protected: std::vector element_ids_; std::vector elements_; + std::vector> element_handles_; }; using nodes_t = std::map>; diff --git a/src/data/soma_node.cpp b/src/data/soma_node.cpp index 5c57bcb..8f40db6 100644 --- a/src/data/soma_node.cpp +++ b/src/data/soma_node.cpp @@ -9,12 +9,20 @@ SomaNode::SomaNode(uint64_t node_id) : Node(node_id) {} void SomaNode::add_element(double* element_value, uint32_t element_id) { - if (!elements_.empty()) { + if (!elements_.empty() || !element_handles_.empty()) { throw std::runtime_error("ERROR: Soma report nodes can only have 1 element"); } elements_.push_back(element_value); element_ids_.push_back(element_id); } +void SomaNode::add_element(std::function element_value, uint32_t element_id) { + if (!elements_.empty() || !element_handles_.empty()) { + throw std::runtime_error("ERROR: Soma report nodes can only have 1 element"); + } + element_handles_.push_back(std::move(element_value)); + element_ids_.push_back(element_id); +} + } // namespace sonata } // namespace bbp diff --git a/src/data/soma_node.h b/src/data/soma_node.h index 706eaad..d13aeae 100644 --- a/src/data/soma_node.h +++ b/src/data/soma_node.h @@ -10,6 +10,7 @@ class SomaNode: public Node SomaNode(uint64_t node_id); void add_element(double* element_value, uint32_t element_id) override; + void add_element(std::function element_value, uint32_t element_id) override; size_t get_num_elements() const noexcept override { return elements_.empty() ? 0 : 1; }; diff --git a/src/library/reports.cpp b/src/library/reports.cpp index 189bc97..5ff4f2f 100644 --- a/src/library/reports.cpp +++ b/src/library/reports.cpp @@ -44,18 +44,20 @@ int sonata_add_node(const char* report_name, return 0; } -int sonata_add_element(const char* report_name, - const char* population_name, - uint64_t node_id, - uint32_t element_id, - double* voltage) { +namespace { +template +int sonata_add_element_impl(const char* report_name, + const char* population_name, + uint64_t node_id, + uint32_t element_id, + T&& voltage) { if (!sonata_report.report_exists(report_name)) { return -2; } try { auto report = sonata_report.get_report(report_name); auto node = report->get_node(population_name, node_id); - node->add_element(voltage, element_id); + node->add_element(std::forward(voltage), element_id); } catch (const std::out_of_range& err) { logger->error(err.what()); return -3; @@ -65,6 +67,24 @@ int sonata_add_element(const char* report_name, } return 0; } +} // namespace + +int sonata_add_element(const char* report_name, + const char* population_name, + uint64_t node_id, + uint32_t element_id, + double* voltage) { + return sonata_add_element_impl(report_name, population_name, node_id, element_id, voltage); +} + +int sonata_add_element_handle(const char* report_name, + const char* population_name, + uint64_t node_id, + uint32_t element_id, + std::function element_value) { + return sonata_add_element_impl( + report_name, population_name, node_id, element_id, std::move(element_value)); +} void sonata_setup_communicators() { sonata_report.create_communicators();